rust编译安卓各个平台so库

安卓studio 安装SDK 和 NDK

所有操作是mac m1 上操作的

NDK 可以在 Android studio 设置里面,搜索sdk ,然后看下SDK 位置例如我下面的位置:

/Users/admin/Library/Android/sdk/ndk

Android NDK(Native Development Kit)生成一个独立的工具链

# 其中/Users/admin/go/ndk/arm64 这个地址是生成各种平台目录
# aarch64-linux-android
python3 /Users/admin/Library/Android/sdk/ndk/27.0.12077973/build/tools/make_standalone_toolchain.py --api 27 --arch arm64 --install-dir /Users/admin/go/ndk/arm64

# armv7-linux-androideabi
python3 /Users/admin/Library/Android/sdk/ndk/27.0.12077973/build/tools/make_standalone_toolchain.py --api 27 --arch arm --install-dir /Users/admin/go/ndk/arm

# x86_64-linux-android
python3 /Users/admin/Library/Android/sdk/ndk/27.0.12077973/build/tools/make_standalone_toolchain.py  --api 27 --arch x86_64 --install-dir /Users/admin/go/ndk/x86_64

编辑 ~/.cargo/config 文件添加

# 这个是我api 27版本的,30版本好像ar要改 
[target.aarch64-linux-android]
ar = "/Users/admin/go/ndk/arm64/bin/llvm-ar"
linker = "/Users/admin/go/ndk/arm64/bin/aarch64-linux-android-clang"

[target.armv7-linux-androideabi]
ar = "/Users/admin/go/ndk/arm/bin/llvm-ar"
linker = "/Users/admin/go/ndk/arm/bin/arm-linux-androideabi-clang"

[target.x86_64-linux-android]
ar = "/Users/admin/go/ndk/x86_64/bin/llvm-ar"
linker = "/Users/admin/go/ndk/x86_64/bin/x86_64-linux-android-clang"


30 版本ar路径变了
[target.aarch64-linux-android]
ar = "/Users/你的用户名/NDK/arm64/bin/aarch64-linux-android-ar"
linker = "/Users/你的用户名/NDK/arm64/bin/aarch64-linux-android-clang"

[target.armv7-linux-androideabi]
ar = "/Users/你的用户名/NDK/arm/bin/arm-linux-androideabi-ar"
linker = "/Users/你的用户名/NDK/arm/bin/arm-linux-androideabi-clang"

[target.i686-linux-android]
ar = "/Users/你的用户名/NDK/x86/bin/i686-linux-android-ar"
linker = "/Users/你的用户名/NDK/x86/bin/i686-linux-android-clang"

rust 程序流程

创建项目
 cargo new --lib my_crypto_lib 
修改 Cargo.toml
# 下面几个值是优化包的体积 打出来so很小
[profile.release]
lto = true
opt-level = "z"
panic = "abort"
codegen-units = 1

[dependencies]
jni = "0.21.1"

[lib]
name = "my_crypto_lib"
crate-type = ["cdylib"]
rust程序
use jni::objects::{JClass, JString};
use jni::JNIEnv;
use jni::sys::{jint,jstring};

// 注意如果包名带下划线需要写成 _1

#[no_mangle]
pub extern "C" fn Java_com_example_rust_1app_RustClass_add(_env: JNIEnv, _class: JClass, a: jint, b: jint) -> jint {
    a + b
}



