Pengikatan Pemecahan Masalah
Penting
Saat ini kami sedang menyelidiki penggunaan pengikatan kustom pada platform Xamarin. Silakan ikuti survei ini untuk menginformasikan upaya pengembangan di masa mendatang.
Artikel ini merangkum kesalahan umum server yang mungkin terjadi saat menghasilkan pengikatan, bersama dengan kemungkinan penyebab dan cara yang disarankan untuk mengatasinya.
Gambaran Umum
Mengikat file pustaka Android ( .aar atau .jar) jarang merupakan urusan yang mudah; biasanya memerlukan upaya tambahan untuk mengurangi masalah yang dihasilkan dari perbedaan antara Java dan .NET. Masalah ini akan mencegah Xamarin.Android mengikat pustaka Android dan menyajikan diri mereka sebagai pesan kesalahan di log build. Panduan ini akan memberikan beberapa tips untuk memecahkan masalah, mencantumkan beberapa masalah/skenario yang lebih umum, dan memberikan solusi yang mungkin agar berhasil mengikat pustaka Android.
Saat mengikat pustaka Android yang ada, perlu diingat poin-poin berikut:
Dependensi eksternal untuk library – Dependensi Java apa pun yang diperlukan oleh pustaka Android harus disertakan dalam proyek Xamarin.Android sebagai ReferenceJar atau sebagai EmbeddedReferenceJar.
Tingkat ANDROID API yang ditargetkan pustaka Android - Tidak mungkin untuk "menurunkan" tingkat ANDROID API; pastikan bahwa proyek pengikatan Xamarin.Android menargetkan tingkat API yang sama (atau lebih tinggi) dengan pustaka Android.
Versi Android JDK yang digunakan untuk mengemas pustaka Android - Kesalahan pengikatan dapat terjadi jika pustaka Android dibangun dengan versi JDK yang berbeda dari yang digunakan oleh Xamarin.Android. Jika memungkinkan, kompilasi ulang pustaka Android menggunakan versi JDK yang sama yang digunakan oleh penginstalan Xamarin.Android Anda.
Langkah pertama untuk memecahkan masalah dengan mengikat pustaka Xamarin.Android adalah mengaktifkan output MSBuild diagnostik. Setelah mengaktifkan output diagnostik, bangun kembali proyek pengikatan Xamarin.Android dan periksa log build untuk menemukan petunjuk tentang apa penyebab masalahnya.
Ini juga dapat terbukti membantu untuk mendekombinasikan pustaka Android dan memeriksa jenis dan metode yang coba diikat Xamarin.Android. Ini tercakup secara lebih rinci nanti dalam panduan ini.
Mendekompresi Pustaka Android
Memeriksa kelas dan metode kelas Java dapat memberikan informasi berharga yang akan membantu dalam mengikat pustaka. JD-GUI adalah utilitas grafis yang dapat menampilkan kode sumber Java dari file CLASS yang terkandung dalam JAR. Ini dapat dijalankan sebagai aplikasi yang berdiri sendiri atau sebagai plug-in untuk IntelliJ atau Eclipse.
Untuk mendekombinasikan pustaka Android, buka . File JAR dengan decompiler Java. Jika pustaka adalah . File AAR , perlu untuk mengekstrak file classes.jar dari file arsip. Berikut ini adalah cuplikan layar sampel penggunaan JD-GUI untuk menganalisis Picasso JAR:
Setelah Anda mendekompilasi pustaka Android, periksa kode sumber. Secara umum, cari :
Kelas yang memiliki karakteristik obfuscation – Karakteristik kelas yang dikaburkan meliputi:
- Nama kelas mencakup $, yaitu $.class
- Nama kelas sepenuhnya disusupi dari karakter huruf kecil, yaitu a.class
import
pernyataan untuk pustaka yang tidak direferensikan – Identifikasi pustaka yang tidak direferensikan dan tambahkan dependensi tersebut ke proyek pengikatan Xamarin.Android dengan TindakanBuild ReferenceJar atau EmbedddedReferenceJar.
Catatan
Mendekompresi pustaka Java mungkin dilarang atau tunduk pada pembatasan hukum berdasarkan undang-undang lokal atau lisensi tempat pustaka Java diterbitkan. Jika perlu, daftarkan layanan profesional hukum sebelum mencoba mendekompilasi pustaka Java dan memeriksa kode sumber.
Memeriksa API.XML
Sebagai bagian dari membangun proyek pengikatan, Xamarin.Android akan menghasilkan nama file XML obj/Debug/api.xml:
File ini menyediakan daftar semua API Java yang coba diikat Xamarin.Android. Isi file ini dapat membantu mengidentifikasi jenis atau metode yang hilang, pengikatan duplikat. Meskipun inspeksi file ini membosankan dan memakan waktu, itu dapat memberikan petunjuk tentang apa yang mungkin menyebabkan masalah pengikatan. Misalnya, api.xml mungkin mengungkapkan bahwa properti mengembalikan jenis yang tidak pantas, atau ada dua jenis yang memiliki nama terkelola yang sama.
Masalah Umum
Bagian ini akan mencantumkan beberapa pesan kesalahan umum atau gejala yang saya alami saat mencoba mengikat pustaka Android.
Masalah: Ketidakcocokan Versi Java
Terkadang jenis tidak akan dihasilkan atau crash yang tidak terduga dapat terjadi karena Anda menggunakan Java versi yang lebih baru atau lebih lama dibandingkan dengan apa yang dikompilasi dengan pustaka. Kompilasi ulang pustaka Android dengan versi JDK yang sama dengan yang digunakan proyek Xamarin.Android Anda.
Masalah: Diperlukan setidaknya satu pustaka Java
Anda menerima kesalahan "setidaknya satu pustaka Java diperlukan," meskipun . JAR telah ditambahkan.
Kemungkinan Penyebab:
Pastikan tindakan build diatur ke EmbeddedJar
. Karena ada beberapa tindakan build untuk . File JAR (seperti InputJar
, , EmbeddedJar
ReferenceJar
dan EmbeddedReferenceJar
), generator pengikatan tidak dapat secara otomatis menebak mana yang akan digunakan secara default. Untuk informasi selengkapnya tentang tindakan build, lihat Tindakan Build.
Masalah: Alat pengikatan tidak dapat memuat . Pustaka JAR
Generator pustaka pengikatan gagal memuat . Perpustakaan JAR.
Kemungkinan Penyebabnya
Beberapa. Pustaka JAR yang menggunakan obfuscation kode (melalui alat seperti Proguard) tidak dapat dimuat oleh alat Java. Karena alat kami menggunakan refleksi Java dan pustaka rekayasa kode byte ASM, alat dependen tersebut dapat menolak pustaka yang dikaburkan sementara alat runtime Android mungkin lulus. Solusinya adalah dengan mengikat pustaka ini dengan tangan alih-alih menggunakan generator pengikatan.
Masalah: Jenis C# yang hilang dalam output yang dihasilkan.
Pengikatan .dll build tetapi melewatkan beberapa jenis Java, atau sumber C# yang dihasilkan tidak dibangun karena kesalahan yang menyatakan ada jenis yang hilang.
Kemungkinan Penyebab:
Kesalahan ini dapat terjadi karena beberapa alasan seperti yang tercantum di bawah ini:
Pustaka yang terikat dapat mereferensikan pustaka Java kedua. Jika API publik untuk pustaka terikat menggunakan jenis dari pustaka kedua, Anda juga harus mereferensikan pengikatan terkelola untuk pustaka kedua.
Ada kemungkinan bahwa pustaka disuntikkan karena refleksi Java, mirip dengan alasan kesalahan beban pustaka di atas, menyebabkan pemuatan metadata yang tidak terduga. Alat Xamarin.Android saat ini tidak dapat menyelesaikan situasi ini. Dalam kasus seperti itu, pustaka harus terikat secara manual.
Ada bug dalam runtime .NET 4.0 yang gagal memuat rakitan ketika seharusnya. Masalah ini telah diperbaiki dalam runtime .NET 4.5.
Java memungkinkan turunan kelas publik dari kelas non-publik, tetapi ini tidak didukung di .NET. Karena generator pengikatan tidak menghasilkan pengikatan untuk kelas non-publik, kelas turunan seperti ini tidak dapat dihasilkan dengan benar. Untuk memperbaikinya, hapus entri metadata untuk kelas turunan tersebut menggunakan remove-node di Metadata.xml, atau perbaiki metadata yang membuat kelas non-publik menjadi publik. Meskipun solusi terakhir akan membuat pengikatan sehingga sumber C# akan dibangun, kelas non-publik tidak boleh digunakan.
Contohnya:
<attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']" name="visibility">public</attr>
Alat yang mengaburkan pustaka Java dapat mengganggu Generator Pengikatan Xamarin.Android dan kemampuannya untuk menghasilkan kelas pembungkus C#. Cuplikan berikut menunjukkan cara memperbarui Metadata.xml untuk membatalkan patfuscate nama kelas:
<attr path="/api/package[@name='{package_name}']/class[@name='{name}']" name="obfuscated">false</attr>
Masalah: Sumber C# yang dihasilkan tidak dibangun karena ketidakcocokan jenis parameter
Sumber C# yang dihasilkan tidak dibuat. Jenis parameter metode penggantian tidak cocok.
Kemungkinan Penyebab:
Xamarin.Android mencakup berbagai bidang Java yang dipetakan ke enum dalam pengikatan C#. Ini dapat menyebabkan ketidaksesuaian jenis dalam pengikatan yang dihasilkan. Untuk mengatasi hal ini, tanda tangan metode yang dibuat dari generator pengikatan perlu dimodifikasi untuk menggunakan enum. Untuk informasi selengkapnya, silakan lihat Mengoreksi Enum.
Masalah: NoClassDefFoundError dalam kemasan
java.lang.NoClassDefFoundError
dilemparkan dalam langkah kemasan.
Kemungkinan Penyebab:
Alasan paling mungkin untuk kesalahan ini adalah bahwa pustaka Java wajib perlu ditambahkan ke proyek aplikasi (.csproj). . File JAR tidak diselesaikan secara otomatis. Pengikatan pustaka Java tidak selalu dihasilkan terhadap rakitan pengguna yang tidak ada di perangkat target atau emulator (seperti Google Peta maps.jar). Ini bukan kasus untuk dukungan proyek Android Library, sebagai pustaka . JAR disematkan di dll pustaka.
Masalah: Menduplikasi jenis EventArgs kustom
Build gagal karena jenis EventArgs kustom duplikat. Kesalahan seperti ini terjadi:
error CS0102: The type `Com.Google.Ads.Mediation.DismissScreenEventArgs' already contains a definition for `p0'
Kemungkinan Penyebab:
Ini karena ada beberapa konflik antara jenis peristiwa yang berasal dari lebih dari satu jenis "listener" antarmuka yang berbagi metode yang memiliki nama yang identik. Misalnya, jika ada dua antarmuka Java seperti yang terlihat dalam contoh di bawah ini, generator membuat DismissScreenEventArgs
untuk dan MediationBannerListener
MediationInterstitialListener
, mengakibatkan kesalahan.
// Java:
public interface MediationBannerListener {
void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
void onDismissScreen(MediationInterstitialAdapter p0);
}
Ini dirancang agar nama panjang pada jenis argumen peristiwa dihindari. Untuk menghindari konflik ini, diperlukan beberapa transformasi metadata. Edit Transformasi\Metadata.xml dan tambahkan argsType
atribut di salah satu antarmuka (atau pada metode antarmuka):
<attr path="/api/package[@name='com.google.ads.mediation']/
interface[@name='MediationBannerListener']/method[@name='onDismissScreen']"
name="argsType">BannerDismissScreenEventArgs</attr>
<attr path="/api/package[@name='com.google.ads.mediation']/
interface[@name='MediationInterstitialListener']/method[@name='onDismissScreen']"
name="argsType">IntersitionalDismissScreenEventArgs</attr>
<attr path="/api/package[@name='android.content']/
interface[@name='DialogInterface.OnClickListener']"
name="argsType">DialogClickEventArgs</attr>
Masalah: Kelas tidak menerapkan metode antarmuka
Pesan kesalahan diproduksi yang menunjukkan bahwa kelas yang dihasilkan tidak menerapkan metode yang diperlukan untuk antarmuka yang diterapkan kelas yang dihasilkan. Namun, melihat kode yang dihasilkan, Anda dapat melihat bahwa metode diimplementasikan.
Berikut adalah contoh kesalahan:
obj\Debug\generated\src\Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.cs(8,23):
error CS0738: 'Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter' does not
implement interface member 'Oauth.Signpost.Http.IHttpRequest.Unwrap()'.
'Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.Unwrap()' cannot implement
'Oauth.Signpost.Http.IHttpRequest.Unwrap()' because it does not have the matching
return type of 'Java.Lang.Object'
Kemungkinan Penyebab:
Ini adalah masalah yang terjadi dengan mengikat metode Java dengan jenis pengembalian kovarian. Dalam contoh ini, metode Oauth.Signpost.Http.IHttpRequest.UnWrap()
perlu mengembalikan Java.Lang.Object
. Namun, metode Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap()
ini memiliki jenis pengembalian .HttpURLConnection
Ada dua cara untuk memperbaiki masalah ini:
Tambahkan deklarasi kelas parsial untuk
HttpURLConnectionRequestAdapter
dan terapkanIHttpRequest.Unwrap()
secara eksplisit :namespace Oauth.Signpost.Basic { partial class HttpURLConnectionRequestAdapter { Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() { return Unwrap(); } } }
Hapus kovarians dari kode C# yang dihasilkan. Ini melibatkan penambahan transformasi berikut ke Transforms\Metadata.xml yang akan menyebabkan kode C# yang dihasilkan memiliki jenis pengembalian :
Java.Lang.Object
<attr path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@name='unwrap']" name="managedReturn">Java.Lang.Object </attr>
Masalah: Tabrakan Nama pada Kelas / Properti Dalam
Visibilitas yang bertentangan pada objek yang diwariskan.
Di Java, tidak diharuskan bahwa kelas turunan memiliki visibilitas yang sama dengan induknya. Java hanya akan memperbaikinya untuk Anda. Di C#, itu harus eksplisit, jadi Anda perlu memastikan semua kelas dalam hierarki memiliki visibilitas yang sesuai. Contoh berikut menunjukkan cara mengubah nama paket Java dari com.evernote.android.job
menjadi Evernote.AndroidJob
:
<!-- Change the visibility of a class -->
<attr path="/api/package[@name='namespace']/class[@name='ClassName']" name="visibility">public</attr>
<!-- Change the visibility of a method -->
<attr path="/api/package[@name='namespace']/class[@name='ClassName']/method[@name='MethodName']" name="visibility">public</attr>
Masalah: Pustaka .so yang Diperlukan oleh Pengikatan Tidak Memuat
Beberapa proyek pengikatan mungkin juga bergantung pada fungsionalitas dalam pustaka .so . Ada kemungkinan bahwa Xamarin.Android tidak akan secara otomatis memuat pustaka .so . Ketika kode Java yang dibungkus dijalankan, Xamarin.Android akan gagal melakukan panggilan JNI dan pesan kesalahan java.lang.UnsatisfiedLinkError: Metode asli tidak ditemukan: akan muncul di logcat keluar untuk aplikasi.
Perbaikan untuk ini adalah memuat pustaka .so secara manual dengan panggilan ke Java.Lang.JavaSystem.LoadLibrary
. Misalnya dengan asumsi bahwa proyek Xamarin.Android memiliki pustaka bersama libpocketsphinx_jni.so termasuk dalam proyek pengikatan dengan tindakan build EmbeddedNativeLibrary, cuplikan berikut (dijalankan sebelum menggunakan pustaka bersama) akan memuat pustaka .so:
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");
Ringkasan
Dalam artikel ini, kami mencantumkan masalah pemecahan masalah umum yang terkait dengan Pengikatan Java dan menjelaskan cara mengatasinya.