1. 整体方案
Rust的移动端跨平台开发方案,具体如下
最底层SDK的业务逻辑由Rust实现
使用ffi工具,编写binding code
Android、iOS:中间层使用uniffi编写binding代码。使用uniffi-bindgen将binding代码生成kotlin、Swift代码,方便Android、iOS调用。
鸿蒙:使用ohos-rs编写binding代码,使用ohos工具生成har包方便鸿蒙调用
构建工具
Android: 最终使用ndk build的工具编译Android 平台的so
iOS:未找到比较好用的工具,自行编写脚本构建xcframework
鸿蒙:最终使用ohrs build 构建鸿蒙平台的so
2. 代码详解 整个工程目录结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ├── doc │ └── image ├── harmony │ ├── dist │ │ ├── strip │ │ └── symbol │ └── src └── uniffi ├── dist │ ├── android │ └── ios ├── mobile_ffi │ └── src └── uniffi-bindgen └── src
2.1 编译环境
Android 安装cargo-ndk cargo install cargo-ndk
iOS 需要安装 Xcode
鸿蒙 需要安装 ohrs cargo install ohrs
该仓库可以作为一个Rust移动端跨平台开发的模版,通过init.py脚本可以快速初始化一个工程。
2.2 uniffi
该目录是workspace,包含mobile-ffi、uniffi-bindgen、dist, build_android_sh, build_ios_xc.sh
编写 rust 代码
该目录是源码依赖uniffi工具
build_android_sh
build_ios_xc.sh
dist
该目录下包括Android、iOS的构建产物
Android: 包含生成的kotlin代码、带符号、无符号的so,其中so包含arm64-v8a、armeabi-v7a
iOS:包含生成的swift代码和xcframework,其中xcframework包含ios-arm64、ios-arm64_x86_64-simulator
2.3 harmony 该目录是依赖ohrs的能力,自动生成har包
build_ohos.sh 是构建鸿蒙产物的脚本,运行 sh build_ohos.sh 即可
该目录下包含鸿蒙平台的构建产物,包含带符号、无符号的so,其中so包含arm64-v8a、armeabi-v7a、x86_64
3. 使用姿势 3.1 iOS 假设需要能够在 arm64 架构下的 iOS 及 macOS 平台下使用,因此需要使用前面生成的库文件和绑定文件创建 xcframework 以便将不同平台和架构的库集成到单个 Framework 中。
3.1.1 环境配置
1 rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios
1 $ brew install swiftformat
3.1.2 iOS 脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #!/ bin/ bash # 主要步骤: # 设置变量: # FFI = "mobile_ffi" : 设置变量FFI,代表要处理的Rust库名称 。 # XC_NAME = "mobile_rust" : 设置变量XC_NAME,可能用于指定最终XCFramework的名称 。 # 进入项目目录: # cd $FFI : 切换到由FFI变量指定的目录 。 # 为iOS目标构建Rust库: # 使用for 循环遍历iOS目标架构(aarch64- apple- ios、 aarch64- apple- ios- sim、 x86_64- apple- ios)。 # 如果目标是armv7s- apple- ios(尽管在循环中并未列出,可能是个遗留条件),则使用Rust的nightly版本和特定的Cargo特性进行构建 。 # 对于其他目标,使用默认的Cargo命令进行构建 。 # 注释掉的rustup target add $TARGET行表明原本可能计划自动安装缺少的目标,但后来决定不执行此操作 。 # 生成绑定: # 使用cargo run -- bin uniffi- bindgen generate命令生成Swift绑定,指定库文件和输出目录 。 # 重命名module.modulemap文件: # 将生成的* .modulemap文件重命名为module.modulemap,以符合iOS项目的命名约定。 # 移动Swift文件到项目目录: # 删除目标项目目录中可能存在的旧Swift文件,然后将新生成的Swift文件移动到正确的位置 。 # 创建模拟器库: # 使用lipo命令合并模拟器架构的库文件,创建一个适用于模拟器的库。 # 注释掉的行表明原本可能还计划为其他架构(如armv7s- apple- ios)创建库,但后来决定不执行此操作。 # 创建XCFramework: # 删除旧的XCFramework(如果有),然后使用xcodebuild - create- xcframework命令创建一个新的XCFramework,包含模拟器和真机架构的库 。 # 清理: # 删除临时目录和文件,以保持工作区的整洁。 FFI = "mobile_ffi" cd $FFI XC_NAME = "mobile_rust" # Add the iOS targets and build for TARGET in \ aarch64- apple- ios \ aarch64- apple- ios- sim \ x86_64- apple- ios do # rustup target add $TARGET if [ $TARGET == "armv7s-apple-ios" ]; then cargo + nightly build - Z build- std= std -- release -- target= $TARGET -- features= mock else cargo build -- release -- target= $TARGET fi done cd - # Generate bindings cargo run -- bin uniffi- bindgen generate -- library ./ target/aarch64-apple-ios/ release/lib${FFI}.dylib --language swift --out-dir ./ bindings # Rename * .modulemap to module.modulemap mv ./ bindings/${FFI}FFI.modulemap ./ bindings/ module.modulemap mkdir - p ./ dist/ios && cp ./ bindings/${FFI}.swift ./ dist/ ios mkdir sim lipo - create ./ target/x86_64-apple-ios/ release/lib${FFI}.a ./ target/aarch64-apple-ios-sim/ release/lib${FFI}.a -output ./ sim/ lib${FFI }.a # lipo - create ./ target/aarch64-apple-ios/ release/lib${FFI}.a ./ target/armv7s-apple-ios/ release/lib${FFI}.a -output ./ sm/ lib${FFI }.a # Recreate XCFramework rm - rf "dist/ios/$XC_NAME.xcframework" xcodebuild - create- xcframework \ - library ./ sim/lib${FFI}.a -headers ./ bindings \ - library ./ target/aarch64-apple-ios/ release/lib${FFI}.a -headers ./ bindings \ - output "dist/ios/$XC_NAME.xcframework" # Cleanup rm - rf bindings sim ios
使用方法:
build_ios_xc.sh 是构建iOS产物的脚本,运行 sh build_ios_xc.sh 即可
3.1.3 生成xcframework
首先我们执行上面的iOS脚本 sh build_ios_xc.sh,等执行完成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 sh build_ios_xc.sh warning : profiles for the non root package will be ignored, specify profiles at the workspace root :package : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi/Cargo .toml workspace : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/Cargo .toml Compiling proc-macro2 v1.0 .92 Compiling unicode-ident v1.0 .14 Compiling serde v1.0 .215 Compiling anyhow v1.0 .93 Compiling camino v1.1 .9 Compiling autocfg v1.4 .0 Compiling thiserror v1.0 .69 Compiling serde_json v1.0 .133 Compiling semver v1.0 .23 Compiling fs-err v2.11 .0 Compiling paste v1.0 .15 Compiling itoa v1.0 .13 Compiling memchr v2.7 .4 Compiling bytes v1.8 .0 Compiling siphasher v0.3 .11 Compiling quote v1.0 .37 Compiling ryu v1.0 .18 Compiling syn v2.0 .89 Compiling log v0.4 .22 Compiling once_cell v1.20 .2 Compiling static_assertions v1.1 .0 Compiling mobile v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/mobile) warning : unused variable : `e` --> /Users/y angcong/Documents /RustProject /mobile_rust_demo/mobile/src/log.rs :14 :19 | 14 | .map_err (|e| anyhow!("set logger failed" ))?; | ^ help : if this is intentional, prefix it with an underscore : `_e` | = note : `#[warn(unused_variables)]` on by default warning : `mobile` (lib) generated 1 warning Compiling uniffi_core v0.28 .3 Compiling serde_derive v1.0 .215 Compiling uniffi_checksum_derive v0.28 .3 Compiling thiserror-impl v1.0 .69 Compiling uniffi_meta v0.28 .3 Compiling toml v0.5 .11 Compiling bincode v1.3 .3 Compiling cargo-platform v0.1 .8 Compiling cargo_metadata v0.15 .4 Compiling uniffi_macros v0.28 .3 Compiling uniffi v0.28 .3 Compiling mobile_ffi v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi) Finished `release` profile [optimized + debuginfo] target (s) in 25. 40s warning : profiles for the non root package will be ignored, specify profiles at the workspace root :package : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi/Cargo .toml workspace : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/Cargo .toml Compiling serde v1.0 .215 Compiling anyhow v1.0 .93 Compiling semver v1.0 .23 Compiling serde_json v1.0 .133 Compiling camino v1.1 .9 Compiling thiserror v1.0 .69 Compiling ryu v1.0 .18 Compiling itoa v1.0 .13 Compiling memchr v2.7 .4 Compiling once_cell v1.20 .2 Compiling static_assertions v1.1 .0 Compiling bytes v1.8 .0 Compiling log v0.4 .22 Compiling mobile v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/mobile) warning : unused variable : `e` --> /Users/y angcong/Documents /RustProject /mobile_rust_demo/mobile/src/log.rs :14 :19 | 14 | .map_err (|e| anyhow!("set logger failed" ))?; | ^ help : if this is intentional, prefix it with an underscore : `_e` | = note : `#[warn(unused_variables)]` on by default warning : `mobile` (lib) generated 1 warning Compiling uniffi_core v0.28 .3 Compiling cargo-platform v0.1 .8 Compiling cargo_metadata v0.15 .4 Compiling uniffi v0.28 .3 Compiling mobile_ffi v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi) Finished `release` profile [optimized + debuginfo] target (s) in 13. 09s warning : profiles for the non root package will be ignored, specify profiles at the workspace root :package : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi/Cargo .toml workspace : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/Cargo .toml Compiling serde v1.0 .215 Compiling anyhow v1.0 .93 Compiling serde_json v1.0 .133 Compiling thiserror v1.0 .69 Compiling camino v1.1 .9 Compiling semver v1.0 .23 Compiling ryu v1.0 .18 Compiling memchr v2.7 .4 Compiling itoa v1.0 .13 Compiling once_cell v1.20 .2 Compiling bytes v1.8 .0 Compiling static_assertions v1.1 .0 Compiling log v0.4 .22 Compiling mobile v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/mobile) warning : unused variable : `e` --> /Users/y angcong/Documents /RustProject /mobile_rust_demo/mobile/src/log.rs :14 :19 | 14 | .map_err (|e| anyhow!("set logger failed" ))?; | ^ help : if this is intentional, prefix it with an underscore : `_e` | = note : `#[warn(unused_variables)]` on by default warning : `mobile` (lib) generated 1 warning Compiling uniffi_core v0.28 .3 Compiling cargo-platform v0.1 .8 Compiling cargo_metadata v0.15 .4 Compiling uniffi v0.28 .3 Compiling mobile_ffi v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi) Finished `release` profile [optimized + debuginfo] target (s) in 11. 31s /Users /yangcong/Documents /RustProject /mobile_rust_demo/uniffi warning : profiles for the non root package will be ignored, specify profiles at the workspace root :package : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/mobile_ffi/Cargo .toml workspace : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/Cargo .toml Compiling memchr v2.7 .4 Compiling minimal-lexical v0.2 .1 Compiling anyhow v1.0 .93 Compiling once_cell v1.20 .2 Compiling ryu v1.0 .18 Compiling itoa v1.0 .13 Compiling serde v1.0 .215 Compiling bytes v1.8 .0 Compiling thiserror v1.0 .69 Compiling fs-err v2.11 .0 Compiling utf8parse v0.2 .2 Compiling siphasher v0.3 .11 Compiling anstyle-parse v0.2 .6 Compiling heck v0.5 .0 Compiling uniffi_meta v0.28 .3 Compiling log v0.4 .22 Compiling smawk v0.3 .2 Compiling nom v7.1 .3 Compiling anstyle-query v1.1 .2 Compiling anstyle v1.0 .10 Compiling is_terminal_polyfill v1.70 .1 Compiling colorchoice v1.0 .3 Compiling textwrap v0.16 .1 Compiling scroll v0.12 .0 Compiling clap_lex v0.7 .3 Compiling anstream v0.6 .18 Compiling askama_escape v0.10 .3 Compiling plain v0.2 .3 Compiling strsim v0.11 .1 Compiling clap_derive v4.5 .18 Compiling goblin v0.8 .2 Compiling clap_builder v4.5 .21 Compiling glob v0.3 .1 Compiling static_assertions v1.1 .0 Compiling uniffi_core v0.28 .3 Compiling askama_parser v0.2 .1 Compiling weedle2 v5.0 .0 Compiling camino v1.1 .9 Compiling semver v1.0 .23 Compiling serde_json v1.0 .133 Compiling cargo-platform v0.1 .8 Compiling basic-toml v0.1 .9 Compiling toml v0.5 .11 Compiling bincode v1.3 .3 Compiling cargo_metadata v0.15 .4 Compiling clap v4.5 .21 Compiling askama_derive v0.12 .5 Compiling uniffi_testing v0.28 .3 Compiling uniffi_macros v0.28 .3 Compiling uniffi_udl v0.28 .3 Compiling askama v0.12 .1 Compiling uniffi_bindgen v0.28 .3 Compiling uniffi v0.28 .3 Compiling uniffi-bindgen v0.1 .0 (/Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/uniffi-bindgen) Finished `dev` profile [unoptimized + debuginfo] target (s) in 20. 30s Running `target/debug/uniffi-bindgen generate --library ./target/aarch64-apple-ios/release/libmobile_ffi.dylib --language swift --out-dir ./bindings` Warning : Unable to auto-format mobile_ffi.swift using swiftformat : Os { code : 2 , kind : NotFound , message : "No such file or directory" }rm : ./dist/ios/swift/mobile_ffi.swift : No such file or directoryxcframework successfully written out to : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/dist/ios/mobile.xcframework
1 xcframework successfully written out to : /Users/y angcong/Documents /RustProject /mobile_rust_demo/uniffi/dist/ios/mobile.xcframework
3.1.4 将xcframework 以及 Swift 集成到xcode
3.1.5 将Swift文件,拖动到工程中
3.1.6 调用rust生成的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @objcMembers @objc(YCTestRustTool) public class YCTestRustTool : NSObject { public static func testRust () { let content = sayHi() print ("来自rust的值" + content) let map = UniffiHandleMap <Any >() _ = map.insert(obj: "洋葱" ) _ = map.insert(obj: "数学" ) print ("插入后的map=" , map) do { let value = try map.get(handle: 1 ) print ("获取索引为1的值" , value) } catch { } do { try map.remove(handle: 1 ) print ("移除后的map=" , map) } catch { } } }
3.2 Android 3.2.1 环境配置
安装ndk
可以使用Android studio 安装,然后配置环境变量
使用cargo 安装ndk
cargo install cargo-ndk
1 2 3 4 5 6 7 - 安装工具链 - ```TypeScript rustup target add aarch64-linux-android rustup target add armv7-linux-androideabi rustup target add i686-linux-android x86_64-linux-android
确保 ktlint
已安装
运行以下命令检查 ktlint
是否可用:
ktlint --version
如果未安装,可以使用以下命令安装:
1 2 curl - sSLO https: sudo mv ktlint /usr/ local/bin/
3.2.2 Android 脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 << 'COMMENT '主要用于构建和准备用于Android平台的Rust库,并生成对应的Kotlin绑定代码 。 下面是详细的步骤解释: 1 . 设置环境变量:FFI = "mobile_ffi" :设置环境变量FFI的值为mobile_ffi,这个值将在后续步骤中用于指定库名和文件路径 。 ANDROID_STRIP = "/Users/yangcong/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-strip" :设置环境变量ANDROID_STRIP,指向Android NDK中的llvm - strip工具路径。 llvm- strip用于移除二进制文件中的符号表,以减少文件大小。 2 . 构建Rust库: cd $FFI:切换到mobile_ffi目录(即环境变量FFI指定的目录) 。 # cargo clean:这一行被注释掉了,如果取消注释,它将会清理之前的构建产物。 cargo ndk build - r:使用cargo- ndk插件构建Rust库, - r参数可能表示“release”模式,但这不是cargo ndk的标准参数,可能是特定于环境的配置或脚本的一部分。 cd .. :返回到上一级目录。 3 . 生成Kotlin绑定: cargo run -- bin uniffi- bindgen generate -- library ./ target/aarch64-linux-android/ release/lib$FFI.so --language kotlin --out-dir ./ bindings:使用uniffi- bindgen工具生成Kotlin绑定代码 。 这里指定了生成的绑定是基于aarch64- linux- android架构的release版本的libmobile_ffi.so库,输出目录为./ bindings。 4 . 准备Android发布文件: cp - r bindings/com ./ dist/android/ kotlin:将生成的Kotlin绑定代码复制到发布目录的相应位置 。 # rm - rf bindings 移除bindings目录,以清理临时文件 5 . 复制库文件到Android架构对应的目录: cp ./ target/aarch64-linux-android/ release/lib$FFI.so ./ dist/android/ symbol/arm64-v8a/ :将aarch64架构的库文件复制到arm64- v8a目录。 cp ./ target/armv7-linux-androideabi/ release/lib$FFI.so ./ dist/android/ symbol/armeabi-v7a/ :将armv7架构的库文件复制到armeabi- v7a目录。 6 . 使用llvm- strip移除符号表:mv ./ target/aarch64-linux-android/ release/lib$FFI.so ./ dist/android/ strip/arm64-v8a/ 和 mv ./ target/armv7-linux-androideabi/ release/lib$FFI.so ./ dist/android/ strip/armeabi-v7a/ :将库文件移动到用于剥离符号表的目录。 ${ANDROID_STRIP } -- strip- all ./ dist/android/ strip/arm64-v8a/ lib$FFI .so 和 ${ANDROID_STRIP } -- strip- all ./ dist/android/ strip/armeabi-v7a/ lib$FFI .so:使用llvm- strip工具移除指定库文件的所有符号表信息,以减少文件大小。 这段脚本的目的是为了构建Rust库,生成对应的Kotlin绑定代码,并准备Android平台所需的库文件,包括复制库文件到正确的架构目录和使用llvm - strip工具移除符号表以减少文件大小。 COMMENT #!/ bin/ bash FFI = "mobile_ffi" # 检查环境变量ANDROID_NDK_HOME是否存在 if [ - z "$ANDROID_NDK_HOME" ]; then echo "ANDROID_NDK_HOME is not set." else echo "ANDROID_NDK_HOME is set to $ANDROID_NDK_PATH" fi ANDROID_STRIP =/ Users /yangcong/ Library /Android/ sdk/ndk/ 25.1 .8937393 /toolchains/ llvm/prebuilt/ darwin- x86_64/bin/ llvm- stripcd $FFI # cargo clean cargo ndk build - r cd .. cargo run -- bin uniffi- bindgen generate -- library ./ target/aarch64-linux-android/ release/lib$FFI.so --language kotlin --out-dir ./ bindings mkdir - p ./ dist/android/ kotlin && cp - r bindings/com ./ dist/android/ kotlin cp - r bindings/com ./ dist/android/ kotlin cd bindings rm - rf com cd - rm - rf bindings mkdir - p ./ dist/android/ strip/arm64-v8a/ && mv ./ target/aarch64-linux-android/ release/lib$FFI.so ./ dist/android/ strip/arm64-v8a/ ${ANDROID_STRIP } -- strip- all ./ dist/android/ strip/arm64-v8a/ lib$FFI .so mkdir - p ./ dist/android/ strip/armeabi-v7a/ && mv ./ target/armv7-linux-androideabi/ release/lib$FFI.so ./ dist/android/ strip/armeabi-v7a/ ${ANDROID_STRIP } -- strip- all ./ dist/android/ strip/armeabi-v7a/ lib$FFI .so
运行脚本:
build_android.sh 是构建Android产物的脚本,运行 sh build_android.sh 即可
3.2.3 生成.so 文件和kotlin文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 sh build_android.sh warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` Building armeabi- v7a (armv7- linux- androideabi) warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: profiles for the non root package will be ignored, specify profiles at the workspace root: package : /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ uniffi/mobile_ffi/ Cargo .tomlworkspace: /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ uniffi/ Cargo .toml warning: unused variable: `e` --> /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ mobile/src/ log.rs:14 :19 | 14 | .map_err(| e| anyhow! ("set logger failed" ))? ; | ^ help: if this is intentional, prefix it with an underscore: `_e` | = note: `#[warn(unused_variables)]` on by default warning: `mobile` (lib) generated 1 warning Finished `release` profile [optimized + debuginfo] target(s) in 0 .12s Building arm64- v8a (aarch64- linux- android) warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: profiles for the non root package will be ignored, specify profiles at the workspace root: package : /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ uniffi/mobile_ffi/ Cargo .tomlworkspace: /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ uniffi/ Cargo .toml warning: unused variable: `e` --> /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ mobile/src/ log.rs:14 :19 | 14 | .map_err(| e| anyhow! ("set logger failed" ))? ; | ^ help: if this is intentional, prefix it with an underscore: `_e` | = note: `#[warn(unused_variables)]` on by default warning: `mobile` (lib) generated 1 warning Finished `release` profile [optimized + debuginfo] target(s) in 0 .05s warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: `/Users/ yangcong/.cargo/ config` is deprecated in favor of `config.toml` note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` warning: profiles for the non root package will be ignored, specify profiles at the workspace root: package : /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ uniffi/mobile_ffi/ Cargo .tomlworkspace: /Users/ yangcong/Documents/ RustProject /mobile_rust_demo/ uniffi/ Cargo .toml Finished `dev` profile [unoptimized + debuginfo] target(s) in 0 .08s Running `target/debug/ uniffi- bindgen generate -- library ./ target/aarch64-linux-android/ release/libmobile_ffi.so --language kotlin --out-dir ./ bindings` Warning : Unable to auto- format mobile_ffi.kt using ktlint: Os { code: 2 , kind: NotFound , message: "No such file or directory" }
生成对应的so 文件和kotlin文件
3.2.4 导入到工程
3.2.5 配置
配置 build.grade, 注意一定要是aar格式的。因为rust依赖的是 Java Native Access (JNA), 所以必须是aar的
修改setting.gradle
3.2.6 调用
3.3 Harmony 参考:https://ohos.rs/docs/usage/basic.html
3.3.1 答疑
我们可以直接在鸿蒙上使用原来双端或者其他端已经构建好的动态/静态链接库吗?
回答:不可以。
这就好比我们想要在iOS上面运行从安卓的NDK构建出来的动态链接库是一个道理,本身由于环境或者native使用问题或者C/C++基础库等一系列问题,导致无法跨系统直接使用。
3.3.2 环境配置
安装ohrs
安装工具链
1 2 3 rustup target add aarch64-unknown -linux-ohos rustup target add armv7-unknown -linux-ohos rustup target add x86_64-unknown -linux-ohos
检查是否安装成功
1 2 3 4 5 6 ➜ ~ ohrs doctor ✔ Environment variable OHOS_NDK_HOME should be set. ✔ Rust version should be >= 1.78 .0 . ✔ Rustup target : aarch64-unknown -linux-ohos should be installed. ✔ Rustup target : armv7-unknown -linux-ohos should be installed. ✔ Rustup target : x86_64-unknown -linux-ohos should be installed.
配置环境变量
1 2 3 export OHOS_NDK_HOME=/Users/yangcong/Library/OpenHarmony/Sdk/12 export OHOS_NDK_HOME=/Users/swain/Library/OpenHarmony/Sdk/12
3.3.3 编写脚本
思路一:按照Android的集成方式,生成.so 文件,.d.ts文件,自己去实现 cmake, cpp 流程,也能实现,但是工作量很大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 FFI ="mobile_oh" OHOS_NDK =/Users/y angcong/Library /OpenHarmony /Sdk /12 OHOS_NDK_HOME =${OHOS_NDK } ohrs build --dist=./dist/symbol / --releasecd dist rm -rf strip mkdir strip cp -r symbol
执行脚本,就会生成下面的目录结构
生成的内容很多,但是对我们有用的就是最后的 har 包
3.3.4 工程接入
导入到工程
调用