天天看點

Rust在Android端的入門開發

IOS上應用還在半路上,遇到了一些內建問題。在了解、學習過程中發現,IOS的Swifit UI動畫真的是比Flutter做的好幾倍,後面有時間可以記錄記錄。本次先記錄Android內建吧,對比性能的話,可以在rust中for循環個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端的入門開發

作者:CodeOver

連結:https://juejin.cn/post/7170696817682694152

來源:稀土掘金

繼續閱讀