Aracılığıyla paylaş


Bağlama Sorunlarını Giderme

Önemli

Şu anda Xamarin platformunda özel bağlama kullanımını araştırıyoruz. Gelecekteki geliştirme çalışmalarını bilgilendirmek için lütfen bu ankete katılın.

Bu makalede, bağlamalar oluşturulurken oluşabilecek sunucusal yaygın hataların yanı sıra olası nedenler ve bunları çözmek için önerilen yollar özetlenmiştir.

Genel bakış

Android kitaplığını ( .aar veya .jar) bağlamak nadiren basit bir iştir; genellikle Java ile .NET arasındaki farklardan kaynaklanan sorunları azaltmak için ek çaba gerektirir. Bu sorunlar, Xamarin.Android'in Android kitaplığını bağlamasını ve kendilerini derleme günlüğünde hata iletileri olarak göstermesini engeller. Bu kılavuz, sorunları gidermeye yönelik bazı ipuçları sağlar, daha yaygın sorunlardan/senaryolardan bazılarını listeler ve Android kitaplığını başarıyla bağlamaya yönelik olası çözümler sağlar.

Mevcut bir Android kitaplığını bağlarken aşağıdaki noktaları göz önünde bulundurmak gerekir:

  • Kitaplığın dış bağımlılıkları – Android kitaplığı için gereken tüm Java bağımlılıkları Xamarin.Android projesine ReferenceJar veya EmbeddedReferenceJar olarak eklenmelidir.

  • Android kitaplığının hedeflediği Android API düzeyi : Android API düzeyini "düşürmek" mümkün değildir; Xamarin.Android bağlama projesinin Android kitaplığıyla aynı API düzeyini (veya üstünü) hedeflediğinden emin olun.

  • Android kitaplığını paketlemek için kullanılan Android JDK sürümü – Android kitaplığı Xamarin.Android tarafından kullanılandan farklı bir JDK sürümüyle oluşturulduysa bağlama hataları oluşabilir. Mümkünse, Xamarin.Android yüklemeniz tarafından kullanılan JDK'nin aynı sürümünü kullanarak Android kitaplığını yeniden derleyin.

Xamarin.Android kitaplığını bağlamayla ilgili sorunları gidermenin ilk adımı, tanılama MSBuild çıkışını etkinleştirmektir. Tanılama çıkışını etkinleştirdikten sonra Xamarin.Android bağlama projesini yeniden derleyin ve sorunun nedeninin ne olduğuna ilişkin ipuçlarını bulmak için derleme günlüğünü inceleyin.

Ayrıca Android kitaplığını derlemek ve Xamarin.Android'in bağlamaya çalıştığı türleri ve yöntemleri incelemek yararlı olabilir. Bu, bu kılavuzun ilerleyen bölümlerinde daha ayrıntılı olarak ele alınmıştır.

Android Kitaplığını Derleme

Java sınıflarının sınıflarını ve yöntemlerini incelemek, kitaplığı bağlamaya yardımcı olacak değerli bilgiler sağlayabilir. JD-GUI, JAR'da yer alan CLASS dosyalarından Java kaynak kodunu görüntüleyebilen bir grafik yardımcı programıdır. Tek başına uygulama olarak veya IntelliJ veya Eclipse eklentisi olarak çalıştırılabilir.

Android kitaplığının kodunu çözmek için dosyasını açın. Java kod ayrıştırıcısı ile JAR dosyası. Kitaplık bir ise. AAR dosyası, arşiv dosyasından dosya classes.jar ayıklamak gerekir. Aşağıda, Picasso JAR'sini analiz etmek için JD-GUI kullanmanın örnek ekran görüntüsü verilmiştir:

Using the Java Decompiler to analyze picasso-2.5.2.jar

