Building a mobile app in Rust and React Native, Part 1: Project Setup
The first post in series ‘building a mobile app in Rust and React Native’.
In this series I will describe process of connecting mobile front-end written in React Native with business logic written in Rust.
As an introduction to this article, I suggest reading a great series from John Gallagher: Building an iOS App in Rust, Part 1: Getting Started with Rust
The app we are building is a mobile wallet for ethereum cryptocurrency. It is able create brainwallet accounts, scan qr-codes with unsigned transactions and sign them.
The main reason why I decided to use Rust in this project was that I already had all modules written in it and ready to use (or at least I thought so).
Required tools
node.js
(tested onv7.4.0
)npm
(tested on5.2.0
)rustup
(tested onrustup 1.0.0 (17b6d21 2016-12-15)
)rustc
(tested on1.19.0 (0ade33941 2017–07–17)
)cargo
(tested oncargo 0.20.0 (a60d185c8 2017–07–13)
)android_ndk
(tested onr13b
)Xcode
(only, for iOS, tested onVersion 8.1 (8B62)
)$NDK_HOME
envarionment variable set to ndk home directory (eg./usr/local/opt/android-ndk
)$JAVA_HOME
envarionment variable set to java home directory (eg./Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home
)
Setting up cross compilation
Once all dependencies are installed, lets set them up. We will start with installing all necessary toolchains.
# ios
rustup target add i386-apple-ios
rustup target add x86_64-apple-ios
rustup target add armv7-apple-ios
rustup target add armv7s-apple-ios
rustup target add aarch64-apple-ios# android
rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add i686-linux-android
Now, let’s create a new project.
react-native init our_project
Next, create rust
subdirectory, enter it and run
cargo new our_project
After those steps, the project directory should look like this:
__test__
android
app.json
index.android.js
index.ios.js
ios
node_modules
package.json
rust
/our_project
/Cargo.toml
/src
Next, let’s setup makefile the project and place it inside our_project
dir.
ARCHS_IOS = i386-apple-ios x86_64-apple-ios armv7-apple-ios armv7s-apple-ios aarch64-apple-ios
ARCHS_ANDROID = aarch64-linux-android armv7-linux-androideabi i686-linux-android
LIB=libsigner.aall: ios androidios: $(LIB)android: $(ARCHS_ANDROID)
sh copy_android.sh.PHONY: $(ARCHS_IOS)
$(ARCHS_IOS): %:
cargo build --target $@ --release.PHONY: $(ARCHS_ANDROID)
$(ARCHS_ANDROID): %:
cargo build --target $@ --release$(LIB): $(ARCHS_IOS)
lipo -create -output $@ $(foreach arch,$(ARCHS_IOS),$(wildcard target/$(arch)/release/$(LIB)))
copy_android.sh
is a shell script that copies our statically compiled libraries to jniLibs
directory.
#! /bin/bashmkdir -p ../../android/app/src/main/jniLibs
mkdir -p ../../android/app/src/main/jniLibs/x86
mkdir -p ../../android/app/src/main/jniLibs/arm64-v8a
mkdir -p ../../android/app/src/main/jniLibs/armeabi-v7acp ./target/i686-linux-android/release/libsigner.so ../../android/app/src/main/jniLibs/x86/libsigner.so
cp ./target/aarch64-linux-android/release/libsigner.so ../../android/app/src/main/jniLibs/arm64-v8a/libsigner.so
cp ./target/armv7-linux-androideabi/release/libsigner.so ../../android/app/src/main/jniLibs/armeabi-v7a/libsigner.so
At this point we can already compile static libraries for android and iOS.
*disclosure
If your rust code links C libraries, the compilation will fail. To make it work, we need to set up custom linker. It can be done inside rust/.cargo/config
file. You can use create-ndk-standalone.sh to generate it.
[target.aarch64-linux-android]
ar = "/Users/marek/projects/ethcore/native-signer/NDK/arm64/bin/aarch64-linux-android-ar"
linker = "/Users/marek/projects/ethcore/native-signer/NDK/arm64/bin/aarch64-linux-android-gcc"[target.armv7-linux-androideabi]
ar = "/Users/marek/projects/ethcore/native-signer/NDK/arm/bin/arm-linux-androideabi-ar"
linker = "/Users/marek/projects/ethcore/native-signer/NDK/arm/bin/arm-linux-androideabi-gcc"[target.i686-linux-android]
ar = "/Users/marek/projects/ethcore/native-signer/NDK/x86/bin/i686-linux-android-ar"
linker = "/Users/marek/projects/ethcore/native-signer/NDK/x86/bin/i686-linux-android-gcc"
At this point our project directory should look like like this:
__test__
android
app.json
index.android.js
index.ios.js
ios
node_modules
package.json
rust
/.cargo
/config
/our_project
/Cargo.toml
/copy_android.sh
/Makefile
/src
In next blog post I will cover making calls between Rust and React Native.
Project’s github repo.