Mesin game Corona memungkinkan Anda membuat aplikasi dan game lintas platform. Namun terkadang API yang mereka berikan tidak cukup. Untuk kasus seperti itu, ada Corona Native , yang memungkinkan Anda untuk memperluas fungsionalitas menggunakan kode asli untuk setiap platform.
Artikel ini akan membahas penggunaan Java dalam proyek Corona untuk android
Untuk memahami apa yang terjadi di artikel, Anda memerlukan pengetahuan dasar tentang Java, Lua dan mesin Corona
Memulai
Corona dan Android Studio harus diinstal di komputer
Folder instalasi Corona juga berisi templat proyek: Native \ Project Template \ App. Salin seluruh folder dan ganti namanya menjadi nama proyek Anda.
Kustomisasi template
Catatan: Saya menggunakan bangunan publik terbaru yang tersedia untuk Corona - 2017.3184 . Dalam versi baru, templat dapat berubah, dan beberapa persiapan dari bab ini tidak lagi diperlukan.
Untuk android kita membutuhkan 2 folder di dalamnya: Corona dan android
Dari folder Corona , hapus Images.xcassets dan LaunchScreen.storyboardc - kita tidak memerlukan folder ini. Di file main.lua , kami juga menghapus semua kode - kami akan mulai membuat proyek dari awal. Jika Anda ingin menggunakan proyek yang sudah ada, maka ganti semua file di folder Corona dengan milik Anda
Folder android adalah proyek yang selesai untuk Android Studio, kita harus membukanya. Pesan pertama dari studio adalah "Sinkronisasi tingkat gagal". Perlu untuk memperbaiki build.gradle:

Untuk memperbaiki situasi, tambahkan tautan ke repositori di buildscript. Saya juga mengubah versi di classpath 'com.android.tools.build:gradle' menjadi yang lebih baru.
Kode build.gradle// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.1.3' } repositories { jcenter() google() } } allprojects { repositories { jcenter() google() } } task clean(type: Delete) { delete rootProject.buildDir }
Langkah selanjutnya adalah mengubah gradle-wrapper.properties . Anda dapat mengubahnya secara manual dengan mengganti versi gradle di distributionUrl . Atau biarkan studio melakukan segalanya untuk Anda.