Android kitaplığını derledikten sonra kaynak kodu inceleyin. Genel olarak konuşursak, için bakın:

  • Karartma özelliklerine sahip sınıflar – Karartılmış sınıfların özellikleri şunlardır:

    • Sınıf adı bir $içerir; örneğin , a$.class
    • Sınıf adı, küçük harf karakterlerinden (örneğin, a.class) tamamen tehlikeye girer
  • importbaşvurulmayan kitaplıklar için deyimler – Başvurulmayan kitaplığı tanımlayın ve ReferenceJar veya EmbedddedReferenceJar Derleme Eylemiile bu bağımlılıkları Xamarin.Android bağlama projesine ekleyin.

Not

Java kitaplığını derlemek yasaklanabilir veya yerel yasalara veya Java kitaplığının yayımlandığı lisansa bağlı olarak yasal kısıtlamalara tabi olabilir. Gerekirse, bir Java kitaplığını derlemeye ve kaynak kodu incelemeye çalışmadan önce bir hukuk uzmanının hizmetlerini listeleyin.

API.XML denetleme

Bağlama projesi oluşturmanın bir parçası olarak, Xamarin.Android obj/Debug/api.xml bir XML dosya adı oluşturur:

Generated api.xml under obj/Debug

Bu dosya, Xamarin.Android'in bağlamaya çalıştığı tüm Java API'lerinin listesini sağlar. Bu dosyanın içeriği, yinelenen bağlama olan eksik türleri veya yöntemleri tanımlamaya yardımcı olabilir. Bu dosyanın incelenmesi yorucu ve zaman alıcı olsa da, bağlama sorunlarına neyin neden olabileceği hakkında ipuçları sağlayabilir. Örneğin, api.xml bir özelliğin uygunsuz bir tür döndürdüğünü veya aynı yönetilen adı paylaşan iki tür olduğunu gösterebilir.

Bilinen Sorunlar

Bu bölümde, Bir Android kitaplığını bağlamaya çalışırken oluşan bazı yaygın hata iletileri veya belirtiler listelenecektir.

Sorun: Java Sürümü Uyuşmazlığı

Bazen türler oluşturulmaz veya kitaplığın derlendiği sürümle karşılaştırıldığında Java'nın daha yeni veya daha eski bir sürümünü kullandığınızdan beklenmeyen kilitlenmeler oluşabilir. Android kitaplığını, Xamarin.Android projenizin kullandığı JDK sürümüyle yeniden derleyin.

Sorun: En az bir Java kitaplığı gereklidir

bir olsa bile "en az bir Java kitaplığı gereklidir" hatasını alıyorsunuz. JAR eklendi.

Olası Nedenler:

Derleme eyleminin olarak EmbeddedJarayarlandığından emin olun. için birden çok derleme eylemi olduğundan. JAR dosyaları (, ve ReferenceJarEmbeddedReferenceJargibiEmbeddedJarInputJar), bağlama oluşturucu varsayılan olarak hangisinin kullanılacağını otomatik olarak tahmin edemez. Derleme eylemleri hakkında daha fazla bilgi için bkz . Derleme Eylemleri.

Sorun: Bağlama araçları dosyasını yükleyemiyor. JAR kitaplığı

Bağlama kitaplığı oluşturucu yükleyemiyor. JAR kitaplığı.

Olası Nedenler

Bazı. Kod gizleme kullanan JAR kitaplıkları (Proguard gibi araçlar aracılığıyla) Java araçları tarafından yüklenemez. Aracımız Java yansımasını ve ASM bayt kod mühendisliği kitaplığını kullandığından, android çalışma zamanı araçları geçebilirken bu bağımlı araçlar belirsiz kitaplıkları reddedebilir. Bunun geçici çözümü, bağlama oluşturucuyu kullanmak yerine bu kitaplıkları el ile bağlamaktır.

Sorun: Oluşturulan çıktıda eksik C# türleri.

Bağlama .dll bazı Java türlerini oluşturur ancak kaçırır veya oluşturulan C# kaynağı eksik türler olduğunu belirten bir hata nedeniyle derlenmiyor.

Olası Nedenler:

