Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Het binden van een Android-bibliotheek (een .aar - of een .jar)-bestand is zelden een eenvoudige affaire; het vereist meestal extra inspanningen om problemen te beperken die het gevolg zijn van de verschillen tussen Java en .NET. Deze problemen verhinderen dat .NET voor Android de Android-bibliotheek bindt en zichzelf presenteert als foutberichten in het buildlogboek. Deze handleiding bevat enkele tips voor het oplossen van de problemen, een lijst met enkele veelvoorkomende problemen/scenario's en biedt mogelijke oplossingen voor het verbinden van de Android-bibliotheek.
Wanneer u een bestaande Android-bibliotheek bindt, moet u rekening houden met de volgende punten:
De externe afhankelijkheden voor de bibliotheek : alle Java-afhankelijkheden die vereist zijn voor de Android-bibliotheek, moeten worden opgenomen in het .NET voor Android-project via een NuGet-pakket of als AndroidLibrary.
Het Niveau van de Android-API waarop de Android-bibliotheek zich richt : het is niet mogelijk om het Android-API-niveau te 'downgraden'; zorg ervoor dat het bindingsproject voor .NET voor Android hetzelfde API-niveau (of hoger) als de Android-bibliotheek heeft.
Aanbeveling
De wiki voor de GitHub-opslagplaats voor bindingsprogramma's is een uitstekende resource en bevat aanvullende informatie over probleemoplossing die kan helpen bij specifieke gevallen.
De eerste stap voor het oplossen van problemen met het binden van een .NET voor Android-bibliotheek is het inschakelen van diagnostische MSBuild-uitvoer. Nadat u de diagnostische uitvoer hebt ingeschakeld, bouwt u het bindingsproject .NET voor Android opnieuw op en bekijkt u het buildlogboek om aanwijzingen te vinden over de oorzaak van het probleem.
Het kan ook nuttig zijn om de Android-bibliotheek te decompileren en de typen en methoden te onderzoeken die .NET voor Android probeert te binden. Dit wordt verderop in deze handleiding nader besproken.
Een Android-bibliotheek decompileren
Het inspecteren van de klassen en methoden van de Java-klassen kan waardevolle informatie bieden die helpt bij het binden van een bibliotheek. JD-GUI is een grafisch hulpprogramma dat Java-broncode kan weergeven uit de CLASS-bestanden in een JAR.
Als u een Android-bibliotheek wilt decompileren, opent u de . JAR-bestand met de Java-decompiler. Als de bibliotheek een .AAR-bestand is, zal de Java-broncode zich bevinden in de classes.jar vermelding van het archiefbestand. Hier volgt een voorbeeldschermopname van het gebruik van JD-GUI om de Picasso JAR te analyseren:
Nadat u de Android-bibliotheek hebt gedecompileerd, controleert u de broncode. Over het algemeen zoekt u naar:
Klassen met kenmerken van obfuscatie – Kenmerken van geobfusceerde klassen zijn onder andere:
- De klassenaam bevat een $, bijvoorbeeld a$.class
- De klassenaam bestaat volledig uit onderkastletters, dat wil zeggen a.class
importverklaringen voor niet-verwezen bibliotheken – Identificeer de niet-verwezen bibliotheek en voeg die afhankelijkheden toe aan het .NET bindingsproject voor Android met behulp van een geschikte binding van NuGet of met een Build Action van AndroidLibrary.
Opmerking
Het ontcompileren van een Java-bibliotheek is mogelijk verboden of onderhevig aan wettelijke beperkingen op basis van lokale wetten of de licentie waaronder de Java-bibliotheek is gepubliceerd. Indien nodig moet u de services van een juridische professional inschakelen voordat u probeert een Java-bibliotheek te decompileren en de broncode inspecteren.
api.xml controleren
Als onderdeel van het bouwen van een bindingsproject genereert .NET voor Android een XML-bestandsnaam obj/Debug/api.xml:
Dit bestand bevat een lijst met alle Java-API's die .NET voor Android probeert te binden. De inhoud van dit bestand kan helpen bij het identificeren van ontbrekende typen of methoden, dubbele binding. Hoewel de inspectie van dit bestand saai en tijdrovend is, kan het aanwijzingen geven over wat de bindingsproblemen kan veroorzaken. api.xml kan bijvoorbeeld aantonen dat een eigenschap een ongepast type retourneert of dat er twee typen zijn die dezelfde beheerde naam delen.
Bekende problemen
In deze sectie worden enkele veelvoorkomende foutberichten of symptomen vermeld die kunnen optreden bij het proberen een Android-bibliotheek te binden.
Probleem: Ontbrekende C#-typen in gegenereerde uitvoer.
De binding .dll wordt gebouwd, maar sommige Java-typen ontbreken, of de gegenereerde C#-bron kan niet worden gebouwd door een fout die ontbrekende typen aangeeft.
Mogelijke oorzaken:
Deze fout kan om verschillende redenen optreden, zoals hieronder wordt vermeld:
De bibliotheek die afhankelijk is, kan verwijzen naar een tweede Java-bibliotheek. Als de openbare API voor de afhankelijke bibliotheek gebruikmaakt van typen uit de tweede bibliotheek, moet u ook verwijzen naar een beheerde binding voor de tweede bibliotheek.
Met Java kan een openbare klasse worden afgeleid van een niet-openbare klasse, maar dit wordt niet ondersteund in .NET. Omdat de bindingsgenerator geen bindingen genereert voor niet-openbare klassen, kunnen afgeleide klassen zoals deze niet correct worden gegenereerd. U lost dit op door de metagegevensvermelding voor die afgeleide klassen te verwijderen met behulp van het remove-knooppunt in Metadata.xmlof de metagegevens op te lossen die de niet-openbare klasse openbaar maken. Hoewel de laatste oplossing de binding maakt zodat de C#-bron wordt gebouwd, mag de niet-openbare klasse niet worden gebruikt.
Voorbeeld:
<attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']" name="visibility">public</attr>Hulpprogramma's waarmee Java-bibliotheken worden verborgen, kunnen de .NET voor Android Binding Generator verstoren en de mogelijkheid om C#-wrapperklassen te genereren. Het volgende fragment laat zien hoe je Metadata.xml bijwerkt om een klassenaam te deobfusceren:
<attr path="/api/package[@name='{package_name}']/class[@name='{name}']" name="obfuscated">false</attr>
Probleem: de gegenereerde C#-bron wordt niet gebouwd omdat het parametertype niet overeenkomt
De gegenereerde C#-broncode kan niet worden opgebouwd. De parametertypen van de overschreven methode komen niet overeen.
Mogelijke oorzaken:
.NET voor Android bevat verschillende Java-velden die zijn toegewezen aan opsommingen in de C#-bindingen. Dit kan leiden tot incompatibiliteit van het type in de gegenereerde bindingen. Om dit op te lossen, moeten de methodehandtekeningen die zijn gemaakt op basis van de bindingsgenerator worden gewijzigd om de opsommingen te kunnen gebruiken. Zie Opsommingen maken voor meer informatie.
Probleem: Aangepaste EventArgs-typen dupliceren
De build mislukt vanwege dubbelgebruik van aangepaste EventArgs-typen. Er treedt een fout zoals deze op:
error CS0102: The type `Com.Google.Ads.Mediation.DismissScreenEventArgs' already contains a definition for `p0'
Mogelijke oorzaken:
Dit komt doordat er een conflict is tussen gebeurtenistypen die afkomstig zijn van meer dan één interface -listenertype dat methoden met identieke namen deelt. Als er bijvoorbeeld twee Java-interfaces zijn, zoals te zien is in het onderstaande voorbeeld, maakt de generator DismissScreenEventArgs voor zowel MediationBannerListener als MediationInterstitialListener, wat resulteert in de fout.
// Java:
public interface MediationBannerListener {
void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
void onDismissScreen(MediationInterstitialAdapter p0);
}
Dit is standaard, zodat lange namen voor gebeurtenisargumenttypen worden vermeden. Om deze conflicten te voorkomen, is een bepaalde metagegevenstransformatie vereist. Bewerk transformaties\Metadata.xml en voeg een argsType kenmerk toe aan een van de interfaces (of op de interfacemethode):
<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>
Probleem: De klasse implementeert geen interfacemethode
Er wordt een foutbericht gegenereerd dat aangeeft dat een gegenereerde klasse geen methode implementeert die vereist is voor een interface die door de gegenereerde klasse wordt geïmplementeerd. Als u echter de gegenereerde code bekijkt, ziet u dat de methode is geïmplementeerd.
Hier volgt een voorbeeld van de fout:
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'
Mogelijke oorzaken:
Dit is een probleem dat optreedt bij het binden van Java-methoden met covariante retourtypen. In dit voorbeeld moet de methode Oauth.Signpost.Http.IHttpRequest.UnWrap() een Java.Lang.Object retourneren. De methode Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() heeft echter een retourtype HttpURLConnection. Er zijn twee manieren om dit probleem op te lossen:
Voeg een gedeeltelijke klassedeclaratie toe voor
HttpURLConnectionRequestAdapteren implementeerIHttpRequest.Unwrap()deze expliciet:namespace Oauth.Signpost.Basic { partial class HttpURLConnectionRequestAdapter { Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() { return Unwrap(); } } }Verwijder de covariantie uit de gegenereerde C#-code. Dit omvat het toevoegen van de volgende transformatie aan transformaties\Metadata.xml waardoor de gegenereerde C#-code een retourtype heeft:
Java.Lang.Object<attr path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@name='unwrap']" name="managedReturn">Java.Lang.Object </attr>
Probleem: Naamconflicten van interne klassen/eigenschappen
Conflicterende zichtbaarheid van geërfde objecten.
In Java is het niet vereist dat een afgeleide klasse dezelfde zichtbaarheid heeft als de bovenliggende klasse. Java lost dat gewoon voor u op. In C# moet dat expliciet zijn, dus moet u ervoor zorgen dat alle klassen in de hiërarchie de juiste zichtbaarheid hebben. In het volgende voorbeeld ziet u hoe u de naam van een Java-pakket wijzigt in com.evernote.android.jobEvernote.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>
Probleem: Een .so-bibliotheek die door de binding is vereist, wordt niet geladen
Sommige bindingsprojecten zijn mogelijk ook afhankelijk van functionaliteit in een .so-bibliotheek . Het is mogelijk dat .NET voor Android de .so-bibliotheek niet automatisch laadt. Wanneer de verpakte Java-code wordt uitgevoerd, kan .NET voor Android de JNI-aanroep niet uitvoeren en wordt het foutbericht java.lang.UnsatisfiedLinkError: Systeemeigen methode niet gevonden: wordt weergegeven in de logcat-out voor de toepassing.
De oplossing hiervoor is om de .so-bibliotheek handmatig te laden met een aanroep naar Java.Lang.JavaSystem.LoadLibrary. Stel dat een .NET voor Android-project de gedeelde bibliotheek libpocketsphinx_jni.so heeft opgenomen in het bindingsproject met een buildactie van EmbeddedNativeLibrary, dan wordt de .so-bibliotheek geladen door het volgende fragment (uitgevoerd voordat de gedeelde bibliotheek wordt gebruikt):
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");