-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
124 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,143 @@ | ||
# rust_android_ios | ||
# Android / iOS app with shared Rust logic | ||
|
||
Android/iOS app with shared Rust logic | ||
|
||
Based on the [Rust Swig](https://github.com/Dushistov/rust_swig) Android example with added support for iOS from [rust-ios-android-example](https://github.com/terhechte/rust-ios-android-example) + upgrade and customization. | ||
#### ✅ Functions | ||
Calls Rust functions from Android / iOS, shows return value in UI. | ||
|
||
The idea is to continue evolving this. Maybe a little mobile Rust framework? It would be interesting to explore reactive (have a Rust stream propagate down to Swift UI or Jetpack compose!). | ||
#### ✅ Callback | ||
Passes callback to Rust and updates UI on Android / iOS with call. | ||
|
||
See [talk](https://www.youtube.com/watch?v=fq1pQ0RpstM) from [@terhechte](https://github.com/terhechte) - this started this! | ||
#### ✅ Reactive | ||
Subscribes in Android / iOS to events triggered by Rust and updates UI with them. | ||
|
||
## Instructions | ||
#### ✅ Unidirectional flow | ||
UI sends event to Rust. Rust emits to channel that is observed in Android / iOS. This allows to e.g. implement MVVM architecture writing the view models in Rust (with some glue to convert the observer-callbacks in observables/channels/SwiftUI/Jetpack compose/etc). | ||
|
||
### Android | ||
# Android / iOS | ||
|
||
Ensure [rustup](https://rustup.rs/) is installed. This includes [Cargo](https://doc.rust-lang.org/cargo/), so you should be able to compile & build Rust projects + install the required targets to build for Android and iOS. | ||
|
||
List available targets: `rustup target list` | ||
Show currently installed targets: `rustup toolchain list` | ||
|
||
The Rust sources are [here](src) | ||
|
||
# Android | ||
|
||
These steps show how to build and run an Android app in debug mode for a 64 bits emulator. | ||
|
||
See [rust_swig documentation](https://dushistov.github.io/rust_swig/java-android-example.html) | ||
|
||
|
||
### iOS | ||
### NDK | ||
|
||
Ensure the [NDK](https://developer.android.com/ndk/guides) is installed. | ||
|
||
### Environment variables | ||
|
||
``` | ||
ANDROID_TOOLCHAINS=<Directory where targets should be installed> | ||
ANDROID_NDK=<NDK's root directory> | ||
``` | ||
|
||
### Add targets | ||
|
||
`rustup target add x86_64-linux-android` | ||
|
||
### Add path to linker | ||
|
||
- Update linker path in <project_root>/.cargo/config: | ||
|
||
``` | ||
[target.x86_64-linux-android] | ||
linker = "<Directory where targets were installed (provided in environment variable)>/android-29-x86_64-4.9/bin/clang" | ||
runner = "../run-on-adroid.sh" | ||
``` | ||
|
||
### Build | ||
From the project's root directory: | ||
``` | ||
./gradlew assembleDebug | ||
``` | ||
|
||
### Install | ||
|
||
Ensure [adb](https://developer.android.com/studio/command-line/adb) is installed and the emulator or device open. | ||
|
||
From the project's root directory: | ||
``` | ||
adb install ./app/build/outputs/apk/debug/app-debug.apk | ||
``` | ||
|
||
### Run | ||
|
||
Start the app in the emulator / device! | ||
|
||
Alternatively just run the project in Android Studio. This will build, install and run. | ||
|
||
|
||
### Relevant configuration files | ||
|
||
See [rust-ios-android-example](https://github.com/terhechte/rust-ios-android-example) | ||
If you want to add targets or tweak the configuration, you have to edit one or more of these files: | ||
|
||
- [App's Gradle config](app/build.gradle): This contains the apk settings (like application id, sdk version) and build steps. It builds for the provided architectures using cargo and puts the generated shared libraries (.so files) in the expected directories. If you want to build for a new target, add it [here](app/build.gradle#L45). The target's key is the folder name where the shared library will be put according to [this](https://developer.android.com/ndk/guides/abis.html), and the value is the toolchain's name used by rustup. | ||
|
||
#### TODO | ||
- [Cargo config](.cargo/config): Contains linker and runner paths for targets. | ||
|
||
Add complete step-by-step for Android & iOS here! | ||
- [build.rs](build.rs): This is a script invoked by Cargo before everything else. For Android, it's used to tell [rust_swig](https://github.com/Dushistov/rust_swig) to generate the glue Rust files needed for Java interop. If you change the app's package structure / names, you have to update this file accordingly. It also sets the import to use for the `NonNull` annotation ( `use_null_annotation_from_package`). If you're using a recent Android SDK version, you don't need to change it. | ||
|
||
## Contribute | ||
### Updating Rust | ||
|
||
You edited something in Rust! Now you have to: | ||
|
||
- Update [java_glue.rs.in](src/java_glue.rs.in) accordingly. This is a file [rust_swig](https://github.com/Dushistov/rust_swig) uses to generate the JNI glue. Consult [rust_swig](https://github.com/Dushistov/rust_swig) docs for syntax. | ||
|
||
- Build, install, run, as described above. | ||
|
||
### Updating Kotlin/Java | ||
|
||
The code of the Android app can be found [here](app). This is a regular Android app which you can work with normally. Just don't modify the generated JNI files and remember to update [build.rs](build.rs) as described in Relevant configuration files, if you change the package structure. | ||
|
||
# iOS | ||
|
||
### App code | ||
|
||
The code of the iOS app can be found [here](ios_app). | ||
|
||
### Add targets | ||
`rustup target add x86_64-apple-ios` | ||
|
||
### Build & run | ||
From the project's root directory: | ||
``` | ||
cargo build --target=x86_64-apple-ios | ||
``` | ||
This will generate the required library files: <project root directory>/target/mobileapp-ios.h with the C headers and the (static) library for the target, <project root directory>/target/<target name>/libmobcore.a. At the moment you have to copy manually libmobcore.a into the iOS app's directory each time you update it. | ||
|
||
With the header and library in place, you can now run the iOS app. | ||
|
||
### Updating Rust | ||
|
||
You edited something in Rust! Now you have to: | ||
|
||
- Update the [C glue Rust implementation file](src/ios_c_headers.rs). Orient with the existing code. Differently to Android we have to write this glue manually, because there's no library like rust_swig. | ||
|
||
- Build as described in "Build & run". Cargo will invoke build.rs, which uses cbindgen to generate the iOS library files. | ||
|
||
- Copy manually the generated <project root directory>/target/<target name>/libmobcore.a to the iOS app project's root folder. | ||
|
||
- Run! | ||
|
||
### Updating Swift/ObjC | ||
|
||
The code of the iOS app can be found [here](ios_app). This is a regular iOS app which you can work with normally. | ||
|
||
# Contribute | ||
|
||
1. Fork | ||
2. Commit changes to a branch in your fork | ||
3. Push your code and make a pull request | ||
|
||
# Credits | ||
|
||
Based on parts of https://github.com/Dushistov/rust_swig and https://github.com/terhechte/rust-ios-android-example |