Home

Awesome

Rust core for native Android and iOS apps

Rust Android [TODO iOS badge]

This is an example that shows how to use a shared Rust core in native Android and iOS apps.

⚠️ Looking for maintainers. If you want to help, just open an issue, or email me ivanhp978@gmail.com

Why?

This approach gives us the best of all worlds: we prevent code duplication by using a shared library. Rust, as a highly performant and safe language is a great fit for mobile. We keep a fully native UI experience and uncomplicated access to the latest APIs of the platforms.

It's also very flexible, allowing to migrate easily between different platforms, including conventional cross-platform frameworks like Flutter or React Native. For example, you can develop your MVP with Rust+React Native or Rust+Flutter, and migrate later to native iOS/Android, without having to rewrite everything. You even can reuse your core for a web-app, using WebAssembly, or desktop app (where again, you can use native or a cross-platform framework like Electron).

Project structure

Possible setups

There are different ways to integrate Rust:

As source (like in this repo)

As binary

The Rust binary is distributed as an external dependency.

Note: it is possible to overwrite the external dependency with a local copy for local development.

As "normal" library

Here the external dependency contains the Rust binary and wrapper libraries for Android and iOS respectively (written in Kotlin and Swift), which hide the FFI/JNI, providing a simple and safe interface to the apps. This makes working with this dependency like with regular third parties.

An example for this and the binary approaches can be found here. The Android build contains a wrapper library, which is imported in the Android app with Gradle. The iOS build is distributed directly as a binary (no wrapper), using Carthage.

Note on concurrency

While it's possible to use asynchronous code in core, it's recommended to use blocking apis and add concurrency in the apps. This simplifies the FFI/JNI interfaces (see the CoEpi example, where the apps add concurrency via RxSwift/RxJava).

"Real world" examples

CoEpi

A mobile contact tracing app for epidemics, with Android and iOS frontends.

Xi editor

A text editor with a lot of frontends: MacOS, GTK, Electron and Windows, among others.

Other related projects

WASM-Rust-d3 example

An example that shows how to display chart data with d3/JS, using a Rust core to fetch it.

yew-d3-example

Similar to the above, but using the Yew framework

Quickstart

Install rustup

Android specific steps

export $NDK_HOME=$HOME/Library/Android/sdk/ndk/21.3.6528147/
cargo install cargo-ndk
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android

iOS specific steps

wget https://github.com/getditto/rust-bitcode/releases/download/v1.46.0/rust-ios-arm64-1.46.0.zip
unzip rust-ios-arm64-1.46.0.zip
cd rust-ios-arm64-1.46.0
./install.sh

As the binaries are not signed, you'll have to convince macOS that it's safe to run them. One solution is to do the following:

  1. cd rust_android_ios/ios_app
  2. cargo +ios-arm64-1.46.0 build --target aarch64-apple-ios --release --lib
  3. if it fails because macOS doesn't trust the binary, go to System Preferences -> Security & Privacy and Allow to run binary then go to 2.

Android specifics

iOS

Inspecting binaries

There are diverse tools to inspect the binaries, e.g.

nm -g libcore.so

Shows the external symbols, useful if you want to check that the library was generated correctly / contains the symbols from your sources.

To look for a specific symbol:

nm -g libcore.so | grep greet

Convenience

iOS

Android

Links

Official Rust FFI docs

Rust FFI guide

Official JNI docs (tutorials may be better to start...)

Android JNI tips

Android supported ABIs

Contribute

  1. Fork
  2. Commit changes to a branch in your fork
  3. Push your code and make a pull request