# rust-dome-android **Repository Path**: pankrati/rust-dome-android ## Basic Information - **Project Name**: rust-dome-android - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-29 - **Last Updated**: 2025-07-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 打包成 Android 库命令 ` $env:ANDROID_NDK_HOME = "C:\ndk\29.0.13599879" cargo ndk -t arm64-v8a -o ./android/app/jniLibs build --release `shell # 深入解析 Rust 方法调用与生命周期管理 在 Android 应用中调用 Rust 方法涉及多个层面的交互,包括 Kotlin/Java 与 Rust 的互操作、JNI 接口以及内存管理。下面我将详细解释整个过程: ## 调用 Rust 方法的完整流程 ### 1. Kotlin 声明外部函数 (Kotlin 端) ```kotlin // 声明外部函数 external fun helloFromRust(name: String): String external fun addNumbers(a: Int, b: Int): Int // 加载 Rust 库 companion object { init { System.loadLibrary("rust_android_demo") } } ``` ### 2. Rust 实现 JNI 函数 (Rust 端) ```rust #[no_mangle] // 防止名称修饰 pub extern "system" fn Java_com_example_rustandroid_MainActivity_helloFromRust( env: JNIEnv, // JNI 环境对象 _class: JClass, // Java 类对象 name: JString, // Java 字符串参数 ) -> jstring { // 返回 Java 字符串 // 将 Java 字符串转换为 Rust 字符串 let input: String = env.get_string(&name) .expect("invalid string") .into(); // 创建新的字符串 let output = format!("你好,{},来自 Rust!", input); // 将 Rust 字符串转换为 Java 字符串并返回 env.new_string(output) .unwrap() .into_raw() // 转换为原始指针 } #[no_mangle] pub extern "system" fn Java_com_example_rustandroid_MainActivity_addNumbers( _env: JNIEnv, // JNI 环境对象 _class: JClass, // Java 类对象 a: jint, // Java int 参数 b: jint, // Java int 参数 ) -> jint { // 返回 Java int a + b // 直接进行加法操作 } ``` ### 3. Kotlin 调用 Rust 函数 ```kotlin // 在 Composable 函数中调用 @Composable fun Greeting(name: String, helloFunc: ((String) -> String)? = null) { val message = helloFunc?.invoke(name) ?: "native lib not loaded" Text(text = message) } // 在 Activity 中传递函数引用 setContent { Greeting( name = "pankrati111", helloFunc = ::helloFromRust // 函数引用 ) } ``` ## 生命周期管理详解 ### 1. Java 对象在 Rust 中的生命周期 当 Java 对象传递给 Rust 时: - **JString**、**JClass** 等是局部引用 (Local References) - 局部引用在 JNI 函数执行期间有效 - 函数返回后,局部引用会自动释放 - **不需要**手动释放这些引用 ### 2. Rust 创建的 Java 对象 当 Rust 创建新对象返回给 Java: ```rust env.new_string(output) // 创建新的 Java 字符串 .unwrap() // 处理可能的错误 .into_raw() // 转换为原始指针返回 ``` - `new_string` 创建一个新的 Java 字符串对象 - 返回的是局部引用 - `into_raw()` 将 JNI 对象转换为原始指针 - 这个指针会被 Kotlin/Java 接收并转换为 Java 对象 - JVM 负责管理返回对象的内存 ### 3. 内存管理注意事项 1. **不要缓存 JNIEnv**: JNIEnv 指针仅在当前线程有效,不应缓存或跨线程使用 2. **局部引用限制**: 单个 JNI 函数最多可创建 16 个局部引用 如果创建大量对象,应使用 `DeleteLocalRef` 手动释放 3. **全局引用**: 如果需要长期持有 Java 对象,应创建全局引用: ```rust let global_ref = env.new_global_ref(local_ref).unwrap(); ``` 使用后必须手动释放: ```rust env.delete_global_ref(global_ref).unwrap(); ``` 4. **字符串处理**: - `GetStringChars`/`ReleaseStringChars` 用于直接访问字符串内容 - 在 Rust 中通常使用 `get_string` 更安全方便 ### 4. 基本类型处理 对于 `addNumbers` 函数: ```rust pub extern "system" fn Java_..._addNumbers( _env: JNIEnv, _class: JClass, a: jint, // 等同于 i32 b: jint, // 等同于 i32 ) -> jint { // 等同于 i32 a + b } ``` - 基本类型 (int, float, boolean 等) 按值传递 - 没有生命周期问题 - 直接使用 Rust 原生类型操作 ## 类型映射表 | Java/Kotlin 类型 | JNI 类型 | Rust 类型 (jni crate) | |----------------|----------|----------------------| | boolean | jboolean | jboolean | | byte | jbyte | jbyte | | char | jchar | jchar | | short | jshort | jshort | | int | jint | jint | | long | jlong | jlong | | float | jfloat | jfloat | | double | jdouble | jdouble | | String | jstring | JString | | Object | jobject | JObject | | Class | jclass | JClass | ## 最佳实践 1. **错误处理**: ```rust let input = match env.get_string(&name) { Ok(s) => s.into(), Err(_) => { // 抛出 Java 异常 env.throw_new("java/lang/IllegalArgumentException", "Invalid string") .expect("Failed to throw exception"); return JObject::null().into_raw(); } }; ``` 2. **资源清理**: ```rust // 获取直接指针(谨慎使用) let chars = env.get_string_chars(&name).unwrap(); // 使用字符串内容... // 必须释放! env.release_string_chars(&name, chars).unwrap(); ``` 3. **线程安全**: - JNIEnv 仅在创建它的线程有效 - 跨线程调用需使用 `JavaVM` 附加线程: ```rust let jvm = JavaVM::from_raw(vm_ptr).unwrap(); let env = jvm.attach_current_thread().unwrap(); ``` ## 完整调用流程图示 ``` Kotlin App │ │ 调用 helloFromRust("pankrati111") ▼ JNI 接口层 │ 转换参数为 JNI 类型 ▼ Rust 实现 │ env.get_string() // Kotlin String → Rust String │ format!("...") // 创建新字符串 │ env.new_string() // Rust String → Java String │ .into_raw() // 返回给 JNI ▲ JNI 接口层 │ 转换返回值为 Java 类型 ▼ Kotlin App │ 接收并显示结果 ``` ## 为什么您的实现安全 在您的代码中: 1. 没有长期持有 Java 对象引用 2. 只处理基本类型和字符串 3. 使用 `get_string`/`new_string` 安全转换 4. Rust 端没有分配需要手动释放的内存 因此,当前实现没有内存泄漏或生命周期问题,是安全的 JNI 交互方式。 对于更复杂的场景(如传递对象数组、回调Java方法等),需要更谨慎的生命周期管理,但您当前的需求不需要这些高级功能。