Rust在Android端集成使用详解
作者:良技漫谈
本文介绍了如何在Android平台上调用Rust编写的组件,详细说明了开发环境的搭建、Rust库的创建、配置和编译过程,以及如何在Android应用中使用Rust编写的代码,文中提到飞书底层使用Rust编写通用组件,展示了Rust在移动端开发中的应用价值
Andorid调用Rust
- 目前Rust在移动端上的应用,一般作为应用sdk的提供,供各端使用,目前飞书底层使用Rust编写通用组件。
- 该篇适合对Android、Rust了解,想看如何做整合,如果想要工程源码,可以评论或留言有解疑也可进行询问(更多最新文章也可关注微信公号:良技漫谈)
一.开发环境:
- 确保rust开发环境,推荐官方文档, 安装即可
- Android相关开发环境,需要NDK的下载安装
- 环境变量的配置,为命令行使用提供全局环境
开发工具:
1. 如果对android studio比较熟悉,可安装rust插件
安装完毕,对Rust Toolchain 位置进行配置确认,否则可能对rs文件无法识别,就无法愉快使用studio编写rust
2. 推荐使用VSCode编写rust代码,可以去下载 Visual Studio Code,然后安装rust相关插件即可。
二.创建Android工程:
• 如果对Android比较熟悉,使用studio来创建工程,和其他Android工程创建一样,创建Empty Activity,工程名 AndroidIntegratingRust
先编译通过该空工程,确保依赖资源下载完整。
三,添加rust lib库:
进入到刚创建的AndroidIntegratingRust工程下
1.使用rust Cargo创建 lib库:
Cargo new rust_lib --lib
• 创建成功后会有rust_lib库,结构如下:
├── app │ ├── build │ ├── build.gradle │ ├── libs │ ├── proguard-rules.pro │ └── src ├── build │ └── kotlin ├── build.gradle ├── gradle │ └── wrapper ├── gradle.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── rust_lib //位置在这 │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ └── target └── settings.gradle
2.编辑Cargo.toml
输入目前需要的jni库依赖, https://crates.io/地址下确认版本, create-type 填写cdylib 动态链接库
[lib] name = "rust_lib" crate-type = ["cdylib"] [dependencies] jni = "0.20.0"
3.配置要编译so的linker及target
- 这个在rust_lib下创建.cargo目录,添加config.toml配置文件
- 填入linker对应的ndk地址:
[target.aarch64-linux-android] linker = "/Users/android-sdk-macosx/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang++" [target.armv7-linux-androideabi] linker = "/Users/android-sdk-macosx/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang++"
ps: 这是我的mac上ndk所在位置,参考Android官方ndk文档。
准备编译rust代码为so的环境已经准备完
四,编写Android和Rust代码:
创建Android代码, RustGreetings类, 使用kotlin所以用external声明JNI函数
class RustGreetings { fun sayHello(to: String): String { return greeting(to) } companion object { @JvmStatic external fun greeting(pattern: String): String } }
在Rust lib库下,编写对应的JNI函数映射,从create.io下可以看到有关JNI的使用,代码如下
use jni::JNIEnv; // These objects are what you should use as arguments to your native // function. They carry extra lifetime information to prevent them escaping // this context and getting used after being GC'd. use jni::objects::{JClass, JString}; // This is just a pointer. We'll be returning it from our function. We // can't return one of the objects with lifetime information because the // lifetime checker won't let us. use jni::sys::jstring; // This keeps Rust from "mangling" the name and making it unique for this // crate. #[no_mangle] pub extern "system" fn Java_com_android_integratingrust_RustGreetings_greeting( env: JNIEnv, // This is the class that owns our static method. It's not going to be used, // but still must be present to match the expected signature of a static // native method. class: JClass, input: JString, ) -> jstring { // First, we have to get the string out of Java. Check out the `strings` // module for more info on how this works. let mut input: String = env .get_string(input) .expect("Couldn't get java string!") .into(); input = append_string(&input); // Then we have to create a new Java string to return. Again, more info // in the `strings` module. let output = env .new_string(format!("Hello, {}!", input)) .expect("Couldn't create java string!"); // Finally, extract the raw pointer to return. output.into_raw() } //============== rust code =============== fn append_string(value: &str) -> String { let mut origin = String::from(value); origin.push_str("this is Rust"); return origin; }
五,编译Rust代码为so
- 编译之前确认之前rust环境是可以使用的了,且要看下rustup target 下是否已经有要交叉编译的工具了。
- rustc --print target-list | grep android 可以查看相关android 交叉编译工具,(我们demo之前在配置target时,使用了32和64位的ARM CPU 架构linker)
aarch64-linux-android arm-linux-androideabi armv7-linux-androideabi i686-linux-android thumbv7neon-linux-androideabi x86_64-linux-android
如果没有安装,需要安装下对应的
rustup target add aarch64-linux-android armv7-linux-androideabi
- rustup show 可以看到当前rust开发语言环境,包括 (installed targets for active toolchain)
- rustup target list可以查看到那些已经安装和rust支持的。
执行编译
到rust_lib目录下执行编译
cargo build --target aarch64-linux-android --release
编译成功到target目录下release下去查看对应的so文件
. ├── CACHEDIR.TAG ├── aarch64-linux-android │ ├── CACHEDIR.TAG │ └── release ├── armv7-linux-androideabi │ ├── CACHEDIR.TAG │ └── release ├── debug │ ├── build │ ├── deps │ ├── examples │ └── incremental └── release ├── build ├── deps ├── examples └── incremental
六,使用rust代码运行工程
sourceSets { main { jniLibs.srcDirs = ['src/main/libs'] } }
- copy 对应的so文件到 Android工程下src/main/libs下
- 在Android工程下build.gradle下记得引用so为jniLibs
到此这篇关于Rust在Android端集成使用介绍的文章就介绍到这了,更多相关Rust Android集成使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!