安卓中使用rust构建的so文件

846 阅读3分钟

本文简介

rust是一门新兴的编程语言,本文介绍了如何将rust编译成安卓中可以使用的so文件,以及在安卓中使用so文件的详细过程。

本文将会比较详细的列举实现步骤,并说明其中的一些细节,但阅读者仍需要有一些rust与安卓开发的基础知识,比如Cargo包管理工具与Andriod Studio等。

微小建议:如遇到一些不熟悉的概念与问题,可在人工智能平台上咨询了解,如ChatGPT或豆包等,本人使用的是豆包。

编译为so文件

创建rust项目

使用命令cargo new so_rust创建so_rust项目

编辑Cargo.toml文件,增加lib.create-type配置与jni依赖,最终内容如下:

[package]
name = "so_rust"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
jni = { version = "0.19.0", default-features = false }

crate-type为cdylib,表明在构建目标平台(比如linux)的动态库时,将会生成目标平台的动态库文件(比如linux中为so文件,安卓是基于linux的),官方文档参考链接:doc.rust-lang.org/reference/l…


创建src/lib.rs文件,并复制以下内容

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[allow(non_snake_case)]
pub mod android {

    use super::add;
    use jni::objects::*;
    use jni::sys::*;

    #[no_mangle]
    pub unsafe extern "C" fn Java_com_sprite_donk_Adder_add(
        _env: JNIEnv,
        _class: JClass,
        num_a: jint,
        num_b: jint,
        ) -> jint {
        add(num_a, num_b)
    }
}
  • ⚠️ Java_com_sprite_donk_Adder_add方法有特别的含义,JAVA_是固定写法,com_sprite_donk(随便写的、请勿在意)是Java的包名,Adder是类名,add是Adder类的静态方法名
  • 使用com_sprite_donk是为了体现包名是可以通用的,不必与安卓项目名保持一致

项目目录内,创建.cargo/config配置文件,并输入以下内容

[target.aarch64-linux-android]
linker = "/Users/xxx/Library/Android/sdk/ndk/28.0.12433566/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android22-clang"
  • aarch64-linux-android,为目标平台,在打包时会使用--target aarch64-linux-android参数来指定
  • linker为安卓ndk中的clang文件地址,是rust编译中会使用到的一个工具
  • 关于安卓ndk的安装,可自行搜索相关教程

使用cargo build --target aarch64-linux-android --release命令构建so文件

不出意外的话,此文件的地址为target/aarch64-linux-android/release/libso_rust.so

在安卓中使用so文件

libso_rust.so文件拷贝到安卓项目的app/src/main/jniLibs/arm64-v8a目录下

  • jniLibs是一个用于存放本地库(Native Libraries)文件的目录,也就是so文件存放的位置
  • 关于arm64-v8a,jniLibs目录下通常会有根据不同CPU架构划分的子目录,arm64-v8a指ARM64位架构,安卓手机的CPU通常使用此架构

创建rust文件中Java_com_sprite_donk_Adder_add方法名对应的Java类

此处是在app/src/main/java中创建com.sprite.donk.Adder类,并写入以下内容:

package com.sprite.donk;

public class Adder {
    static {
        System.loadLibrary("so_rust");
    }

    public static native int add(int numA, int numB);
}

(防小白)com.sprite.donk.Adder并不是文件名,实际文件地址为app/src/main/java/com/sprite/donk/Adder.java


使用com.sprite.donk.Adder

可以在MainActivity.kt中引入引入该类并在onCreate中使用,部分代码如下:


// ...省略部分代码

// 引入Adder类
import com.sprite.donk.Adder

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 使用Adder类,并捕获错误(如有、防闪退)
        try {
            val res = Adder.add(10, 20)
            Log.i("MainActivityError", res.toString())
        } catch (e: Error) {
            Log.i("MainActivityError",e.message.*toString*())
        }
        
        // ...省略部分代码
    }
}

// ...省略部分代码

kt是kotlin文件后缀,kotlin中可以直接使用JAVA类

之后可以使用Andriod Studio调试运行安卓app,并查看Logcat信息

总结

通过将rust代码编译为so文件,并在安卓中使用,是一种方式

也可以使用mozilla官方提供的Rust Android Gradle Plugin,项目地址为:github.com/mozilla/rus…