#[no_mangle]
pub extern "C" fn  Java_com_example_rust_1app_RustClass_processStringo<'local>(mut env: JNIEnv<'local>, _class:  JClass<'local>, input: JString<'local>) -> jstring {
    // First, we have to get the string out of Java. Check out the `strings`
    // module for more info on how this works.
    let input: String =
        env.get_string(&input).expect("Couldn't get java string!").into();

    // 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 跨平台是否安装
rustup show
安装多个安卓架构平台
# arm64
rustup target install aarch64-linux-android 
# arm32
rustup target install armv7-linux-androideabi
# amd64
rustup target install x86_64-linux-android
# amd32
rustup target install i686-linux-android


rustup show
验证编译rust so 动态库
cargo build --target aarch64-linux-android --release
cargo build --target armv7-linux-androideabi --release
cargo build --target x86_64-linux-android --release
cargo build --target i686-linux-android --release
更小的生成方式
 cargo install cargo-ndk 
 确认
 cargo intall --list
多个平台打包,这个方式比上面cargo build 要小很多具体原因不知道是什么,ndk这个库估计做了优化
# 会生成到项目目录 jniLibs 下,
cargo ndk -t armeabi-v7a -t arm64-v8a -t x86 -t x86_64 -o ./jniLibs build --release

生成如下:
在这里插入图片描述
再jniLibs目录查看下大小

find . -type f -exec du -h {} +

打包出来很小

xz:jniLibs (master*) $ find . -type f -exec du -h {} +

8.0K    ./.DS_Store
 80K    ./armeabi-v7a/libmy_crypto_lib.so
264K    ./arm64-v8a/libmy_crypto_lib.so
128K    ./x86_64/libmy_crypto_lib.so
然后吧 jniLibs 复制到java项目

如图:
在这里插入图片描述

build.gradle 修改下引入
android {
......
    sourceSets {
        main {
            jniLibs.srcDirs = ['jniLibs']
        }

        androidTest {
            jniLibs.srcDirs = ['jniLibs']
        }
    }

....
}

如图
在这里插入图片描述

安卓java程序
package com.example.rust_app;

public class RustClass {
    static {
        System.loadLibrary("my_crypto_lib");
    }

    public native int add(int a, int b);

    public native String processStringo(String a);

    public  void addTest() {
        int result = add(99, 5);
        System.out.println("Result: " + result);
        String resultStr = processStringo(",world");
        System.out.println("string:" + resultStr);
    }
}

测试效果
在这里插入图片描述

借鉴了文章: https://blog.csdn.net/ysy950803/article/details/122882360
rust jni 文档地址: https://docs.rs/jni/latest/jni/

jni 本地rust 代码调试

192:project (master*) $ tree
.
├── com
│   └── example
│       └── rust_app
│           ├── Main.class
│           ├── RustClass.class
│           └── com_example_rust_app_RustClass.h
└── src
    └── com
        └── example
            └── rust_app
                ├── Main.java
                └── RustClass.java

里面src 根据java 的包名和来的 , com 下面的不用自己创建
生成java class 文件

javac -d ./ src/com/example/rust_app/RustClass.java
javac -d ./ src/com/example/rust_app/Main.java
头文件生成
javac -h ./com/example/rust_app src/com/example/rust_app/RustClass.java

cargo build 
#引入动态库,这个需要引入本机的不是so,mac 上是.dylib 后缀,linux 是 so,windows 是dll,例如这个就是我动态库地址 /Users/admin/go/rust/my_crypto_lib/target/debug 
java -Djava.library.path=/Users/admin/go/rust/my_crypto_lib/target/debug com.example.rust_app.Main

就会调用动态库方法

例如我rust 代码 lib.rs

mod lib_aes;

use jni::objects::{JClass,  JString};
use jni::JNIEnv;
use jni::sys::{jint,jstring};
// cargo ndk -t armeabi-v7a -t arm64-v8a -t x86_64 -o ./jniLibs build --release


#[no_mangle]
pub extern "C" fn Java_com_example_rust_1app_RustClass_add(_env: JNIEnv, _class: JClass, a: jint, b: jint) -> jint {
    a + b
}


#[no_mangle]
pub extern "C" fn  Java_com_example_rust_1app_RustClass_processStringo<'local>(mut env: JNIEnv<'local>, _class:  JClass<'local>, input: JString<'local>) -> jstring {
    let mut input: String =
        env.get_string(&input).expect("Couldn't get java string!").into();
    test_add(&mut input);
    let output = env.new_string(format!("Hello, {}!", input))
        .expect("Couldn't create java string!");

    output.into_raw()

}


#[no_mangle]
pub extern "C" fn  Java_com_example_rust_1app_RustClass_decode<'local>(mut env: JNIEnv<'local>, _class:  JClass<'local>, input: JString<'local>) -> jstring {


    // 尝试从 Java 字符串转换为 Rust String
    let input_result = env.get_string(&input);

    match input_result {
        Ok(rust_string) => {
            // 成功转换后进行操作
            let rust_string: String = rust_string.into();

            let output = env.new_string(lib_aes::decode_run(&rust_string));
            // 检查新字符串创建是否成功
            match output {
                Ok(java_string) => java_string.into_raw(),
                Err(_) => {
                    // 创建输出字符串失败,返回空字符串
                    env.new_string("").expect("Couldn't create Java string!").into_raw()
                }
            }
        },
        Err(_) => {
            // 输入字符串转换失败,返回空字符串
            env.new_string("").expect("Couldn't create Java string!").into_raw()
        }
    }



}




fn test_add(s: &mut String) {
    s.push_str(" How are you?");
}

java RustClass.java 代码

public class RustClass {
    static {
        System.loadLibrary("my_crypto_lib");
    }

    public native int add(int a, int b);

    public native String processStringo(String a);
    public native String decode(String a);

    public void addTest() {
        String resultJson = decode("fpFgVAlfnUpiq7JI909po4VLw/vS+p4A8AVgwnVsZwcZSN2b/I44o/4pGEP5oHVCRBQx4aJeUSlumboaWBjJx/5usD1Ju4d6XwZWZ2CC+9I=");
        System.out.println("解密:" + resultJson);
    }
}

java Main.java

package com.example.rust_app;

public class Main {
    public static void main(String[] args) {
        RustClass rustClass = new RustClass();
        rustClass.addTest();
    }
}

openssl 编译失败解决方式

https://gist.github.com/ospfranco/7b691ddc8f2fdba66dde5f67564a7c69

https://stackoverflow.com/questions/76352747/openssl-cross-compilation-fails添加链接描述

相关推荐

  1. 使用so

    2024-07-18 14:54:01       26 阅读
  2. Rust 语言中的跨 GUI

    2024-07-18 14:54:01       28 阅读
  3. 的在线视频下载神器—Seal

    2024-07-18 14:54:01       100 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 14:54:01       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 14:54:01       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 14:54:01       57 阅读
  4. Python语言-面向对象

    2024-07-18 14:54:01       68 阅读

热门阅读

  1. C++代码_让室友坑我

    2024-07-18 14:54:01       21 阅读
  2. 网络安全-网络安全及其防护措施10

    2024-07-18 14:54:01       21 阅读
  3. 反悔贪心和例题

    2024-07-18 14:54:01       24 阅读
  4. Docker 镜像存储目录的位置修改教程

    2024-07-18 14:54:01       24 阅读
  5. 生成Elasticsearch xpack安全认证证书

    2024-07-18 14:54:01       20 阅读
  6. 计算机视觉篇5 图像的位置--边框

    2024-07-18 14:54:01       18 阅读
  7. 大龄程序员的出路在哪里?

    2024-07-18 14:54:01       22 阅读