背景
最近持续在学习 Rust 相关知识,之前写了一篇 Rust 学习笔记 - Android Native 信号捕获(安全气囊)。在学习编写这部分代码的时候,我发现了一个痛点:每次修改 Rust 写的 Native 代码后,都需要将编译生成的.so 文件手动复制到 Android 项目中,这种重复劳动不仅繁琐,而且容易出错,而且Android Studio插件库检索不到Rust扩展,理论上它也是基于idea开发的🤔。

不过提高效率,寻思编写一个Python脚本,然后自动挪动,但发现这样做细节比较多,Build 生成的资源路径比较多,不规范且效率也不高。最近在 GitHub 上发现了一个欢迎度比较高的Gradle 插件,用的人比较多,使用起来非常方便,遇到的问题较少。特此记录并分享这个解决方案,希望对其他开发者有所帮助。
Rust开发必备仓库介绍
由 Mozilla (火狐浏览器最为知名)提供的插件,用于在 Android 项目中集成 Rust 代码。它简化了将 Rust 编译成 Android 原生库的过程,使开发者可以轻松地在 Android 应用中使用高性能的 Rust 代码,同时利用 Gradle 构建系统的便利性。
Rust Mobile 是一个支持 Rust 开发移动应用程序(如 Android 和 iOS)的组织。他们的目标是通过创建和维护相关的 Rust crates(库),促进移动开发方面的协作和工具开发。他们关注的问题包括标准化库的链接方式、SDK 版本控制以及 JNI 调用的处理方法。
配置依赖
首先,由于Android Studio不支持下载Rust插件,所以我仍然使用IntelliJ IDEA开发。
此时需要安装Android插件与Rust插件,并配置好Android SDK & NDK。
新建创建一个Android项目,我这边仍然以 NativeAirbag 为例。
Step 1
添加Rust Gradle插件。
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.2.0' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
id 'org.jetbrains.kotlin.jvm' version '1.9.0' apply false
id 'com.android.library' version '8.2.0' apply false
id "org.mozilla.rust-android-gradle.rust-android" version "0.9.4"
}
Step 2
对 app 模块配置 Rust 插件。
plugins {
id 'org.mozilla.rust-android-gradle.rust-android' // 坑 1 :一定在首位添加 不然会导致 elf 打包失败,找不到 elf 文件。
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
此时 async gradle 会报错。

缺少插件配置cargo的一些参数,我们先别急着配置。
Step 3
此时需要构建出我们的 Rust工程包,由于我们想做一个 NativeAirbag 的SDK,所以我这边创建了一个子module。

我们所有的逻辑通过 Rust 实现在这个 module,所以就在这个工程模块下创建。
我们可以使用命令
cd airbag/src/main/rust
cargo new airbag
这样就创建了一个Rust工程文件夹。
Step 4
第三步搞定之后我们就可以配置一下 插件中的 cargo 的参数了,同样在app模块下添加配置。
cargo {
module = "../airbag/src/main/rust/airbag" // 配置一下 Rust 工程路径
libname = "airbag" // 这里要与 Cargo.toml 中的 name 值一样
targets = ["x86_64", "arm64"] // 指定 CPU架构,到时候编译时会生成对应的 elf 文件
// profile = 'release'
profile = 'debug'
}
这个 Cargo插件参数有很多配置,前三个字段是必须指定的。其他参数配置可以参考文档与源码酌情设置。
Step 5
由于我们改动 Rust 代码以后需要触发编译,然后在 Android 侧调用 JNI 等等去调试。
需要 每次去执行 ./gradlew cargoBuild 去构建,所以比较麻烦,创建一个 task 过滤器在执行构建 apk 打包的行为前,先触发Rust 编译,如下代码。
tasks.configureEach { task ->
if ((task.name == 'javaPreCompileDebug' || task.name == 'javaPreCompileRelease')) {
// task.dependsOn 'cargoBuild'
// task.dependsOn 'cargoBuildArm'
task.dependsOn 'cargoBuildArm64'
task.dependsOn 'cargoBuildX86_64'
}
}
Step 6
此时有时候我们触发./gradlew cargoBuild会报错,
/usr/bin/env bash /Users/edisonli/Downloads/NativeAirbag/build/linker-wrapper/linker-wrapper.sh
->/usr/bin/env bash /Users/edisonli/Downloads/NativeAirbag/build/linker-wrapper/linker-wrapper.sh
/Users/edisonli/Downloads/NativeAirbag/build/linker-wrapper/linker-wrapper.sh: line 4: : command not found
因为这个 Rust 插件需要结合 Python执行一些文件操作,因此需要指定 Python路径,如果你有这个问题,请在 local.properties 文件中添加 python路径。
rust.pythonCommand=/opt/homebrew/bin/python3
当然你也可以不用 python 可以配置其他的方式。
Step 7
执行 apk 打包命令的时候,Rust 编译好的 elf 文件会自动打包到 apk 中,非常的方便。

按照上述路径足以支持初学 Rust 语言并且希望可以在 Android 上实践的同学, 开始写 Rust 吧。
如果进一步入门可以参考如下几篇。
Rust 学习笔记 - Android Native 信号捕获(安全气囊)
TODO
现在遗留一些开发上的问题
如何断点调试?
待研究。
kotlin JNI调用找不到方法?
native方法无法找到Rust中的JNI函数,即便包名+类名都是正确的。切换成Java就OK。
2024-09-18 更新
测试的代码
修改后的代码
2024-11-13 更新
最近编译运行发现python版本升级到3.13版本以后,会导致编译时提示import pipes找不到,查询了一下再新版本中它已经被弃用了。
解决方案
rust.pythonCommand=/opt/homebrew/bin/python3.12
使用指定python 3.12版本