Řešení potíží s vazbami

Důležité

V současné době prošetřujeme využití vlastních vazeb na platformě Xamarin. Pokud chcete informovat budoucí úsilí o rozvoj, využijte tento průzkum .

Tento článek shrnuje serverové běžné chyby, ke kterým může dojít při generování vazeb, spolu s možnými příčinami a navrhovanými způsoby jejich řešení.

Přehled

Vytvoření vazby knihovny Pro Android ( soubor .aar nebo .jar) je zřídka jednoduchá záležitost. Obvykle vyžaduje další úsilí ke zmírnění problémů, které vyplývají z rozdílů mezi Javou a .NET. Tyto problémy zabrání vytvoření vazby knihovny Pro Android v Xamarin.Androidu a zobrazí se jako chybové zprávy v protokolu sestavení. Tato příručka obsahuje několik tipů pro řešení potíží, seznam některých nejběžnějších problémů a scénářů a poskytuje možná řešení úspěšné vazby knihovny Pro Android.

Při vytváření vazby existující knihovny Pro Android je nutné mít na paměti následující body:

  • Externí závislosti pro knihovnu – Všechny závislosti Java vyžadované knihovnou Androidu musí být zahrnuty do projektu Xamarin.Android jako ReferenceJar nebo jako EmbeddedReferenceJar.

  • Úroveň rozhraní Android API, na kterou cílí knihovna Androidu , není možné downgradovat úroveň rozhraní ANDROID API. Ujistěte se, že projekt vazby Xamarin.Android cílí na stejnou úroveň rozhraní API (nebo vyšší) jako knihovna Androidu.

  • Verze sady Android JDK, která byla použita k zabalení knihovny Pro Android – Chyby vazby mohou nastat, pokud byla knihovna Pro Android vytvořena s jinou verzí sady JDK, než kterou používá Xamarin.Android. Pokud je to možné, překompilujte knihovnu Pro Android pomocí stejné verze sady JDK, kterou používá vaše instalace Xamarin.Android.

Prvním krokem při řešení potíží s vazbou knihovny Xamarin.Android je povolení výstupu nástroje MSBuild diagnostiky. Po povolení výstupu diagnostiky znovu sestavte projekt vazby Xamarin.Android a prozkoumejte protokol sestavení a vyhledejte povědomí o příčině problému.

Může také být užitečné dekompilovat knihovnu Pro Android a prozkoumat typy a metody, které se Xamarin.Android snaží svázat. Podrobnější informace najdete dále v této příručce.

Dekompilování knihovny pro Android

Kontrola tříd a metod tříd Java může poskytovat cenné informace, které vám pomůžou s vazbou knihovny. JD-GUI je grafický nástroj, který může zobrazit zdrojový kód Java ze souborů CLASS obsažených v SOUBORU JAR. Dá se spustit jako samostatná aplikace nebo jako modul plug-in pro IntelliJ nebo Eclipse.

Chcete-li dekompilovat knihovnu pro Android, otevřete soubor . Soubor JAR s dekompilerem Java Pokud je knihovna . Soubor AAR , je nutné extrahovat soubor classes.jar ze souboru archivu. Následuje ukázkový snímek obrazovky s použitím grafického uživatelského rozhraní (JD-GUI) k analýze souboru Picasso JAR:

Using the Java Decompiler to analyze picasso-2.5.2.jar

Jakmile dekompilujete knihovnu androidu, prozkoumejte zdrojový kód. Obecně řečeno, hledejte:

  • Třídy, které mají charakteristiky obfuskace – charakteristiky obfuskovaných tříd zahrnují:

    • Název třídy obsahuje , $tj. a$.class.
    • Název třídy je zcela ohrožen malá písmena, tj. a.class.
  • import příkazy pro neodkazované knihovny – Identifikujte nerozpoznanou knihovnu a přidejte tyto závislosti do projektu vazby Xamarin.Android pomocí akcesestavení ReferenceJar nebo EmbedddedReferenceJar.

Poznámka:

Dekompilování knihovny Java může být zakázáno nebo podléhat právním omezením na základě místních zákonů nebo licence, pod kterou byla knihovna Java publikována. V případě potřeby zapojte služby právního odborníka, než se pokusíte dekompilovat knihovnu Java a prozkoumat zdrojový kód.

Kontrola API.XML

V rámci vytváření projektu vazby vygeneruje Xamarin.Android název souboru XML obj/Debug/api.xml:

Generated api.xml under obj/Debug

