summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcos <cos>2020-03-22 19:08:12 +0100
committercos <cos>2020-03-22 19:08:12 +0100
commit5151e6766f3686a8bef475fc90aee794274ab3c9 (patch)
tree21a6abfdce2ac6035a397a3e356e39485ca4df76
downloadhello_rust_example-android-master.zip
Initial (and likely only) commitHEADmaster
-rw-r--r--Cargo.toml7
-rw-r--r--FFI.java10
-rw-r--r--MainActivity.java22
-rw-r--r--README9
-rw-r--r--activity_main.xml13
-rw-r--r--build_apk.sh20
-rw-r--r--build_java.sh14
-rwxr-xr-xbuild_ndk.sh8
-rw-r--r--build_rust.sh11
-rwxr-xr-xcargo.config7
-rwxr-xr-xinstall_rust.sh4
-rw-r--r--lib.rs-part013
-rw-r--r--lib.rs-part121
-rw-r--r--strings.xml5
14 files changed, 164 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..346a751
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,7 @@
+[...]
+
+[target.'cfg(target_os="android")'.dependencies]
+jni = { version = "0.5", default-features = false }
+
+[lib]
+crate-type = ["dylib"]
diff --git a/FFI.java b/FFI.java
new file mode 100644
index 0000000..8104b2f
--- /dev/null
+++ b/FFI.java
@@ -0,0 +1,10 @@
+package rs.cph.hellorust;
+
+public class FFI {
+
+ private static native String func(final String pattern);
+
+ public String runFunc(String to) {
+ return func(to);
+ }
+}
diff --git a/MainActivity.java b/MainActivity.java
new file mode 100644
index 0000000..5ffaa29
--- /dev/null
+++ b/MainActivity.java
@@ -0,0 +1,22 @@
+package rs.cph.hellorust;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class MainActivity extends Activity {
+
+ static {
+ System.loadLibrary("rustcode");
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FFI rustcode = new FFI();
+ String s = rustcode.runFunc("Sundkaj 7");
+ ((TextView)findViewById(R.id.greetingField)).setText(s);
+ }
+}
diff --git a/README b/README
new file mode 100644
index 0000000..fb8b67a
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+Files illustrating a minimal example of how to link Rust code from an android
+java application. The pieces should be possible to puzzle together into a hello
+world like example.
+
+These go together with the slides published at:
+https://blag.netizen.se/posts/2020-03-22-rust-on-android.html
+
+As is told on above mentioned blog post, this is the material from a short
+presentation I held a year ago on linking to Rust code from java on android.
diff --git a/activity_main.xml b/activity_main.xml
new file mode 100644
index 0000000..5bbe817
--- /dev/null
+++ b/activity_main.xml
@@ -0,0 +1,13 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="@string/hello_msg"
+ tools:context=".MainActivity" />
+</RelativeLayout>
diff --git a/build_apk.sh b/build_apk.sh
new file mode 100644
index 0000000..ce9707a
--- /dev/null
+++ b/build_apk.sh
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+
+ANDROID_PATH="/usr/lib/android-sdk/"
+BUILD_TOOLS="24.0.2"
+AAPT="${ANDROID_PATH}/build-tools/${BUILD_TOOLS}/aapt"
+DX="${ANDROID_PATH}/build-tools/${BUILD_TOOLS}/dx"
+ZIPALIGN="${ANDROID_PATH}/build-tools/${BUILD_TOOLS}/zipalign"
+APKSIGNER="/usr/bin/apksigner"
+PLATFORM="${ANDROID_PATH}/platforms/android-24/android.jar"
+
+echo "Translating in Dalvik bytecode..."
+$DX --dex --output=classes.dex obj
+
+echo "Making APK..."
+$AAPT package -f -m -F bin/hello.unaligned.apk -M AndroidManifest.xml -S res -I $PLATFORM
+$AAPT add bin/hello.unaligned.apk classes.dex lib/armeabi/librustcode.so
+
+echo "Aligning and signing APK..."
+$APKSIGNER sign --ks ~/.android/keys/release-key.keystore bin/hello.unaligned.apk
+$ZIPALIGN -f 4 bin/hello.unaligned.apk bin/hello.apk
diff --git a/build_java.sh b/build_java.sh
new file mode 100644
index 0000000..6fa5a4a
--- /dev/null
+++ b/build_java.sh
@@ -0,0 +1,14 @@
+#!/bin/sh -e
+
+ANDROID_PATH="/usr/lib/android-sdk/"
+BUILD_TOOLS="24.0.2"
+AAPT="${ANDROID_PATH}/build-tools/${BUILD_TOOLS}/aapt"
+PLATFORM="${ANDROID_PATH}/platforms/android-24/android.jar"
+JAVAOPTS="-d obj -classpath src -bootclasspath $PLATFORM -source 1.7 -target 1.7"
+
+echo "Generating R.java file..."
+$AAPT package -f -m -J src -M AndroidManifest.xml -S res -I $PLATFORM
+
+echo "Compiling..."
+javac $JAVAOPTS src/rs/cph/hellorust/MainActivity.java
+javac $JAVAOPTS src/rs/cph/hellorust/R.java
diff --git a/build_ndk.sh b/build_ndk.sh
new file mode 100755
index 0000000..694f466
--- /dev/null
+++ b/build_ndk.sh
@@ -0,0 +1,8 @@
+mkdir NDK
+NDK_HOME="/usr/lib/android-ndk/"
+API_LEVEL=24
+for ARCH in arm64 arm x86
+do
+ ${NDK_HOME}/build/tools/make_standalone_toolchain.py \
+ --api ${API_LEVEL} --arch ${ARCH} --install-dir NDK/${ARCH}
+done
diff --git a/build_rust.sh b/build_rust.sh
new file mode 100644
index 0000000..36cf2a8
--- /dev/null
+++ b/build_rust.sh
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+for TARGET in aarch64-linux-android armv7-linux-androideabi
+do
+ echo "Building rust lib for ${TARGET}"
+ (cd rustcode; cargo build --target ${TARGET} --release)
+done
+
+ln -s "`pwd`"/rustcode/target/aarch64-linux-android/release/librustcode.so jniLibs/arm64/
+ln -s "`pwd`"/rustcode/target/armv7-linux-androideabi/release/librustcode.so jniLibs/armeabi/
+ln -s "`pwd`"/rustcode/target/i686-linux-android/release/librustcode.so jniLibs/x86/
diff --git a/cargo.config b/cargo.config
new file mode 100755
index 0000000..5f09fe7
--- /dev/null
+++ b/cargo.config
@@ -0,0 +1,7 @@
+[target.armv7-linux-androideabi]
+ar = "`pwd`/NDK/arm/bin/arm-linux-androideabi-ar"
+linker = "`pwd`/NDK/arm/bin/arm-linux-androideabi-clang"
+
+[target.aarch64-linux-android ...]
+
+[target.i686-linux-android ...]
diff --git a/install_rust.sh b/install_rust.sh
new file mode 100755
index 0000000..69acd4f
--- /dev/null
+++ b/install_rust.sh
@@ -0,0 +1,4 @@
+for TARGET in aarch64-linux-android armv7-linux-androideabi i686-linux-android
+do
+ rustup target add ${TARGET}
+done
diff --git a/lib.rs-part0 b/lib.rs-part0
new file mode 100644
index 0000000..d2578cd
--- /dev/null
+++ b/lib.rs-part0
@@ -0,0 +1,13 @@
+use std::os::raw::{c_char};
+use std::ffi::{CString, CStr};
+
+#[no_mangle]
+pub extern fn rust_func(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()
+}
diff --git a/lib.rs-part1 b/lib.rs-part1
new file mode 100644
index 0000000..cec0883
--- /dev/null
+++ b/lib.rs-part1
@@ -0,0 +1,21 @@
+#[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_rs_cph_hellorust_FFI_func(env: JNIEnv, _: JClass, java_pattern: JString)
+ -> jstring {
+ let world = rust_func(env.get_string(java_pattern).expect("invalid pattern string").as_ptr());
+ // Retake pointer, to 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()
+ }
+}
diff --git a/strings.xml b/strings.xml
new file mode 100644
index 0000000..1fa2c41
--- /dev/null
+++ b/strings.xml
@@ -0,0 +1,5 @@
+<resources>
+ <string name="app_name">Hello Rust</string>
+ <string name="hello_msg">Hello Rust!</string>
+ <string name="title_activity_main">MainActivity</string>
+</resources>