- Install rust
- Add $ANDROID_HOME, $NDK_HOME and $JAVA_HOME
Hasans-Air:~ h_ajsf$ sudo code $HOME/.bash_profile
// Write below
PATH=$PATH:/usr/local/Cellar/flutter/bin
PATH=$PATH:/Users/$USER/.cargo/bin
PATH=$PATH:${ANDROID_HOME}/tools/
export JAVA_HOME=$(/usr/libexec/java_home)
export ANDROID_HOME=/usr/local/share/android-sdk
export NDK_HOME=$ANDROID_HOME/ndk-bundle
// save and Exit
// Confirm changes
Hasans-Air:~ h_ajsf$ source $HOME/.bash_profile
- Add Android targets:
Hasans-Air:ndk h_ajsf$ rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android arm-linux-androideabi
For iOS, below targets are require:
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios i386-apple-ios
- Create rust lib
Hasans-Air:greetings h_ajsf$ cargo new rust_lib_for_android --lib
Created binary (application) `cargo` project
Hasans-Air:greetings h_ajsf$ cd rust_lib_for_android
- Create chain tools Using rustup, like:
Hasans-MacBook-Air:~ h_ajsf$ rustup target add x86_64-linux-android
Hasans-MacBook-Air:~ h_ajsf$ rustup toolchain install stable-x86_64-linux-android
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ rustup override set stable-x86_64-linux-android
see (here)[https://forge.rust-lang.org/platform-support.html] for supported platforms.
Or, using Android NDK, as not all Tier 2 platforms are working fine with rustup tolchain
, NDK can be used as:
usage: make_standalone_toolchain.py [-h] --arch {arm,arm64,x86,x86_64}
[--api API] [--stl STL] [--force] [-v]
[--package-dir PACKAGE_DIR | --install-dir INSTALL_DIR]
Details commands are below:
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ ${NDK_HOME}/build/tools/make_standalone_toolchain.py --api 28 --arch x86_64 --install-dir NDK/x86_64
Hasans-Air:rust_lib_for_android h_ajsf$ ${NDK_HOME}/build/tools/make_standalone_toolchain.py --api 28 --arch arm64 --install-dir NDK/arm64
Hasans-Air:rust_lib_for_android h_ajsf$ ${NDK_HOME}/build/tools/make_standalone_toolchain.py --api 28 --arch arm --install-dir NDK/arm
Hasans-Air:rust_lib_for_android h_ajsf$ ${NDK_HOME}/build/tools/make_standalone_toolchain.py --api 28 --arch x86 --install-dir NDK/x86
For iOS,cargo-lipo
creates a universal library, and can be installed as below:
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ cargo install cargo-lipo
- Create /.cargo/config file
Hasans-Air:rust_lib_for_android h_ajsf$ mkdir .cargo
Hasans-Air:rust_lib_for_android h_ajsf$ cd .cargo
Hasans-Air:.cargo h_ajsf$ touch config
- Open the greetings folder in your favorite IFE, I'm using VS Code
Hasans-Air:.cargo h_ajsf$ cd ..
Hasans-Air:rust_lib_for_android h_ajsf$ cd ..
Hasans-Air:documents h_ajsf$ ls
rust_lib_for_android
Hasans-Air:documents h_ajsf$ code rust_app
- Add the below to the /.cargo/config file
[target.x86_64-linux-android]
ar = "NDK/x86/bin/x86_64-linux-android-ar"
linker = "NDK/x86_64/bin/x86_64-linux-android-clang"
[target.aarch64-linux-android]
ar = "NDK/arm64/bin/aarch64-linux-android-ar"
linker = "NDK/arm64/bin/aarch64-linux-android-clang"
[target.armv7-linux-androideabi]
ar = "NDK/arm/bin/arm-linux-androideabi-ar"
linker = "NDK/arm/bin/arm-linux-androideabi-clang"
[target.i686-linux-android]
ar = "NDK/x86/bin/i686-linux-android-ar"
linker = "NDK/x86/bin/i686-linux-android-clang"
- Replace the content of the src/lib.rs by the below:
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
#[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_mozilla_greetings_RustGreetings_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()
}
}
- Add the below to the Cargo.toml
[target.'cfg(target_os="android")'.dependencies]
jni = { version = "0.5", default-features = false }
[lib]
name = "greetings"
crate-type = ["dylib"]
- Build the static library for each target
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ cargo build --target x86_64-linux-android --release
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ cargo build --target aarch64-linux-android --release
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ cargo build --target armv7-linux-androideabi --release
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ cargo build --target i686-linux-android --release
Note aarch64
can be used for both arm64
and arm64-v8a
For iOS, run cargo lipo --release
Hasans-MacBook-Air:rust_lib_for_android h_ajsf$ cargo lipo --release
Due to a known rustc issue, cargo-lipo can only be run on macOS. See https://github.com/rust-lang/rust/issues/36156#issuecomment-373201676 for more info.
Compiling cargo v0.1.0 (/Users/h_ajsf/Documents/greetings/rust_lib_for_android)
warning: dropping unsupported crate type `dylib` for target `aarch64-apple-ios`
warning: dropping unsupported crate type `cdylib` for target `aarch64-apple-ios`
Finished release [optimized] target(s) in 5.90s
Compiling cargo v0.1.0 (/Users/h_ajsf/Documents/greetings/rust_lib_for_android)
warning: dropping unsupported crate type `dylib` for target `armv7-apple-ios`
warning: dropping unsupported crate type `cdylib` for target `armv7-apple-ios`
Finished release [optimized] target(s) in 0.98s
Compiling cargo v0.1.0 (/Users/h_ajsf/Documents/greetings/rust_lib_for_android)
warning: dropping unsupported crate type `dylib` for target `i386-apple-ios`
warning: dropping unsupported crate type `cdylib` for target `i386-apple-ios`
Finished release [optimized] target(s) in 1.56s
Compiling cargo v0.1.0 (/Users/h_ajsf/Documents/greetings/rust_lib_for_android)
warning: dropping unsupported crate type `dylib` for target `x86_64-apple-ios`
warning: dropping unsupported crate type `cdylib` for target `x86_64-apple-ios`
Finished release [optimized] target(s) in 0.88s
And the universal iOS library can be found in cargo/target/universal/release/libgreetings.a
- For iOS:
- Add the
greetings.h
file, by:File\Add files to "Greetings"...
- Add native file
libgreetings.a
and the native interactive frameworklibresolv.tbd
byGeneral -> Linked Frameworks and Libraries
- Create bridging header
Greetings-Bridging-Header.h
byFile\New\File.... Header File
and import thegreetings.h
file into it so the file became as below:
#ifndef Greetings_Bridging_Header_h
#define Greetings_Bridging_Header_h
#import "greetings.h"
#endif
- Update the
Build Settings -> Objective-C Bridging Header
by adding the path ofGreetings-Bridging-Header.h
file - Update the
Build Settings -> Library Search Paths
by adding the path of importedlibgreetings.a
file - Create
RustGreetings
swift file byFile\New\File...
andiOS\Source\Swift File
, and add to it the:
class RustGreetings {
func sayHello(to: String) -> String {
let result = rust_greeting(to)
let swift_result = String(cString: result!)
rust_greeting_free(UnsafeMutablePointer(mutating: result))
return swift_result
}
}
- Update the
viewDidLoad
in theViewController.swift
file, by adding:
let rustGreetings = RustGreetings()
print("\(rustGreetings.sayHello(to: "world"))")
Top comments (2)
Wow, I have never thought about building Android app in Rust, nice to see it's possible (despite the fact that I am not so good at coding in Rust as in other languages). Will probably experiment with it in the future. Thanks!
I saw that go(Lang) had the option to build for Android (and iOS) and with rust supporting wasm I meant to look into it. You verified it for me.
Was that "platform support" page the only resource you used?
Also, what's that lipo crate for? Is that the only way to make a universal binary because the tool chains can't do it themselves?