Tento soubor obsahuje seznam všech rozhraní JAVA API, která Xamarin.Android zkouší vytvořit vazbu. Obsah tohoto souboru může pomoct identifikovat všechny chybějící typy nebo metody, duplicitní vazbu. I když kontrola tohoto souboru je zdlouhavá a časově náročná, může poskytnout vodítka k tomu, co může způsobovat jakékoli problémy s vazbou. Například api.xml může odhalit, že vlastnost vrací nevhodný typ nebo že existují dva typy, které sdílejí stejný spravovaný název.

Známé problémy

Tato část obsahuje seznam některých běžných chybových zpráv nebo příznaků, ke kterým dochází při pokusu o vytvoření vazby knihovny androidu.

Problém: Neshoda verzí Javy

Někdy se může stát, že typy nebudou generovány nebo neočekávané chybové ukončení, protože používáte novější nebo starší verzi Javy v porovnání s tím, s čím byla knihovna zkompilována. Znovu zkompilujte knihovnu Pro Android se stejnou verzí sady JDK, kterou používá váš projekt Xamarin.Android.

Problém: Vyžaduje se aspoň jedna knihovna Java.

Zobrazí se chyba "Vyžaduje se alespoň jedna knihovna Java", i když . Byl přidán soubor JAR.

Možné příčiny:

Ujistěte se, že je akce sestavení nastavená na EmbeddedJar. Vzhledem k tomu, že existuje více akcí sestavení pro . Soubory JAR (například InputJar, EmbeddedJarReferenceJar a EmbeddedReferenceJar) generátor vazeb nemůže automaticky odhadnout, který z nich se má použít ve výchozím nastavení. Další informace o akcích sestavení najdete v tématu Akce sestavení.

Problém: Nástroje vazby nemůžou načíst . Knihovna JAR

Generátor vazby knihovny se nepodaří načíst . Knihovna JAR.

Možné příčiny

Některé. Knihovny JAR, které používají obfuskaci kódu (prostřednictvím nástrojů, jako je Proguard), nelze načíst pomocí nástrojů Java. Vzhledem k tomu, že náš nástroj využívá reflexi Javy a knihovnu pro přípravu kódu ASM, můžou tyto závislé nástroje odmítnout obfuskované knihovny, zatímco nástroje pro android runtime mohou proběhnout. Alternativním řešením je ruční vytvoření vazby těchto knihoven místo použití generátoru vazeb.

Problém: Chybějící typy jazyka C# ve vygenerovaném výstupu

Vazba .dll sestavení, ale chybí některé typy Javy nebo vygenerovaný zdroj jazyka C# se nevytvořuje kvůli chybě s oznámením, že chybí typy.

Možné příčiny:

K této chybě může dojít z několika důvodů, jak je uvedeno níže:

  • Vázaná knihovna může odkazovat na druhou knihovnu Java. Pokud veřejné rozhraní API pro vázanou knihovnu používá typy z druhé knihovny, musíte odkazovat také na spravovanou vazbu pro druhou knihovnu.

  • Je možné, že knihovna byla vložena z důvodu reflexe Jazyka Java, podobně jako příčinou výše uvedené chyby načtení knihovny, což způsobuje neočekávané načítání metadat. Nástroje Xamarin.Android momentálně nemůžou tuto situaci vyřešit. V takovém případě musí být knihovna vázána ručně.

  • V modulu runtime .NET 4.0 došlo k chybě, která se nepodařilo načíst sestavení, když měla. Tento problém je opravený v modulu runtime .NET 4.5.

  • Java umožňuje odvození veřejné třídy z neveřejné třídy, ale to není podporováno v .NET. Vzhledem k tomu, že generátor vazeb negeneruje vazby pro neveřejné třídy, odvozené třídy, jako jsou tyto, nelze správně vygenerovat. Tento problém vyřešíte tak, že odeberete položku metadat pro tyto odvozené třídy pomocí uzlu remove-node v Metadata.xml nebo opravíte metadata, která zpřístupňuje neveřejnou třídu. I když druhé řešení vytvoří vazbu tak, aby se zdroj jazyka C#sestavil, neměla by se použít veřejná třída.

    Příklad:

    <attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']"
        name="visibility">public</attr>
    
  • Nástroje, které obfuscate knihovny Java mohou kolidovat s generátorem vazeb Xamarin.Android a jeho schopnost generovat třídy obálky jazyka C#. Následující fragment kódu ukazuje, jak aktualizovat Metadata.xml a zrušit tak název třídy:

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

Problém: Vygenerovaný zdroj jazyka C# se nevytvořuje kvůli neshodě typu parametru

Vygenerovaný zdroj jazyka C# se nevytvořuje. Přepisované typy parametrů metody se neshodují.

Možné příčiny:

