Řešení potíží s vazbami

Důležité

V současné době zkoumáme využití vlastních vazeb na platformě Xamarin. Využijte tento průzkum, abyste informovali o budoucím úsilí o vývoj.

Tento článek shrnuje běžné serverové 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 souboru knihovny pro Android (soubor .aar nebo .jar)je jen zřídka jednoduché. Obvykle vyžaduje další úsilí ke zmírnění problémů, které jsou důsledkem rozdílů mezi Javou a .NET. Tyto problémy zabrání Xamarin.Androidu v navázání knihovny pro Android a prezentují 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 možná řešení pro úspěšné navázání knihovny pro Android.

Při vytváření vazby existující knihovny pro Android je potřeba 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 součástí projektu Xamarin.Android jako reference Nebojako EmbeddedReference Při.

  • Úroveň rozhraní Android API, na kterou knihovna Androidu cílí – 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 pro Android.

  • Verze sady Android JDK, která se použila k zabalení knihovny pro Android – K chybám vazeb může dojít v případě, že byla knihovna androidu sestavena s jinou verzí sady JDK, než kterou používá Xamarin.Android. Pokud je to možné, znovu zkompilujte 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í diagnostických MSBuild výstupu. Po povolení diagnostického výstupu znovu sestavte projekt vazby Xamarin.Android a prozkoumejte protokol sestavení a vyhledejte stopu o příčině problému.

Může být také užitečné dekompilovat knihovnu Androidu a prozkoumat typy a metody, které se Xamarin.Android pokouší navázat. Podrobnější popis najdete dále v tomto průvodci.

Dekompilice knihovny pro Android

Kontrola tříd a metod tříd Java může poskytnout cenné informace, které vám pomohou s vazbou knihovny. JD-GUI je grafický nástroj, který dokáže zobrazit zdrojový kód Java ze souborů CLASS obsažených v souboru JAR. Můžete ji spustit jako samostatnou aplikaci nebo jako modul plug-in pro IntelliJ nebo Eclipse.

Pokud chcete dekompilovat knihovnu androidu, otevřete . Soubor JAR s dekompilátorem Java. Pokud je knihovna . Soubor AAR je potřeba extrahovat soubor classes.jar z archivního souboru. Následuje ukázkový snímek obrazovky s použitím rozhraní JD-GUI k analýze souboru JAR Picassa:

Použití dekompilátoru Java k analýze picasso-2.5.2.jar

Po dekompilaci knihovny pro Android prozkoumejte zdrojový kód. Obecně platí, že hledejte :

  • Mezi třídy, které mají charakteristiky obfuskace – Charakteristiky obfuskovaných tříd patří:

    • Název třídy obsahuje $ , tj. $
    • Název třídy je zcela ohrožený malá písmena, tj. třída .
  • příkazy pro neodkazované knihovny – Identifikujte neodkazovanou knihovnu a přidejte tyto závislosti do projektu vazby Xamarin.Android pomocí akce sestavení Reference Zad nebo EmbedddedReference V.

Poznámka

Dekompilice knihovny Java může být zakázána nebo podléhat právním omezením na základě místních zákonů nebo licence, na základě které byla knihovna Java publikována. V případě potřeby si před pokusem o dekompilace knihovny Java a kontrole zdrojového kódu zapište služby právní odborníka.

Kontrola API.XML

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

Vygenerované api.xml v části obj/Debug

Tento soubor obsahuje seznam všech rozhraní Java API, která se Xamarin.Android pokouší navázat. Obsah tohoto souboru může pomoct identifikovat všechny chybějící typy nebo metody, duplicitní vazby. I když je kontrola tohoto souboru zdlouhavá a časově náročná, může vám poskytnout vodítka k tomu, co může být příčinou problémů s vazbami. Například může api.xml, že vlastnost vrací nevhodný typ nebo že existují dva typy, které sdílejí stejný spravovaný název.

Známé problémy

V této části najdete některé běžné chybové zprávy nebo příznaky, ke kterým dochází při pokusu o vytvoření vazby knihovny pro Android.

Problém: Neshoda verzí Javy

V některých případech typy nebudou generovány nebo může dojít k neočekávaným chybám, 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 alespoň jedna knihovna Java.

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

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 , a ) nemohou generátor vazeb automaticky odhadnout, který z nich InputJar se má použít ve výchozím EmbeddedJarReferenceJarEmbeddedReferenceJar nastavení. Další informace o akcích sestavení najdete v tématu Build Actions.

Problém: Nástroje vazby nemohou načíst . Knihovna JAR

Generátoru vazeb 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 Jazyka Java a knihovnu ASM BYTE Code Engineering, mohou tyto závislé nástroje odmítat obfuskované knihovny, zatímco mohou prošly běhové nástroje Androidu. Alternativním řešením je vytvořit vazbu těchto knihoven ručně místo použití generátoru vazeb.

