Dalam membuat aplikasi Mobile tentu menggunakan teknologi Native dari masing-masing platform seperti SwiftUI untuk iOS dan Jetpack Compose untuk Android adalah pilihan terbaik dalam segi performa dan User Experience (UX).
Namun, kita juga tahu bahwa dalam membangun aplikasi Mobile, kita tidak hanya membuat User Interface (UI) saja, ada banyak sekali hal lain yang perlu kita buat, seperti network call, caching, image processing, dll. Yang mana itu sebetulnya tidak platform specific seperti UI, sehingga kita bisa mengurangi redundansi penulisan kode untuk bagian-bagian tersebut dengan cara hanya menulis 1 kali saja, kemudian kita akan pakai di kedua platform!
Ada beberapa cara Sharing Code yang bisa kita pilih, mungkin menggunakan Kotlin Multi Platform (KMP), mungkin menggunakan C++, atau menggunakan bahasa pemrograman Rust yang akan kita gunakan dalam tutorial ini.
Berikut adalah beberapa alasan mengapa Rust mungkin cocok digunakan dalam Sharing Code pada aplikasi Mobile:
Rust dikenal sebagai bahasa yang memiliki performa sangat tinggi, bahkan bisa mendekati C/C++. Hal ini bisa didapatkan dari Zero-Cost Abstraction (abstraksi yang tidak berdampak ke performa pada runtime) yang ada pada Rust dan juga memory management yang tidak menggunakan Garbage Collector.
Karena performanya yang sangat oke, ada beberapa perusahaan besar yang mulai mengadopsi Rust, contohnya seperti Discord (dari Go ke Rust), Figma (dari Typescript ke Rust), dll
Memory Safety artinya program kita akan terbebas dari bugs yang berhubungan dengan memory management, seperti memory leaks (memory tidak pernah di-deallocate), mengakses null pointer, melakukan double free, dll.
Nah, di Rust, masalah-masalah tersebut akan terdeteksi lebih awal pada saat program kita dicompile.
Karena alasan memory safety inilah Linux & Windows mulai mengadopsi Rust dalam kernel OS-nya. Bahkan departemen pertahanan AS (DARPA) mulai rewrite program yang mereka tulis menggunakan C ke Rust.
Ada beberapa fitur pada Rust yang dapat meningkatkan produktivitas kita sebagai Developer, misalnya Macros untuk code generator, Auto Completion, Auto Formatter, dll.
Jika program kita ada error, error message nya pun sangat useful. bahkan kadang compilernya memberikan suggestion untuk memperbaiki error tersebut.
Selain itu, ada ratusan ribu crates (library) di crates.io yang dapat kita gunakan sehingga proses development menjadi lebih cepat.
Sejak beberapa tahun lalu, Android sudah mendukung Rust sebagai bahasa pemrograman untuk membangun native OS components mereka. (https://source.android.com/docs/setup/build/rust/building-rust-modules/overview)
Untuk mengikuti tutorial ini, pastikan kamu sudah menginstall:
Rust
Xcode
Android Studio
Sekarang, kita akan mulai membuat projectnya, kita akan membuat library Rust yang memiliki function get_message dan library tersebut akan kita gunakan di iOS dan Android.
Silakan buat folder baru bernama "greeting-demo"
1mkdir greeting-demo2cd greeting-demo
Untuk membuat library Rust, jalankan command:
1cargo new greeting --lib
Kemudian tambahkan crate uniffi ke library kita:
Cargo.toml1[lib]2crate_type = ["cdylib", "staticlib"]3name = "greeting"45[dependencies]6uniffi = { version = "0.28.1", features = ["cli"] }
Setelah itu tambahkan function get_message pada file "lib.rs":
lib.rs1uniffi::setup_scaffolding!();23#[uniffi::export]4fn get_message() -> String {5 String::from("Hello from Rust! 🦀")6}
Terakhir, buat file "uniffi-bindgen.rs" di dalam folder "bin", yang berisi:
uniffi-bindgen.rs1fn main() {2 uniffi::uniffi_bindgen_main()3}
Jika kita build, maka akan muncul sebuah dynamic library bernama "libgreeting.dylib" pada folder "target/debug" yang akan kita pakai pada step berikutnya.
1cargo build
Silakan buka Xcode dan buat project SwiftUI baru bernama "GreetingIOS" pada folder "greeting".
Pertama, kita akan generate binding terlebih dahulu agar kita bisa memanggil library rust di swift.
1cargo run --bin uniffi-bindgen generate --library ./target/debug/libgreeting.dylib --language swift --out-dir ./bindings
Command di atas akan menghasilkan folder "bindings" di project rust kita yang berisi binding rust untuk swift.
Lalu pindahkan file "greeting.swift" ke folder "ios" dan rename menjadi "Greeting.swift"
1mv ./bindings/greeting.swift ./ios/Greeting.swift
Kemudian tambahkan beberapa target berikut ke Rust:
1rustup target add aarch64-apple-ios-sim aarch64-apple-ios
Jalankan command berikut untuk build library iOS:
1cargo build --release --target=aarch64-apple-ios-sim2cargo build --release --target=aarch64-apple-ios
Command di atas akan menghasilkan 2 file binary bernama "target/aarch64-apple-ios-sim/release/libgreeting.a" dan "target/aarch64-apple-ios/release/libgreeting.a".
XCFramework memungkinkan kita untuk mengimport library iOS dengan lebih mudah. Jadi, kita akan membuat file .xcframework dari 2 file binary di atas.
Pertama, kita ubah rename dulu "bindings/greetingFFI.modulemap" menjadi "bindings/module.modulemap" agar Xcode dapat menemukan module kita.
Kemudian, buat file .xcframework:
1xcodebuild -create-xcframework \2 -library ./target/aarch64-apple-ios-sim/release/libgreeting.a -headers ./bindings \3 -library ./target/aarch64-apple-ios/release/libgreeting.a -headers ./bindings \4 -output "ios/Greeting.xcframework"
Silakan drag & drop file "Greeting.xcframework" dan file "Greeting.swift" ke project iOS kita.
Sekarang, kita sudah bisa memanggil function getMessage dari Rust di Swift.
Penamaan function akan disesuaikan secara otomatis sesuai konvensi dari masing-masing bahasa oleh binding yang telah kita buat di awal. Misalnya dalam hal ini get_message di Rust akan menjadi getMessage di Swift.
ContentView.swift1import SwiftUI23struct ContentView: View {4 var body: some View {5 VStack {7 Text(getMessage())8 }9 .padding()10 }11}1213#Preview {14 ContentView()15}
Agar tiap kali ada perubahan di library Rust-nya kita tidak perlu menjalankan command satu per-satu, lebih baik kita membuat script automasi untuk pembuatan XCFramework.
Buat file baru bernama "build_ios.sh" yang berisi:
build ios.sh1#!/bin/bash23# Build the dylib4cargo build56# Generate bindings7cargo run --bin uniffi-bindgen generate --library ./target/debug/libgreeting.dylib --language swift --out-dir ./bindings89# Add the iOS targets and build10for TARGET in \11 aarch64-apple-darwin \12 aarch64-apple-ios \13 aarch64-apple-ios-sim \14 x86_64-apple-darwin \15 x86_64-apple-ios; do16 rustup target add $TARGET17 cargo build --release --target=$TARGET18done1920# Rename *.modulemap to module.modulemap21mv ./bindings/greetingFFI.modulemap ./bindings/module.modulemap2223# Move the Swift file to the project24rm ./ios/Greeting.swift25mv ./bindings/greeting.swift ./ios/Greeting.swift2627# Recreate XCFramework28rm -rf "ios/Greeting.xcframework"29xcodebuild -create-xcframework \30 -library ./target/aarch64-apple-ios-sim/release/libgreeting.a -headers ./bindings \31 -library ./target/aarch64-apple-ios/release/libgreeting.a -headers ./bindings \32 -output "ios/Greeting.xcframework"3334# Cleanup35rm -rf bindings
1chmod +x build_ios.sh2./build_ios.sh
Silakan buka Android Studio, dan buat project baru bernama "GreetingAndroid"
Di Android, kita membutuhkan NDK (Native Development Kit) untuk menggunakan library yang ditulis menggunakan bahasa native seperti C, C++ dan Rust.
Silakan klik Tools -> SDK Manager -> SDK Tools kemudian "Check (NDK Side by Side)"
Setelah itu pindah ke project Rust, dan jalankan command berikut:
1cargo install cargo-ndk
Dan tambahkan beberapa target berikut ke Rust:
1rustup target add \2 aarch64-linux-android \3 armv7-linux-androideabi \4 i686-linux-android \5 x86_64-linux-android
Jalankan command berikut untuk membuat library Android:
1cargo ndk -o ../GreetingAndroid/app/src/main/jniLibs \2 --manifest-path ./Cargo.toml \3 -t armeabi-v7a \4 -t arm64-v8a \5 -t x86 \6 -t x86_64 \7 build --release
Kemudian kita perlu generate Binding Rust ke Kotlin menggunakan command berikut:
1cargo run --bin uniffi-bindgen generate --library ./target/debug/libgreeting.dylib --language kotlin --out-dir ../GreetingAndroid/app/src/main/java/dev/alfin/greetingandroid
Pertama, kita perlu menambahkan 2 dependencies berikut di file "build.gradle.kts"
1dependencies {2 // ...3 // UniFFI4 implementation("net.java.dev.jna:jna:5.7.0@aar")5 implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")6}
Sekarang, kita sudah bisa memanggil function getMessage dari Rust di Kotlin.
MainActivity.kt1import uniffi.greeting.getMessage23class MainActivity : ComponentActivity() {4 override fun onCreate(savedInstanceState: Bundle?) {5 super.onCreate(savedInstanceState)6 enableEdgeToEdge()7 setContent {8 GreetingAndroidTheme {9 Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->10 Column(11 verticalArrangement = Arrangement.Center,12 horizontalAlignment = Alignment.CenterHorizontally,13 modifier = Modifier.fillMaxSize().padding(innerPadding)14 ) {15 Text(17 text = getMessage()18 )19 }20 }21 }22 }23 }24}
Agar tiap kali ada perubahan di library Rust-nya kita tidak perlu menjalankan command satu per-satu, lebih baik kita membuat script automasi untuk pembuatan Library Android.
Buat file baru bernama "build_android.sh" yang berisi:
build android.sh1#!/bin/bash23# Set up cargo-ndk and add the Android targets4cargo install cargo-ndk5rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android67# Build the dylib8cargo build910# Build the Android libraries in jniLibs11cargo ndk -o ../GreetingAndroid/app/src/main/jniLibs \12 --manifest-path ./Cargo.toml \13 -t armeabi-v7a \14 -t arm64-v8a \15 -t x86 \16 -t x86_64 \17 build --release1819# Create Kotlin bindings20cargo run --bin uniffi-bindgen generate --library ./target/debug/libgreeting.dylib --language kotlin --out-dir ../GreetingAndroid/app/src/main/java/dev/alfin/greetingandroid
1chmod +x build_android.sh2./build_android.sh
Sekarang, kita telah belajar bagaimana cara membuat sebuah library di Rust yang bisa digunakan di platform iOS dan Android. Selanjutnya mungkin kamu bisa kembangkan lagi library-nya agar bisa digunakan juga di Web atau di Desktop.
Oke mungkin itu saja yang bisa saya bagikan kali ini, kalau kamu merasa artikel ini bermanfaat silakan Like & Share artikel ini ke teman-teman kamu atau jika kamu punya pertanyaan, tulis aja di kolom komentar, Thank you! 😁 🙏
Source code lengkap dari tutorial ini bisa kalian akses di sini: https://github.com/alfinsyahruddin/greeting-demo
Always open to new ideas. 🕊️
Articles that you might want to read.
Otomatisasi build, testing, screenshot, dan deployment aplikasi iOS ke Testflight & AppStore.
Tutorial multilingual menggunakan react-i18next
Buat aplikasi AI pertama-mu dalam 10 menit ⚡️