Bu hata, aşağıda listelenen çeşitli nedenlerden kaynaklanabilir:

  • Bağlı olan kitaplık ikinci bir Java kitaplığına başvurabilir. İlişkili kitaplığın genel API'sinde ikinci kitaplıktan türler kullanılıyorsa, ikinci kitaplık için de yönetilen bağlamaya başvurmanız gerekir.

  • Yukarıdaki kitaplık yükleme hatasının nedenine benzer şekilde Java yansıması nedeniyle bir kitaplık eklenmiş olabilir ve bu da meta verilerin beklenmedik şekilde yüklenmesine neden olabilir. Xamarin.Android'in araçları şu anda bu durumu çözemiyor. Böyle bir durumda, kitaplığın el ile bağlanması gerekir.

  • .NET 4.0 çalışma zamanında olması gerektiğinde derlemeleri yükleyemeyen bir hata oluştu. Bu sorun .NET 4.5 çalışma zamanında düzeltilmiştir.

  • Java, genel olmayan bir sınıftan genel sınıf türetmeye izin verir, ancak bu .NET'te desteklenmez. Bağlama oluşturucu ortak olmayan sınıflar için bağlamalar oluşturmadığından, bunlar gibi türetilmiş sınıflar doğru oluşturulamaz. Bunu düzeltmek için, Metadata.xml remove-node kullanarak türetilmiş sınıfların meta veri girdisini kaldırın veya genel olmayan sınıfı genel yapan meta verileri düzeltin. İkinci çözüm C# kaynağının derlenmesi için bağlamayı oluştursa da, ortak olmayan sınıf kullanılmamalıdır.

    Örneğin:

    <attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']"
        name="visibility">public</attr>
    
  • Java kitaplıklarını gizleyen araçlar, Xamarin.Android Bağlama Oluşturucu'ya ve C# sarmalayıcı sınıfları oluşturma yeteneğine engel olabilir. Aşağıdaki kod parçacığında, bir sınıf adının engelini kaldıracak şekilde Metadata.xml nasıl güncelleştirilecek gösterilmektedir:

    <attr path="/api/package[@name='{package_name}']/class[@name='{name}']"
        name="obfuscated">false</attr>
    

Sorun: Oluşturulan C# kaynağı parametre türü uyuşmazlığı nedeniyle oluşturulmuyor

Oluşturulan C# kaynağı derlenmiyor. Geçersiz kılınan yöntemin parametre türleri eşleşmiyor.

Olası Nedenler:

Xamarin.Android, C# bağlamalarındaki sabit listeleriyle eşlenen çeşitli Java alanları içerir. Bunlar, oluşturulan bağlamalarda tür uyumsuzluklarına neden olabilir. Bunu çözmek için, bağlama oluşturucudan oluşturulan yöntem imzalarının sabit listeleri kullanmak için değiştirilmesi gerekir. Daha fazla bilgi için bkz . Numaralandırmaları Düzeltme.

Sorun: Paketlemede NoClassDefFoundError

java.lang.NoClassDefFoundError paketleme adımında oluşturulur.

Olası Nedenler:

Bu hatanın en olası nedeni, uygulama projesine (.csproj) zorunlu bir Java kitaplığı eklenmesi gerektiğidir. . JAR dosyaları otomatik olarak çözümlenmez. Java kitaplık bağlaması her zaman hedef cihazda veya öykünücüde (Google Haritalar maps.jar gibi) mevcut olmayan bir kullanıcı derlemesine karşı oluşturulmaz. Android Kitaplığı proje desteği için kitaplığı olarak bu durum geçerli değildir. JAR, kitaplık dll'sine eklenir.

Sorun: Yinelenen özel EventArgs türleri

Yinelenen özel EventArgs türleri nedeniyle derleme başarısız oluyor. Aşağıdaki gibi bir hata oluşur:

error CS0102: The type `Com.Google.Ads.Mediation.DismissScreenEventArgs' already contains a definition for `p0'

Olası Nedenler:

Bunun nedeni, aynı adlara sahip yöntemleri paylaşan birden fazla arabirim "dinleyicisi" türünden gelen olay türleri arasında bazı çakışmalar olmasıdır. Örneğin, aşağıdaki örnekte görüldüğü gibi iki Java arabirimi varsa, oluşturucu hem hem MediationInterstitialListenerde MediationBannerListener için oluşturur DismissScreenEventArgs ve hatayla sonuçlanır.