Problém: Ve vygenerovaných výstupech chybí typy jazyka C#.

Vazba se .dll, ale chybí některé typy Jazyka Java, nebo se vygenerovaný zdroj C# nevytváří 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:

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

  • Je možné, že knihovna byla injektována z důvodu reflexe Jazyka Java, podobně jako výše uvedená chyba načtení knihovny, což způsobilo neočekávané načítání metadat. Nástroje Xamarin.Androidu v současné době tuto situaci nevyřeší. V takovém případě musí být knihovna ručně svázaná.

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

  • Java umožňuje odvozování veřejné třídy z ne veřejná třída, ale v .NET to není podporováno. Vzhledem k tomu, že generátor vazeb negeneruje vazby pro ne veřejné třídy, nelze takové odvozené třídy vygenerovat správně. Pokud chcete tento problém vyřešit, odeberte položku metadat pro tyto odvozené třídy pomocí uzlu remove-node v Metadata.xmlnebo opravte metadata, která z ne public třídy dělají veřejné. I když druhé řešení vytvoří vazbu tak, aby se zdroj C# sestaví, ne veřejná třída by se neměla používat.

    Například:

    <attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']"
        name="visibility">public</attr>
    
  • Nástroje, které obfuskují knihovny Jazyka Java, mohou narušovat generátor vazeb Xamarin.Android a jeho schopnost generovat obálkové třídy jazyka C#. Následující fragment kódu ukazuje, jakMetadata.xml zrušitobfuscate název třídy:

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

Problém: Vygenerovaný zdroj C# se nevytváří kvůli neshodě typů parametrů

Vygenerovaný zdroj C# se nevytváří. Typy parametrů přepsané metody se neshodují.

Možné příčiny:

Xamarin.Android obsahuje celou řadu polí Java, která jsou namapovaná na výčty ve vazbách jazyka C#. Ty mohou způsobit nekompatibilitu typů ve vygenerovaných vazbách. Pokud chcete tento problém vyřešit, je potřeba upravit podpisy metod vytvořené z generátoru vazeb tak, aby se používají výčty. Další informace najdete v tématu Oprava výčtů.

Problém: NoClassDefFoundError v balení

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

Možné příčiny:

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

Problém: Duplicitní vlastní typy EventArgs

Sestavení selže kvůli duplicitním vlastním typům EventArgs. Dojde k této chybě:

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

Možné příčiny:

Je to proto, že mezi typy událostí, které pocházejí z více než jednoho typu "naslouchacího procesu", který sdílí metody se stejnými názvy, dochází ke konfliktu. Pokud například existují dvě rozhraní Java, jak je vidět v následujícím příkladu, generátor vytvoří pro a , což DismissScreenEventArgsMediationBannerListener vede k MediationInterstitialListener chybě.

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

Je to z návrhu tak, aby se zabránilo zdlouhavé názvy u typů argumentů událostí. Aby nedocházelo k těmto konfliktům, je potřeba některé transformace metadat. Upravte Transforms\Metadata.xml a přidejte atribut do jednoho z rozhraní (nebo do metody 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 oznamující, že vygenerovaná třída neimplementuje metodu požadovanou pro rozhraní, které vygenerovaná třída implementuje. Při pohledu na vygenerovaný kód ale vidí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í návratové typy. V tomto příkladu musí Oauth.Signpost.Http.IHttpRequest.UnWrap() metoda vrátit Java.Lang.Object . Metoda má Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() však návratový typ HttpURLConnection . Tento problém můžete vyřešit dvěma způsoby:

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

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

    <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ů u vnitřních tříd nebo vlastností

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

V Javě není nutné, aby odvozená třída měl stejnou viditelnost jako její nadřazená třída. Java to za vás opraví. V jazyce C# to 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 .so požadovaná vazbami se nenačítá

Některé projekty vazeb mohou také záviset na funkčnosti v knihovně .so. Je možné, že Xamarin.Android nenačte automaticky knihovnu .so. Při spuštění zabaleného kódu Java se Xamarin.Android nepodaří provést volání JNI a chybovou zprávu java.lang.UnsatisfiedLinkError: Nativní metoda se nenašla: zobrazí se v logcat out pro aplikaci.

Opravou tohoto problému je ruční načtení knihovny .so s voláním . Například za předpokladu, že projekt Xamarin.Android má sdílenou knihovnu libpocketsphinx_jni.so zahrnutou do projektu vazby s akcí sestavení EmbeddedNativeLibrary,načte následující fragment kódu (spuštěný před použitím sdílené knihovny) knihovnu .so:

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

Souhrn

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