Xamarin.Android obsahuje řadu polí Java, která jsou namapovaná na výčty v vazbách jazyka C#. To může způsobit nekompatibilitu typu ve vygenerovaných vazbách. Pokud chcete tento problém vyřešit, musí být podpisy metody vytvořené z generátoru vazeb upraveny tak, aby používaly výčty. Další informace naleznete v tématu Oprava výčtů.

Problém: NoClassDefFoundError v balení

java.lang.NoClassDefFoundError je vyvolán v kroku balení.

Možné příčiny:

Nejpravděpodobnějším důvodem této chyby je, že je potřeba do projektu aplikace (.csproj) přidat povinnou knihovnu Java. . Soubory JAR se automaticky nepřekládají. Vazba knihovny Java není vždy generována pro uživatelské sestavení, které neexistuje v cílovém zařízení nebo emulátoru (například Google Mapy maps.jar). To není případ podpory projektu knihovny Android, jako knihovna . Soubor JAR je vložen do knihovny dll.

Problém: Duplicitní vlastní typy EventArgs

Sestavení selže kvůli duplicitním vlastním typům EventArgs. K této chybě dochází:

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

Možné příčiny:

Důvodem je, že mezi typy událostí, které pocházejí z více než jednoho typu "naslouchacího procesu" rozhraní, který sdílí metody s identickými názvy. Pokud jsou například dvě rozhraní Java, jak je vidět v následujícím příkladu, generátor vytvoří DismissScreenEventArgs pro obojí MediationBannerListener a MediationInterstitialListener, což vede k chybě.

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

Jde o návrh tak, aby se zabránilo zdlouhavým názvům typů argumentů událostí. Aby se zabránilo těmto konfliktům, vyžaduje se určitá transformace metadat. Upravte transforms\Metadata.xml a přidejte argsType atribut na rozhraní (nebo v metodě rozhraní):

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

Problém: Třída neimplementuje metodu rozhraní

Vytvoří se chybová zpráva, která indikuje, že vygenerovaná třída neimplementuje metodu, která je vyžadována pro rozhraní, které vygenerovaná třída implementuje. Když se ale podíváte na vygenerovaný kód, uvidíte, že je metoda implementovaná.

Tady je příklad chyby:

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'

Možné příčiny:

Jedná se o problém, ke kterému dochází u vazeb metod Java s kovariantním návratovým typem. V tomto příkladu musí metoda Oauth.Signpost.Http.IHttpRequest.UnWrap() vrátit Java.Lang.Object. Metoda Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() však má návratový HttpURLConnectiontyp . Tento problém můžete vyřešit dvěma způsoby:

  • Přidejte deklaraci částečné třídy pro HttpURLConnectionRequestAdapter a explicitně implementujte IHttpRequest.Unwrap():

    namespace Oauth.Signpost.Basic {
        partial class HttpURLConnectionRequestAdapter {
            Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() {
                return Unwrap();
            }
        }
    }
    
  • Odeberte kovarianci z vygenerovaného kódu jazyka C#. To zahrnuje přidání následující transformace do transforms\Metadata.xml což způsobí, že vygenerovaný kód jazyka C# bude mít návratový Java.Lang.Objecttyp:

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

Problém: Kolize názvů ve vnitřních třídách / vlastnostech

Konfliktní viditelnost u zděděných objektů

V Javě není nutné, aby odvozená třída měla stejnou viditelnost jako nadřazená třída. Java to vyřeší za vás. V jazyce C# musí být explicitní, takže musíte zajistit, aby všechny třídy v hierarchii měly odpovídající viditelnost. Následující příklad ukazuje, jak změnit název balíčku Java z com.evernote.android.job na 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>

Problém: Knihovna požadovaná vazbou se nenačítá

Některé projekty vazeb můžou záviset také na funkcích v knihovně .so . Je možné, že Xamarin.Android automaticky nenačte knihovnu .so . Když se zabalený kód Java spustí, Xamarin.Android neprovede volání JNI a chybovou zprávu java.lang.UnsatisfiedLinkError: Nativní metoda nebyla nalezena: zobrazí se v odhlašovacím příkazu aplikace.

Oprava tohoto problému spočívá v ručním načtení knihovny .so s voláním Java.Lang.JavaSystem.LoadLibrary. Předpokládejme například, že projekt Xamarin.Android má sdílenou knihovnu libpocketsphinx_jni.so součástí vazbového projektu s akcí sestavení EmbeddedNativeLibrary, následující fragment kódu (spuštěn před použitím sdílené knihovny) načte knihovnu .so:

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

Shrnutí

V tomto článku jsme uvedli běžné problémy s řešením potíží souvisejících s vazbami Java a vysvětlili jsme, jak je vyřešit.