Android dengan NDK memiliki dukungan untuk kode C / C ++ dan iOS dengan Objective-C ++ juga memiliki dukungan, jadi bagaimana cara menulis aplikasi dengan kode C / C ++ asli yang dibagikan antara Android dan iOS?
java
c++
java-native-interface
cross-platform
objective-c++
ademar111190
sumber
sumber
Jawaban:
Memperbarui.
Jawaban ini cukup populer bahkan empat tahun setelah saya menulisnya, dalam empat tahun ini banyak hal yang berubah, jadi saya memutuskan untuk memperbarui jawaban saya agar lebih sesuai dengan kenyataan kita saat ini. Ide jawaban tidak berubah; implementasinya sedikit berubah. Bahasa Inggris saya juga telah berubah, telah meningkat pesat, jadi jawabannya lebih dapat dimengerti oleh semua orang sekarang.
Silakan lihat di repo sehingga Anda dapat mengunduh dan menjalankan kode yang akan saya tunjukkan di bawah.
Jawabannya
Sebelum saya menunjukkan kodenya, harap banyak melihat diagram berikut.
Setiap OS memiliki UI dan kekhasannya sendiri, jadi kami bermaksud untuk menulis kode khusus untuk setiap platform dalam hal ini. Di sisi lain, semua kode logika, aturan bisnis, dan hal-hal yang dapat dibagikan kami bermaksud untuk menulis menggunakan C ++, sehingga kami dapat mengkompilasi kode yang sama ke setiap platform.
Dalam diagram, Anda dapat melihat lapisan C ++ di tingkat paling bawah. Semua kode bersama ada di segmen ini. Level tertinggi adalah kode Obj-C / Java / Kotlin biasa, tidak ada berita di sini, bagian yang paling sulit adalah lapisan tengah.
Lapisan tengah ke sisi iOS sederhana; Anda hanya perlu mengonfigurasi proyek Anda untuk membangun menggunakan varian Obj-c yang dikenal sebagai Objective-C ++ dan itu saja, Anda memiliki akses ke kode C ++.
Hal menjadi lebih sulit di sisi Android, kedua bahasa, Java dan Kotlin, di Android, dijalankan di bawah Mesin Virtual Java. Jadi satu-satunya cara untuk mengakses kode C ++ menggunakan JNI , harap luangkan waktu untuk membaca dasar-dasar JNI. Untungnya, Android Studio IDE saat ini memiliki peningkatan besar di sisi JNI, dan banyak masalah ditampilkan kepada Anda saat Anda mengedit kode.
Kode demi langkah
Sampel kami adalah aplikasi sederhana yang Anda kirimi teks ke CPP, dan itu mengubah teks itu menjadi sesuatu yang lain dan mengembalikannya. Idenya adalah, iOS akan mengirim "Obj-C" dan Android akan mengirim "Java" dari bahasa masing-masing, dan kode CPP akan membuat teks sebagai berikut "cpp mengatakan halo ke << teks diterima >> ".
Kode CPP bersama
Pertama-tama, kita akan membuat kode CPP bersama, melakukannya kita memiliki file header sederhana dengan deklarasi metode yang menerima teks yang diinginkan:
Dan implementasi CPP:
Unix
Bonus yang menarik adalah, kita juga bisa menggunakan kode yang sama untuk Linux dan Mac serta sistem Unix lainnya. Kemungkinan ini sangat berguna karena kita dapat menguji kode bersama kita lebih cepat, jadi kita akan membuat Main.cpp sebagai berikut untuk mengeksekusinya dari mesin kita dan melihat apakah kode bersama berfungsi.
Untuk membuat kode, Anda perlu menjalankan:
iOS
Saatnya menerapkan di sisi seluler. Sejauh iOS memiliki integrasi sederhana, kami mulai dengannya. Aplikasi iOS kami adalah aplikasi Obj-c biasa dengan hanya satu perbedaan; file adalah
.mm
dan bukan.m
. yaitu Ini adalah aplikasi Obj-C ++, bukan aplikasi Obj-C.Untuk organisasi yang lebih baik, kami membuat CoreWrapper.mm sebagai berikut:
Kelas ini memiliki tanggung jawab untuk mengubah jenis CPP dan panggilan ke jenis dan panggilan Obj-C. Ini tidak wajib setelah Anda dapat memanggil kode CPP pada file apa pun yang Anda inginkan di Obj-C, tetapi ini membantu untuk menjaga organisasi, dan di luar file pembungkus Anda, Anda mempertahankan kode gaya Obj-C lengkap, hanya file pembungkus menjadi gaya CPP .
Setelah pembungkus Anda terhubung ke kode CPP, Anda dapat menggunakannya sebagai kode Obj-C standar, misalnya ViewController "
Lihat tampilan aplikasi:
Android
Sekarang saatnya integrasi Android. Android menggunakan Gradle sebagai sistem build, dan untuk kode C / C ++ menggunakan CMake. Jadi, hal pertama yang perlu kita lakukan adalah mengkonfigurasi CMake pada file gradle:
Dan langkah kedua adalah menambahkan file CMakeLists.txt:
File CMake adalah tempat Anda perlu menambahkan file CPP dan folder header yang akan Anda gunakan pada proyek, pada contoh kami, kami menambahkan
CPP
folder dan file Core.h / .cpp. Untuk mengetahui lebih lanjut tentang konfigurasi C / C ++, silakan baca.Sekarang kode inti adalah bagian dari aplikasi kita sekarang saatnya untuk membuat jembatan, untuk membuat semuanya lebih sederhana dan teratur kita membuat kelas khusus bernama CoreWrapper untuk menjadi pembungkus antara JVM dan CPP:
Perhatikan bahwa kelas ini memiliki
native
metode dan memuat pustaka asli bernamanative-lib
. Library ini adalah yang kita buat, pada akhirnya, kode CPP akan menjadi objek bersama yang.so
disematkan File di APK kita, danloadLibrary
akan memuatnya. Terakhir, saat Anda memanggil metode native, JVM akan mendelegasikan panggilan tersebut ke library yang dimuat.Sekarang bagian paling aneh dari integrasi Android adalah JNI; Kami membutuhkan file cpp sebagai berikut, dalam kasus kami "native-lib.cpp":
Hal pertama yang akan Anda perhatikan adalah
extern "C"
bagian ini diperlukan agar JNI berfungsi dengan benar dengan kode CPP dan tautan metode kami. Anda juga akan melihat beberapa simbol yang digunakan JNI untuk bekerja dengan JVM sebagaiJNIEXPORT
danJNICALL
. Untuk Anda memahami arti dari hal-hal tersebut, perlu meluangkan waktu dan membacanya , untuk keperluan tutorial ini anggap saja hal-hal tersebut sebagai boilerplate.Satu hal penting dan biasanya akar dari banyak masalah adalah nama metode; itu harus mengikuti pola "Java_package_class_method". Saat ini, Android studio memiliki dukungan yang sangat baik untuk itu sehingga dapat menghasilkan boilerplate ini secara otomatis dan menunjukkan kepada Anda kapan itu benar atau tidak dinamai. Pada contoh kami, metode kami bernama "Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString" itu karena "ademar.androidioscppexample" adalah paket kami, jadi kami mengganti "." oleh "_", CoreWrapper adalah kelas tempat kita menghubungkan metode asli dan "concatenateMyStringWithCppString" adalah nama metode itu sendiri.
Karena kami memiliki metode yang dinyatakan dengan benar, inilah saatnya untuk menganalisis argumen, parameter pertama adalah penunjuknya
JNIEnv
adalah cara kami memiliki akses ke hal-hal JNI, sangat penting untuk kami membuat konversi seperti yang akan Anda lihat segera. Yang kedua adalahjobject
instance dari objek yang Anda gunakan untuk memanggil metode ini. Anda dapat menganggapnya sebagai java " ini ", pada contoh kami, kami tidak perlu menggunakannya, tetapi kami masih perlu mendeklarasikannya. Setelah proyek ini, kita akan menerima argumen metode tersebut. Karena metode kami hanya memiliki satu argumen - String "myString", kami hanya memiliki "jstring" dengan nama yang sama. Juga perhatikan bahwa tipe kembalian kita juga jstring. Itu karena metode Java kami mengembalikan String, untuk informasi lebih lanjut tentang jenis Java / JNI silakan baca.Langkah terakhir adalah mengonversi jenis JNI menjadi jenis yang kami gunakan di sisi CPP. Pada contoh kami, kami mengubah
jstring
menjadiconst char *
pengiriman itu diubah menjadi CPP, mendapatkan hasilnya dan mengubahnya kembali kejstring
. Seperti semua langkah lainnya di JNI, ini tidak sulit; itu hanya boilerplated, semua pekerjaan dilakukan olehJNIEnv*
argumen yang kita terima ketika kita memanggilGetStringUTFChars
danNewStringUTF
. Setelah kode kita siap dijalankan di perangkat Android, mari kita lihat.sumber
Pendekatan yang dijelaskan dalam jawaban luar biasa di atas dapat sepenuhnya diotomatiskan oleh Scapix Language Bridge yang menghasilkan kode pembungkus dengan cepat langsung dari header C ++. Berikut ini contohnya :
Tentukan kelas Anda di C ++:
Dan sebut saja dari Swift:
Dan dari Jawa:
sumber