前语

IOS上运用还在半路上,遇到了一些集成问题。在了解、学习过程中发现,IOSSwifit UI动画真的是比Flutter做的好几倍,后边有时刻能够记载记载。本次先记载Android集成吧,比照功能的话,能够在rustfor循环个10万次,比照C的时刻消耗。
参考资料
Building and Deploying a Rust library on Android
JNI Create
Create JNI

目录

Rust在Android端的入门开发

一、环境准备

rustup装备

这个装备,在装rust的时候就装备了,能够忽略。如果没有装备,想了解的能够看二、Rust入门之Hello World

装备NDK

第一步
先确定自己的NDK目录
默许目录一般都在/Users/你的用户名/Library/Android/sdk/ndk-bundle这个方位,用户目录能够用${HOME}代替。

第二步
创立库crate

cargo new android_demo --lib

第三步
切换到 android_demo 项目下,创立 NDK 文件
找到 make_standalone_toolchain.py 文件,履行以下句子

python D:/Android/SDK/ndk-bundle/build/tools/make_standalone_toolchain.py --api 26 --arch arm64 --install-dir NDK/arm64
python D:/Android/SDK/ndk-bundle/build/tools/make_standalone_toolchain.py --api 26 --arch arm --install-dir NDK/arm
python D:/Android/SDK/ndk-bundle/build/tools/make_standalone_toolchain.py --api 26 --arch x86 --install-dir NDK/x86

对应的NDK目录如下

Rust在Android端的入门开发

第四步
找到 cargo的装备文件,~/.cargo/config

[target.aarch64-linux-android]
ar = "E:/VSCodeWorkspace/rust/android_demo/NDK/arm64/bin/aarch64-linux-android-ar"
linker = "E:/VSCodeWorkspace/rust/android_demo/NDK/arm64/bin/aarch64-linux-android-clang"
[target.armv7-linux-androideabi]
ar = "E:/VSCodeWorkspace/rust/android_demo/NDK/arm/bin/arm-linux-androideabi-ar"
linker = "E:/VSCodeWorkspace/rust/android_demo/NDK/arm/bin/arm-linux-androideabi-clang"
[target.i686-linux-android]
ar = "E:/VSCodeWorkspace/rust/android_demo/NDK/x86/bin/i686-linux-android-ar"
linker = "E:/VSCodeWorkspace/rust/android_demo/NDK/x86/bin/i686-linux-android-clang"

其间 E:/VSCodeWorkspace/rust/android_demo 是本次项目目录。

第五步
增加工具链

rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android

第六步
在当时 android_demo 目录下,履行以下句子
编译Rust项目,按需求的架构编译即可。

cargo build --target aarch64-linux-android --release
cargo build --target armv7-linux-androideabi --release
cargo build --target i686-linux-android --release
  • 出现问题
    • note: %1 不是有用的 Win32 运用程序。 (os error 193) ,第三步和第六步编译不一致。解决方法:将第四步,换成Android SDK 目录下的ndk,看下面代码示例。
    • error: linker cc not found,解决方案也是依照下面,一定要运用 .cmd

解决方案

[target.aarch64-linux-android]
ar = "D:\\Android\\SDK\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\aarch64-linux-android-ar"
linker = "D:\\Android\\SDK\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\aarch64-linux-android26-clang.cmd"
[target.armv7-linux-androideabi]
ar = "D:\\Android\\SDK\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\arm-linux-androideabi-ar"
linker = "D:\\Android\\SDK\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\armv7a-linux-androideabi26-clang++.cmd"
xxx

产品

Rust在Android端的入门开发

二、Rust实现

Cargo.toml

[package]
name = "android_demo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
jni-sys = "0.3.0"
[target.'cfg(target_os="android")'.dependencies]
jni = { version = "0.5", default-features = false }
[lib]
crate-type = ["dylib"]

lib.rs

/*
 * @Author: axiong
 */
use std::os::raw::{c_char};
use std::ffi::{CString, CStr};
#[no_mangle]
pub extern fn rust_greeting(to: *const c_char) -> *mut c_char {
    let c_str = unsafe { CStr::from_ptr(to) };
    let recipient = match c_str.to_str() {
        Err(_) => "there",
        Ok(string) => string,
    };
    CString::new("Hello ".to_owned() + recipient).unwrap().into_raw()
}
/// Expose the JNI interface for android below
/// 只要在方针渠道是Android的时候才敞开 [cfg(target_os="android")
/// 由于JNI要求驼峰命名,所以要敞开 allow(non_snake_case)
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
    extern crate jni;
    use super::*;
    use self::jni::JNIEnv;
    use self::jni::objects::{JClass, JString};
    use self::jni::sys::{jstring};
    #[no_mangle]
    pub unsafe extern fn Java_com_rjx_rustdemo_RustGreeting_greeting(env: JNIEnv, _: JClass, java_pattern: JString) -> jstring {
        // Our Java companion code might pass-in "world" as a string, hence the name.
        let world = rust_greeting(env.get_string(java_pattern).expect("invalid pattern string").as_ptr());
        // Retake pointer so that we can use it below and allow memory to be freed when it goes out of scope.
        let world_ptr = CString::from_raw(world);
        let output = env.new_string(world_ptr.to_str().unwrap()).expect("Couldn't create java string!");
        output.into_inner()
    }
}

三、Android集成

SO集成

Rust在Android端的入门开发

RustGreeting.java

public class RustGreeting {
    static {
        System.loadLibrary("android_demo");
    }
    private static native String greeting(final String pattern);
    public static String sayHello(String to) {
        return greeting(to);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    // Used to load the 'native-lib' library on application startup.
    static {
        //System.loadLibrary("native-lib");
    }
    private ActivityMainBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(RustGreeting.sayHello("Rust!!"));
    }
}

作用

Rust在Android端的入门开发