Selain itu, Anda perlu memperbaiki build.gradle untuk modul aplikasi: di cleanAssets Anda perlu menambahkan baris hapus "$ projectDir / build / intermediates / jniLibs" , yang tanpanya Anda harus melakukan proyek bersih sebelum setiap permulaan ( diambil dari sini )
Sekarang sinkronisasi berhasil, hanya ada beberapa peringatan yang terkait dengan buildToolsVersion usang dan sintaks lama dalam konfigurasi. Memperbaiki mereka tidak sulit.
Sekarang di studio kita melihat 2 modul: aplikasi dan plugin. Ganti nama aplikasi (com.mycompany.app) dan plugin (plugin.library) sebelum melanjutkan.
Lebih lanjut dalam kode, plugin akan disebut plugin.habrExamplePlugin
Plugin ini berisi kelas LuaLoader secara default - itu akan bertanggung jawab untuk menangani panggilan dari kode lua. Sudah ada beberapa kode, tapi mari kita bersihkan.
Kode LuaLoader package plugin.habrExamplePlugin; import com.naef.jnlua.JavaFunction; import com.naef.jnlua.LuaState; @SuppressWarnings({"WeakerAccess", "unused"}) public class LuaLoader implements JavaFunction { @Override public int invoke(LuaState luaState) { return 0; } }
Menggunakan kode plugin dari kode lua
Corona Native menggunakan jnlua untuk mengikat kode java dan lua. LuaLoader mengimplementasikan antarmuka jnlua.JavaFunction, sehingga metode yang dipanggil tersedia dari kode lua. Untuk memastikan semuanya beres, tambahkan kode logging ke LuaLoader.invoke dan buat plugin yang membutuhkan di main.lua
@Override public int invoke(LuaState luaState) { Log.d("Corona native", "Lua Loader invoke called"); return 0; }
local habrPlugin = require("plugin.habrExamplePlugin") print("test:", habrPlugin)
Setelah meluncurkan aplikasi, di antara log kita akan melihat 2 baris berikut:
D / Corona asli: Lua Loader memanggil dipanggil
I / Corona: tes benar
Jadi, aplikasi kami mengunduh plugin, dan meminta pengembalian yang benar. Sekarang mari kita coba mengembalikan tabel lua dengan fungsi dari kode Java.
Untuk menambahkan fungsi ke modul, kita menggunakan antarmuka jnlua.NamedJavaFunction. Contoh fungsi sederhana tanpa argumen dan tanpa nilai balik:
class HelloHabrFunction implements NamedJavaFunction { @Override public String getName() { return "helloHabr"; } @Override public int invoke(LuaState L) { Log.d("Corona native", "Hello Habr!"); return 0; } }
Untuk mendaftarkan fungsi baru kami di lua, kami menggunakan metode LuaState.register:
public class LuaLoader implements JavaFunction { @Override public int invoke(LuaState luaState) { Log.d("Corona native", "Lua Loader invoke called"); String libName = luaState.toString(1);
Kode ini membutuhkan penjelasan tambahan:
LuaState, parameter dari metode invoke, pada dasarnya mewakili pembungkus atas mesin virtual Lua (tolong perbaiki saya jika saya salah menuliskannya). Bagi mereka yang terbiasa menggunakan kode lua dari C, LuaState sama dengan pointer lua_State di C.
Bagi mereka yang ingin mempelajari hutan bekerja dengan lua, saya sarankan membaca manual, dimulai dengan Program Aplikasi Antarmuka
Jadi, ketika dipanggil, kita mendapatkan LuaState. Ini memiliki tumpukan yang berisi parameter yang diteruskan ke fungsi kami dari kode lua. Dalam hal ini, ini adalah nama modul, karena LuaLoader dijalankan ketika panggilan membutuhkan ("plugin.habrExamplePlugin").
Angka yang dikembalikan oleh invoke menunjukkan jumlah variabel dari tumpukan yang akan dikembalikan ke kode lua. Jika diperlukan, angka ini tidak berpengaruh, tetapi kami akan menggunakan pengetahuan ini nanti dengan membuat fungsi yang mengembalikan beberapa nilai
Menambahkan bidang ke modul
Selain fungsi, kami juga dapat menambahkan bidang tambahan ke modul, misalnya versi:
luaState.register(libName, luaFunctions);
Dalam hal ini, kami menggunakan indeks -2 untuk menunjukkan bahwa bidang perlu diatur untuk modul kami. Indeks negatif berarti bahwa penghitungan dimulai pada akhir tumpukan. -1 akan menunjuk ke string "0.1.2" (dalam lua, indeks dimulai dengan satu).
Agar tidak menyumbat tumpukan, setelah mengatur bidang, saya sarankan memanggil luaState.pop (1) - melempar 1 elemen dari tumpukan.
Kode LuaLoader lengkap @SuppressWarnings({"WeakerAccess", "unused"}) public class LuaLoader implements JavaFunction { @Override public int invoke(LuaState luaState) { Log.d("Corona native", "Lua Loader invoke called"); String libName = luaState.toString(1); // ( require) NamedJavaFunction[] luaFunctions = new NamedJavaFunction[]{ new HelloHabrFunction(), // }; luaState.register(libName, luaFunctions); // , luaState.register(libName, luaFunctions); // , luaState.pushString("0.1.2"); // luaState.setField(-2, "version"); // version . // 1 lua . // require , require return 0; } }
Contoh Fungsi
Contoh fungsi yang mengambil banyak string dan menggabungkannya melalui pembangun StringImplementasi:
class StringJoinFunction implements NamedJavaFunction{ @Override public String getName() { return "stringJoin"; } @Override public int invoke(LuaState luaState) { int currentStackIndex = 1; StringBuilder stringBuilder = new StringBuilder(); while (!luaState.isNone(currentStackIndex)){ String str = luaState.toString(currentStackIndex); if (str != null){
Penggunaan dalam lua:
local joinedString = habrPlugin.stringJoin("this", " ", "was", " ", "concated", " ", "by", " ", "Java", "!", " ", "some", " ", "number", " : ", 42); print(joinedString)
Contoh mengembalikan beberapa nilaikelas SumFunction mengimplementasikan NamedJavaFunction {
Timpa
public String getName () {
kembalikan "jumlah";
}
@Override public int invoke(LuaState luaState) { if (!luaState.isNumber(1) || !luaState.isNumber(2)){ luaState.pushNil(); luaState.pushString("Arguments should be numbers!"); return 2; } int firstNumber = luaState.toInteger(1); int secondNumber = luaState.toInteger(1); luaState.pushInteger(firstNumber + secondNumber); return 1; }
}
Java Reflection - menggunakan kelas Java langsung di lua
Perpustakaan jnlua memiliki kelas JavaReflector khusus yang bertanggung jawab untuk membuat tabel lua dari objek java. Dengan demikian, Anda dapat menulis kelas dalam java dan memberikannya ke kode lua untuk digunakan di masa depan.
Untuk melakukan ini cukup sederhana:
Contoh kelas
@SuppressWarnings({"unused"}) public class Calculator { public int sum(int number1, int number2){ return number1 + number2; } public static int someStaticMethod(){ return 4; } }
Menambahkan instance kelas ini ke modul kami
luaState.pushJavaObject(new Calculator()); luaState.setField(-2, "calc"); luaState.pop(1);
Penggunaan di Lua:
local calc = habrPlugin.calc print("call method of java object", calc:sum(3,4)) print("call static method of java object", calc:getClass():someStaticMethod())
Perhatikan titik dua dalam panggilan metode kelas. Untuk metode statis, Anda juga harus menggunakan titik dua.
Kemudian saya perhatikan fitur reflektor yang menarik: jika kita hanya mengirimkan instance kelas ke lua, maka memanggil metode statisnya dimungkinkan melalui getClass (). Tetapi setelah panggilan melalui getClass (), panggilan selanjutnya akan dipicu pada objek itu sendiri:
print("call method of java object", calc:sum(3,4))
Selain itu, menggunakan getClass (), kita dapat membuat objek baru secara langsung di lua:
local newInstance = calc:getClass():new()
Sayangnya, saya tidak dapat menyimpan Calculator.class di bidang modul karena "java.lang.IllegalArgumentException: tipe ilegal" di dalam setField .
Membuat dan memanggil fungsi lua dengan cepat
Bagian ini muncul karena mahkota tidak menyediakan kemampuan untuk mengakses fungsi dari apinya secara langsung di Jawa. Tapi jnlua.LuaState memungkinkan Anda memuat dan mengeksekusi kode lua yang berubah-ubah:
class CreateDisplayTextFunction implements NamedJavaFunction{
Ingatlah untuk mendaftarkan fungsi melalui LuaLoader.invoke, mirip dengan contoh sebelumnya
Panggilan dalam lua:
habrPlugin.createText("Hello Habr!")
Kesimpulan
Dengan demikian, aplikasi Android Anda dapat menggunakan semua kemampuan asli platform. Satu-satunya kelemahan dari solusi ini adalah Anda kehilangan kemampuan untuk menggunakan Corona Simulator, yang memperlambat pengembangan (memulai ulang simulator hampir seketika, tidak seperti debugging pada emulator atau perangkat yang membutuhkan build + install)
Tautan yang bermanfaat
Kode lengkap tersedia di github
Dokumentasi Asli Korona
3) Salah satu repositori jnlua . Membantu saya memahami tujuan beberapa fungsi.