Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Att binda ett Android-bibliotek ( en .aar - eller .jar)-fil är sällan en enkel affär. Det kräver vanligtvis ytterligare arbete för att åtgärda problem som beror på skillnaderna mellan Java och .NET. De här problemen hindrar .NET för Android från att binda Android-biblioteket och visas som felmeddelanden i byggloggen. Den här guiden innehåller några tips för att felsöka problemen, lista några av de vanligaste problemen/scenarierna och tillhandahålla möjliga lösningar för att binda Android-biblioteket.
När du binder ett befintligt Android-bibliotek måste du tänka på följande:
De externa beroendena för biblioteket – Alla Java-beroenden som krävs av Android-biblioteket måste ingå i .NET för Android-projektet via ett NuGet-paket eller som en AndroidLibrary.
Android API-nivån som Android-biblioteket riktar in sig på – Det går inte att "nedgradera" Android API-nivån. se till att .NET for Android-bindningsprojektet har samma API-nivå (eller högre) som Android-biblioteket.
Tips/Råd
Wikin för GitHub-lagringsplatsen för bindningsverktyg är en bra resurs och innehåller ytterligare felsökningsinformation som kan hjälpa dig med specifika fall.
Det första steget för att felsöka problem med att binda ett .NET för Android-bibliotek är att aktivera diagnostiska MSBuild-utdata. När du har aktiverat diagnostikutdata återskapar du .NET for Android-bindningsprojektet och undersöker byggloggen för att hitta ledtrådar om vad orsaken till problemet är.
Det kan också vara användbart att dela upp Android-biblioteket och undersöka de typer och metoder som .NET för Android försöker binda. Detta beskrivs mer detaljerat senare i den här guiden.
Dekompilera ett Android-bibliotek
Genom att inspektera klasser och metoder för Java-klasserna kan du ge värdefull information som hjälper dig att binda ett bibliotek. JD-GUI är ett grafiskt verktyg som kan visa Java-källkod från KLASS-filerna som finns i en JAR.
Om du vill dela upp ett Android-bibliotek öppnar du . JAR-fil med Java-decompiler. Om biblioteket är en . AAR-fil , Java-källkoden finns i classes.jar posten i arkivfilen. Följande är ett exempel på en skärmbild av hur du använder JD-GUI för att analysera Picasso JAR:
När du har dekompilerat Android-biblioteket undersöker du källkoden. Generellt sett letar du efter :
Klasser som har egenskaper för fördunkling – Egenskaper för fördunklade klasser är:
- Klassnamnet innehåller en $, d.v.s. a$.class
- Klassnamnet är helt komprometterat med gemener, d.v.s. a.class
importinstruktioner för orefererade bibliotek – Identifiera det orefererade biblioteket och lägg till dessa beroenden i .NET för Android-bindningsprojekt med en lämplig bindning från NuGet eller med en Byggåtgärd för AndroidLibrary.
Anmärkning
Att dela upp ett Java-bibliotek kan vara förbjudet eller omfattas av juridiska begränsningar baserat på lokala lagar eller den licens enligt vilken Java-biblioteket publicerades. Om det behövs kan du anlita en juridisk personal innan du försöker dela upp ett Java-bibliotek och inspektera källkoden.
Inspektera api.xml
Som en del av skapandet av ett bindningsprojekt genererar .NET för Android ett XML-filnamn obj/Debug/api.xml:
Den här filen innehåller en lista över alla Java-API:er som .NET för Android försöker binda. Innehållet i den här filen kan hjälpa dig att identifiera eventuella typer eller metoder som saknas, duplicerad bindning. Även om kontrollen av den här filen är omständlig och tidskrävande kan den ge ledtrådar om vad som kan orsaka bindningsproblem. Till exempel kan api.xml visa att en egenskap returnerar en olämplig typ eller att det finns två typer som delar samma hanterade namn.
Kända problemområden
I det här avsnittet visas några vanliga felmeddelanden eller symtom som jag får när jag försöker binda ett Android-bibliotek.
Problem: C#-typer saknas i genererade utdata.
Bindningen .dll bygger men missar vissa Java-typer, eller så skapas inte den genererade C#-källan på grund av ett fel som anger att det saknas typer.
Möjliga orsaker:
Det här felet kan inträffa på grund av flera orsaker som anges nedan:
Biblioteket som är bundet kan referera till ett andra Java-bibliotek. Om det offentliga API:et för det bundna biblioteket använder typer från det andra biblioteket måste du även referera till en hanterad bindning för det andra biblioteket.
Med Java kan du härleda en offentlig klass från en icke-offentlig klass, men det stöds inte i .NET. Eftersom bindningsgeneratorn inte genererar bindningar för icke-offentliga klasser kan härledda klasser som dessa inte genereras korrekt. Åtgärda detta genom att antingen ta bort metadataposten för dessa härledda klasser med hjälp av remove-node i Metadata.xmleller åtgärda metadata som gör den icke-offentliga klassen offentlig. Även om den senare lösningen skapar bindningen så att C#-källan skapas ska den icke-offentliga klassen inte användas.
Som exempel:
<attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']" name="visibility">public</attr>Verktyg som fördunklar Java-bibliotek kan störa .NET för Android-bindningsgeneratorn och dess förmåga att generera C#-omslutningsklasser. Följande kodfragment visar hur du uppdaterar Metadata.xml för att ta bort ett klassnamn:
<attr path="/api/package[@name='{package_name}']/class[@name='{name}']" name="obfuscated">false</attr>
Problem: Den genererade C#-källan skapas inte på grund av parametertypens matchningsfel
Den genererade C#-källkoden kompileras inte. Den åsidosatta metodens parametertyper matchar inte.
Möjliga orsaker:
.NET för Android innehåller en mängd olika Java-fält som är mappade till uppräkningar i C#-bindningar. Dessa kan orsaka typinkompatibiliteter i de genererade bindningarna. För att lösa detta måste de metodsignaturer som skapats från bindningsgeneratorn ändras för att använda enum. Mer information finns i Skapa uppräkningar.
Problem: Duplicera anpassade EventArgs-typer
Build misslyckades på grund av duplicerade anpassade EventArgs-typer. Ett fel som detta inträffar:
error CS0102: The type `Com.Google.Ads.Mediation.DismissScreenEventArgs' already contains a definition for `p0'
Möjliga orsaker:
Det beror på att det finns en konflikt mellan händelsetyper som kommer från mer än en gränssnittstyp av typen "lyssnare" som delar metoder med identiska namn. Om det till exempel finns två Java-gränssnitt som visas i exemplet nedan skapar generatorn DismissScreenEventArgs såväl MediationBannerListener som MediationInterstitialListener, vilket leder till felet.
// Java:
public interface MediationBannerListener {
void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
void onDismissScreen(MediationInterstitialAdapter p0);
}
Detta är avsiktligt så att långa namn på händelseargumenttyper undviks. För att undvika dessa konflikter krävs viss metadatatransformering. Redigera transformeringar\Metadata.xml och lägg till ett argsType attribut i något av gränssnitten (eller på gränssnittsmetoden):
<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>
Problem: Klassen implementerar inte gränssnittsmetod
Ett felmeddelande skapas som anger att en genererad klass inte implementerar en metod som krävs för ett gränssnitt som den genererade klassen implementerar. Om du tittar på den genererade koden kan du dock se att metoden har implementerats.
Här är ett exempel på felet:
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'
Möjliga orsaker:
Det här är ett problem som uppstår med att binda Java-metoder med samtidiga returtyper. I det här exemplet måste metoden Oauth.Signpost.Http.IHttpRequest.UnWrap() returnera Java.Lang.Object. Metoden Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() har dock en returtyp av HttpURLConnection. Det finns två sätt att åtgärda det här problemet:
Lägg till en partiell klassdeklaration för
HttpURLConnectionRequestAdapteroch implementeraIHttpRequest.Unwrap()explicit.namespace Oauth.Signpost.Basic { partial class HttpURLConnectionRequestAdapter { Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() { return Unwrap(); } } }Ta bort kovariansen från den genererade C#-koden. Detta innebär att du lägger till följande transformering till transformeringar\Metadata.xml vilket gör att den genererade C#-koden har en returtyp av
Java.Lang.Object:<attr path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@name='unwrap']" name="managedReturn">Java.Lang.Object </attr>
Problem: Namnkollisioner på inre klasser/egenskaper
Motstridig synlighet för ärvda objekt.
I Java krävs det inte att en härledd klass har samma synlighet som dess överordnade. Java kommer bara att åtgärda det åt dig. I C# måste det vara explicit, så du måste se till att alla klasser i hierarkin har rätt synlighet. I följande exempel visas hur du ändrar ett Java-paketnamn från com.evernote.android.job till 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>
Problem: Ett .so-bibliotek som krävs av bindningen läses inte in
Vissa bindningsprojekt kan också vara beroende av funktioner i ett .so-bibliotek . Det är möjligt att .NET för Android inte automatiskt läser in .so-biblioteket . När den omslutna Java-koden körs misslyckas .NET för Android med att göra JNI-anropet och felmeddelandet java.lang.UnsatisfiedLinkError: Den interna metoden hittades inte: visas i logcat-ut för programmet.
Korrigeringen för detta är att manuellt läsa in .so-biblioteket med ett anrop till Java.Lang.JavaSystem.LoadLibrary. Om du till exempel antar att ett .NET för Android-projekt har delat bibliotek libpocketsphinx_jni.so som ingår i bindningsprojektet med en byggåtgärd av EmbeddedNativeLibrary, läser följande kodfragment (körs innan du använder det delade biblioteket) in .so-biblioteket :
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");