概述
本文档详细介绍如何在鸿蒙OS应用中集成Rust代码,通过将Rust编译为SO库,实现鸿蒙应用(ArkTS/Java)与Rust的交互。这种整合方式可以充分利用Rust的性能优势和内存安全性,同时发挥鸿蒙OS的生态优势。
环境准备
开发环境要求
- 操作系统:Windows 10/11 64位或macOS 10.15及以上
- 鸿蒙开发工具:DevEco Studio 4.0及以上
- JDK:11.0及以上
- Rust环境:
- Rustup (Rust版本管理工具)
- Rust 1.60及以上版本
- 鸿蒙SDK:API Version 9及以上
环境安装步骤
安装DevEco Studio
从华为开发者联盟下载并安装最新版本,安装过程中勾选鸿蒙SDK。安装Rust环境
# Windows (使用PowerShell) Invoke-WebRequest https://sh.rustup.rs -UseBasicParsing | Invoke-Expression # macOS/Linux curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安装鸿蒙交叉编译目标
# 对于32位ARM架构 rustup target add armv7-linux-androideabi # 对于64位ARM架构 rustup target add aarch64-linux-android
安装NDK
在DevEco Studio中,通过Settings > Appearance & Behavior > System Settings > Android SDK
安装NDK(建议版本25及以上)
开发流程
步骤1:创建Rust库项目
创建一个新的Rust库项目:
cargo new --lib rust_harmony_demo cd rust_harmony_demo
修改
Cargo.toml
文件,添加必要配置:[package] name = "rust_harmony_demo" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] # 编译为C风格的动态链接库 [dependencies] jni = "0.21.1" # 用于JNI交互 libc = "0.2" # C标准库绑定
编写Rust代码(
src/lib.rs
):use jni::JNIEnv; use jni::objects::{JClass, JString}; use jni::sys::jstring; use libc::{c_char, c_int}; use std::ffi::{CString, CStr}; // 简单的加法函数,演示基本类型交互 #[no_mangle] pub extern "C" fn add(a: c_int, b: c_int) -> c_int { a + b } // 字符串处理函数,演示字符串交互 #[no_mangle] pub extern "C" fn process_string(input: *const c_char) -> *mut c_char { if input.is_null() { return std::ptr::null_mut(); } let c_str = unsafe { CStr::from_ptr(input) }; let rust_str = match c_str.to_str() { Ok(s) => s, Err(_) => return std::ptr::null_mut(), }; // 处理字符串:转为大写并添加前缀 let result = format!("Rust processed: {}", rust_str.to_uppercase()); // 转换为C字符串并返回 CString::new(result).unwrap().into_raw() } // JNI函数,直接与Java/ArkTS交互 #[no_mangle] pub extern "C" fn Java_com_example_rustdemo_RustInterface_nativeGreet( env: JNIEnv, _class: JClass, name: JString ) -> jstring { // 将Java字符串转换为Rust字符串 let name: String = env.get_string(name).expect("Failed to get string").into(); // 处理 let greeting = format!("Hello from Rust, {}!", name); // 将Rust字符串转换回Java字符串 env.new_string(greeting).expect("Failed to create string") } // 提供一个释放字符串内存的函数 #[no_mangle] pub extern "C" fn free_string(s: *mut c_char) { if !s.is_null() { unsafe { CString::from_raw(s); } } }
步骤2:编译Rust为鸿蒙兼容的SO库
创建交叉编译配置文件(
rust-toolchain.toml
):[toolchain] channel = "stable" targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
创建编译脚本(
build_harmony.sh
或build_harmony.bat
):Linux/macOS:
#!/bin/bash # 设置NDK路径(请替换为实际路径) NDK_PATH=~/Android/Sdk/ndk/25.1.8937393 # 编译64位版本 export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang cargo build --target aarch64-linux-android --release # 编译32位版本 export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi29-clang cargo build --target armv7-linux-androideabi --release
Windows:
@echo off :: 设置NDK路径(请替换为实际路径) set NDK_PATH=C:\Users\<用户名>\AppData\Local\Android\Sdk\ndk\25.1.8937393 :: 编译64位版本 set CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=%NDK_PATH%\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android29-clang.exe cargo build --target aarch64-linux-android --release :: 编译32位版本 set CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=%NDK_PATH%\toolchains\llvm\prebuilt\windows-x86_64\bin\armv7a-linux-androideabi29-clang.exe cargo build --target armv7-linux-androideabi --release
执行编译脚本:
# Linux/macOS chmod +x build_harmony.sh ./build_harmony.sh # Windows build_harmony.bat
编译成功后,SO库将生成在以下目录:
- 64位:
target/aarch64-linux-android/release/librust_harmony_demo.so
- 32位:
target/armv7-linux-androideabi/release/librust_harmony_demo.so
- 64位:
步骤3:创建鸿蒙应用项目
在DevEco Studio中创建一个新的鸿蒙应用项目:
- 选择"Application"
- 选择"Empty Ability"
- 设置项目名称(如"RustHarmonyDemo")
- 选择合适的保存路径
- 设置API版本(9及以上)
项目结构准备:
在entry/src/main
目录下创建jniLibs
文件夹,并按架构创建子文件夹:entry/src/main/jniLibs/ ├── arm64-v8a/ # 64位ARM └── armeabi-v7a/ # 32位ARM
复制SO库到对应目录:
# 64位库 cp target/aarch64-linux-android/release/librust_harmony_demo.so \ entry/src/main/jniLibs/arm64-v8a/ # 32位库 cp target/armv7-linux-androideabi/release/librust_harmony_demo.so \ entry/src/main/jniLibs/armeabi-v7a/
步骤4:在鸿蒙应用中调用Rust代码
方式1:通过ArkTS的NAPI调用(推荐)
创建ArkTS扩展模块:
在entry/src/main/ets
目录下创建rust
文件夹,添加rustInterface.ets
:// 声明外部SO库中的函数 @External('librust_harmony_demo.so') declare function add(a: number, b: number): number; @External('librust_harmony_demo.so') declare function process_string(input: string): string; @External('librust_harmony_demo.so') declare function free_string(s: string): void; // 封装Rust接口 export class RustInterface { // 调用Rust加法函数 static addNumbers(a: number, b: number): number { return add(a, b); } // 调用Rust字符串处理函数 static processText(input: string): string { const result = process_string(input); // 注意:在实际应用中需要管理内存,使用后释放 // free_string(result); // 根据具体使用场景决定何时释放 return result; } }
在页面中使用:
修改entry/src/main/ets/pages/Index.ets
:import { RustInterface } from '../rust/rustInterface'; @Entry @Component struct Index { @State result: string = "Click the buttons to test Rust integration" build() { Row() { Column() { Text('Rust & HarmonyOS Demo') .fontSize(20) .margin(10) Button('Test Addition') .onClick(() => { const sum = RustInterface.addNumbers(23, 42); this.result = `23 + 42 = ${sum}`; }) .margin(5) Button('Test String Processing') .onClick(() => { const processed = RustInterface.processText("hello harmonyos"); this.result = processed; }) .margin(5) Text(this.result) .fontSize(16) .margin(10) .textAlign(TextAlign.Center) } .width('100%') } .height('100%') } }
方式2:通过Java JNI调用
创建Java接口类:
在entry/src/main/java/com/example/rustdemo
目录下创建RustInterface.java
:package com.example.rustdemo; public class RustInterface { // 加载SO库 static { System.loadLibrary("rust_harmony_demo"); } // 声明native方法 public static native int add(int a, int b); public static native String processString(String input); public static native String nativeGreet(String name); public static native void freeString(String s); }
在ArkTS中调用Java接口:
import { RustInterface } from 'java:com.example.rustdemo.RustInterface'; // 使用示例 let sum = RustInterface.add(10, 20); let greeting = RustInterface.nativeGreet("HarmonyOS");
步骤5:配置应用并运行
配置
build.gradle
:
在entry/build.gradle
中添加NDK配置:android { // ...其他配置 defaultConfig { // ...其他配置 ndk { abiFilters 'arm64-v8a', 'armeabi-v7a' } } }
连接鸿蒙设备或启动模拟器
点击DevEco Studio中的运行按钮(▶️),将应用部署到设备上
常见问题及解决方案
1. 编译错误:链接器找不到
问题:编译Rust时出现类似"linker aarch64-linux-android29-clang
not found"的错误
解决方案:
- 确认NDK路径是否正确设置
- 确认NDK版本是否兼容(建议25及以上)
- 检查目标架构与NDK工具链是否匹配
2. 运行时错误:找不到SO库
问题:应用运行时出现"java.lang.UnsatisfiedLinkError: dlopen failed: library “librust_harmony_demo.so” not found"
解决方案:
- 确认SO库已正确放置在
jniLibs
对应架构目录下 - 检查
build.gradle
中是否正确配置了abiFilters
- 确认设备架构与提供的SO库架构匹配
3. 内存泄漏
问题:使用字符串交互时可能出现内存泄漏
解决方案:
- 确保从Rust返回的字符串在使用后通过
free_string
释放 - 考虑使用RAII模式封装字符串操作,自动管理内存
4. 类型转换错误
问题:Rust与ArkTS/Java之间的类型转换错误
解决方案:
- 仔细处理不同类型系统之间的映射关系
- 对于复杂类型,考虑使用JSON等序列化格式进行交互
- 增加错误处理代码,避免因类型不匹配导致崩溃
最佳实践
接口设计:
- 保持Rust接口简洁,尽量使用基本数据类型
- 对于复杂数据结构,考虑使用Protocol Buffers或JSON序列化
内存管理:
- 明确内存所有权,避免悬垂指针
- 为所有分配的内存提供释放函数
- 优先使用安全的类型转换函数
错误处理:
- 在Rust中捕获所有可能的错误,并转换为适合鸿蒙应用的错误码
- 在鸿蒙应用中检查所有Rust调用的返回值
性能优化:
- 将频繁调用的操作批处理,减少跨语言调用开销
- 对于计算密集型任务,尽量在Rust中完成,减少数据传输
测试策略:
- 为Rust代码编写单元测试
- 为接口编写集成测试,验证端到端功能
总结
通过本文档介绍的方法,我们可以在鸿蒙OS应用中成功集成Rust代码,充分利用两种技术的优势。这种整合方式不仅可以提升应用的性能和安全性,还能复用已有的Rust生态系统资源。
随着鸿蒙OS的不断发展,相信Rust与鸿蒙的整合会更加顺畅,为开发者提供更多可能性。建议持续关注鸿蒙官方文档和Rust交叉编译工具链的更新,以获取更好的开发体验。