Rust移动开发:Rust在Android端集成使用介绍

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

PS: 也欢迎大家评论和交流~ 更多文章也可关注微信公号:良技漫谈

相关推荐
软件聚导航32 分钟前
uniapp 安卓和ios震动方法,支持息屏和后台震动,ios和安卓均通过测试
android·ios·uni-app
zhangphil41 分钟前
Android叠加双RecyclerView ScaleGestureDetector AnimatorSet动态放大缩小,Kotlin(1)
android·kotlin
studyForMokey41 分钟前
【Android零碎笔记】
android·笔记
冷眼看人间恩怨44 分钟前
【Android】Android Studio打包APK、精简APK大小与规范处理详解
android·ide·android studio·apk
码农飞飞1 小时前
详解Rust字符串用法
开发语言·算法·rust·string·所有权·字符串用法
vincent_woo1 小时前
再学安卓 - init进程
android·操作系统
zhoujun7982 小时前
Hybrid APP 移动开发-客户端
android
for_syq3 小时前
Android res复制脚本
android·linux·服务器
Object~3 小时前
【第十一课】Rust并发编程(二)
开发语言·后端·rust
WeiComp4 小时前
Android数据存储——文件存储、SharedPreferences、SQLite、Litepal
android·数据库·sqlite·litepal