// Java:
public interface MediationBannerListener {
    void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
    void onDismissScreen(MediationInterstitialAdapter p0);
}

Bu, tasarım gereğidir, böylece olay bağımsız değişken türlerinde uzun adlardan kaçınılır. Bu çakışmaları önlemek için bazı meta veri dönüştürmeleri gerekir. Transforms\Metadata.xml düzenleyin ve arabirimlerden herhangi birinde (veya arabirim yönteminde) bir argsType öznitelik ekleyin:

<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>

Sorun: Sınıf arabirim yöntemini uygulamıyor

Oluşturulan bir sınıfın, oluşturulan sınıfın uyguladığı bir arabirim için gerekli olan bir yöntemi uygulamadığını belirten bir hata iletisi oluşturulur. Ancak, oluşturulan koda baktığınızda yönteminin uygulandığını görebilirsiniz.

Hatanın bir örneği aşağıda verilmiştir:

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'

Olası Nedenler:

Bu, java yöntemlerinin birlikte değişken dönüş türleriyle bağlanmasıyla oluşan bir sorundur. Bu örnekte yönteminin Oauth.Signpost.Http.IHttpRequest.UnWrap() döndürmesi Java.Lang.Objectgerekir. Ancak yönteminin Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() dönüş türü vardır HttpURLConnection. Bu sorunu düzeltmenin iki yolu vardır:

  • için HttpURLConnectionRequestAdapter kısmi sınıf bildirimi ekleyin ve açıkça uygulayın IHttpRequest.Unwrap():

    namespace Oauth.Signpost.Basic {
        partial class HttpURLConnectionRequestAdapter {
            Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() {
                return Unwrap();
            }
        }
    }
    
  • Oluşturulan C# kodundan kovaryansı kaldırın. Bu, oluşturulan C# kodunun dönüş türüne Java.Lang.Objectsahip olmasına neden olacak Transforms\Metadata.xml'a aşağıdaki dönüşümü eklemeyi içerir:

    <attr
        path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@name='unwrap']"
        name="managedReturn">Java.Lang.Object
    </attr>
    

Sorun: İç Sınıflarda / Özelliklerde Ad Çakışmaları

Devralınan nesnelerde çakışan görünürlük.

Java'da, türetilmiş bir sınıfın üst sınıfıyla aynı görünürlüğe sahip olması gerekmez. Java bunu sizin için düzeltir. C# dilinde bu açık olmalıdır, bu nedenle hiyerarşideki tüm sınıfların uygun görünürlüğe sahip olduğundan emin olmanız gerekir. Aşağıdaki örnekte Java paketi adının olarak com.evernote.android.jobEvernote.AndroidJobnasıl değiştireceği gösterilmektedir:

<!-- 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>

Sorun: Bağlamanın Gerektirdiği .so Kitaplığı Yüklenmiyor

Bazı bağlama projeleri bir .so kitaplığındaki işlevselliğe de bağlı olabilir. Xamarin.Android'in .so kitaplığını otomatik olarak yüklememesi mümkündür. Sarmalanan Java kodu yürütürken, Xamarin.Android JNI çağrısını yapamaz ve java.lang.UnsatisfiedLinkError: Native yöntemi bulunamadı: uygulama için logcat out içinde görüntülenir.

Bunun düzeltmesi, .so kitaplığını çağrısıyla el ile yüklemektirJava.Lang.JavaSystem.LoadLibrary. Örneğin, bir Xamarin.Android projesinin embeddedNativeLibrary derleme eylemiyle bağlama projesine dahil libpocketsphinx_jni.o nedenle paylaşılan kitaplığı olduğunu varsayarsak, aşağıdaki kod parçacığı (paylaşılan kitaplığı kullanmadan önce yürütülür) .so kitaplığını yükler:

Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");

Özet

Bu makalede Java Bağlamalarıyla ilgili yaygın sorun giderme sorunlarını listeledik ve bunların nasıl çözüleceğini açıkladık.