Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Das Binden einer Android-Bibliotheksdatei (AAR- oder JAR-Datei) ist meistens kompliziert. In der Regel ist ein zusätzlicher Aufwand erforderlich, um Probleme zu beheben, die sich aufgrund der Unterschiede zwischen Java und .NET ergeben. Diese Probleme verhindern, dass .NET für Android die Android-Bibliothek bindet und sich selbst als Fehlermeldungen im Buildprotokoll darstellt. Diese Anleitung enthält einige Tipps zur Problembehandlung, eine Liste der häufigeren Probleme/Szenarios sowie mögliche Lösungen für eine erfolgreiche Bindung der Android-Bibliothek.
Beim Binden einer vorhandenen Android-Bibliothek müssen folgende Punkte beachtet werden:
Die externen Abhängigkeiten für die Bibliothek – Alle Java-Abhängigkeiten, die von der Android-Bibliothek benötigt werden, müssen im .NET für Android-Projekt über ein NuGet-Paket oder als AndroidLibrary enthalten sein.
Die Android-API-Ebene, auf die die Android-Bibliothek ausgerichtet ist – Es ist nicht möglich, die Android-API-Ebene zu "downgrade". Stellen Sie sicher, dass das .NET für Android-Bindungsprojekt auf die gleiche API-Ebene (oder höher) wie die Android-Bibliothek ausgerichtet ist.
Tipp
Das GitHub-Repositorywiki "Bindungstooling" ist eine großartige Ressource und enthält zusätzliche Informationen zur Problembehandlung, die bei bestimmten Fällen hilfreich sein können.
Der erste Schritt zur Problembehandlung bei der Bindung einer .NET für Android-Bibliothek besteht darin, die MsBuild-Diagnoseausgabe zu aktivieren. Nachdem Sie die Diagnoseausgabe aktiviert haben, erstellen Sie das .NET für Android-Bindungsprojekt neu, und überprüfen Sie das Buildprotokoll, um Hinweise auf die Ursache des Problems zu finden.
Es kann sich auch als hilfreich erweisen, die Android-Bibliothek zu dekompilieren und die Typen und Methoden zu untersuchen, die .NET für Android zu binden versucht. Dies wird weiter unten in dieser Anleitung ausführlicher beschrieben.
Dekompilieren einer Android-Bibliothek
Die Überprüfung der Klassen und Methoden der Java-Klassen kann wertvolle Informationen liefern, die beim Binden einer Bibliothek von Nutzen sind. JD-GUI ist ein grafisches Hilfsprogramm, das Java-Quellcode aus den CLASS-Dateien anzeigen kann, die in einer JAR-Datei enthalten sind.
Um eine Android-Bibliothek zu dekompilieren, öffnen Sie die JAR Datei mit dem Java Decompiler. Wenn es sich bei der Bibliothek um eine . AAR-Datei , der Java-Quellcode befindet sich im classes.jar Eintrag der Archivdatei. Der folgende Beispielscreenshot veranschaulicht die Verwendung von JD-GUI zum Analysieren der Picasso-JAR:
Untersuchen Sie den Quellcode, nachdem Sie die Android-Bibliothek dekompiliert haben. Suchen Sie generell nach:
Klassen mit Merkmalen der Verschleierung – Zu den Merkmalen verschleierter Klassen gehören:
- Der Klassenname enthält ein $, z. B. a$.class.
- Der Klassenname besteht ausschließlich aus Kleinbuchstaben, z. B. a.class.
importAnweisungen für nicht referenzierte Bibliotheken – Identifizieren Sie die nicht referenzierte Bibliothek, und fügen Sie diese Abhängigkeiten dem .NET für Android-Bindungsprojekt mit einer entsprechenden Bindung aus NuGet oder mit einer Buildaktion von AndroidLibrary hinzu.
Hinweis
Das Dekompilieren einer Java-Bibliothek ist möglicherweise unzulässig oder unterliegt aufgrund von lokalen Gesetzen oder der Lizenz, unter der die Java-Bibliothek veröffentlicht wurde, rechtlichen Beschränkungen. Nehmen Sie ggf. die Dienste eines spezialisierten Juristen in Anspruch, bevor Sie versuchen, eine Java-Bibliothek zu dekompilieren und den Quellcode zu untersuchen.
Überprüfen Sie api.xml
Im Rahmen der Erstellung eines Bindungsprojekts generiert .NET für Android einen XML-Dateinamen obj/Debug/api.xml:
Diese Datei enthält eine Liste aller Java-APIs, die .NET für Android zu binden versucht. Der Inhalt dieser Datei kann hilfreich sein, um fehlende Typen oder Methoden bzw. doppelte Bindungen zu ermitteln. Obwohl die Überprüfung dieser Datei mühsam und zeitaufwändig ist, kann sie Hinweise auf mögliche Ursachen für Bindungsprobleme liefern. Beispielsweise kann api.xml zeigen, dass eine Eigenschaft einen ungeeigneten Typ zurückgibt oder zwei Typen mit demselben verwalteten Namen vorhanden sind.
Bekannte Probleme
In diesem Abschnitt werden einige der häufigsten Fehlermeldungen oder Symptome aufgelistet, die beim Binden einer Android-Bibliothek auftreten können.
Problem: Fehlende C#-Typen in generierter Ausgabe.
Die DLL-Bindung wird kompiliert, es fehlen jedoch einige Java-Typen, oder der generierte C#-Quellcode kompiliert nicht aufgrund eines Fehlers, der darauf hinweist, dass Typen fehlen.
Mögliche Ursachen:
Dieser Fehler kann aus verschiedenen Gründen auftreten, die nachstehend aufgelistet sind:
Die gebundene Bibliothek kann auf eine zweite Java-Bibliothek verweisen. Wenn die öffentliche API für die gebundene Bibliothek Typen aus der zweiten Bibliothek verwendet, müssen Sie eben falls auf eine verwaltete Bindung für die zweite Bibliothek verweisen.
Java ermöglicht das Ableiten einer öffentlichen Klasse von einer nicht öffentlichen Klasse, dies wird aber in .NET nicht unterstützt. Da der Bindungsgenerator keine Bindungen für nicht öffentliche Klassen generiert, können abgeleitete Klassen wie diese nicht ordnungsgemäß generiert werden. Um dieses Problem zu beheben, entfernen Sie entweder den Metadateneintrag für die abgeleiteten Klassen mit „remove-node“ in Metadata.xml, oder korrigieren Sie die Metadaten, die die nicht öffentliche Klasse als öffentlich festlegen. Obwohl die letzte Lösung die Bindung so erstellt, damit der C#-Quellcode kompiliert wird, sollte die nicht öffentliche Klasse nicht verwendet werden.
Zum Beispiel:
<attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']" name="visibility">public</attr>Tools, die Java-Bibliotheken verschleiern, beeinträchtigen möglicherweise den .NET für Android-Bindungsgenerator und seine Fähigkeit zum Generieren von C#-Wrapperklassen. Der folgende Codeausschnitt zeigt, wie Metadata.xml aktualisiert werden muss, um die Verschleierung eines Klassennamens aufzuheben:
<attr path="/api/package[@name='{package_name}']/class[@name='{name}']" name="obfuscated">false</attr>
Problem: Die generierte C#-Quelle wird aufgrund von Parametertypkonflikten nicht erstellt.
Der generierte C#-Quellcode wird nicht kompiliert. Die Parametertypen der überschriebenen Methode stimmen nicht überein.
Mögliche Ursachen:
.NET für Android enthält eine Vielzahl von Java-Feldern, die den Enumerationen in den C#-Bindungen zugeordnet sind. Diese können Typinkompatibilitäten in den generierten Bindungen verursachen. Um dieses Problem zu beheben, müssen die vom Binding-Generator erstellten Methodensignaturen so geändert werden, dass die Enums verwendet werden. Weitere Informationen finden Sie unter Erstellen von Enumerationen.
Problem: Doppelte benutzerdefinierte EventArgs-Typen
Der Buildvorgang schlägt aufgrund doppelter benutzerdefinierter EventArgs-Typen fehl. Die Fehlermeldung sieht in etwa folgendermaßen aus:
error CS0102: The type `Com.Google.Ads.Mediation.DismissScreenEventArgs' already contains a definition for `p0'
Mögliche Ursachen:
Dies liegt daran, dass ein Konflikt zwischen Ereignistypen besteht, die von mehreren Schnittstellenlistenertypen stammen, die Methoden mit identischen Namen aufweisen. Wenn beispielsweise wie im folgenden Beispiel zwei Java-Schnittstellen vorhanden sind, erstellt der Generator DismissScreenEventArgs für MediationBannerListener und MediationInterstitialListener, was zu einem Fehler führt.
// Java:
public interface MediationBannerListener {
void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
void onDismissScreen(MediationInterstitialAdapter p0);
}
Dies ist systembedingt, um sehr lange Namen für Ereignisargumenttypen zu vermeiden. Um diese Konflikte zu vermeiden, ist eine Metadatentransformation erforderlich. Bearbeiten Sie Transforms\Metadata.xml, und fügen Sie ein argsType-Attribut für beide Schnittstellen (oder für die Schnittstellenmethode) hinzu:
<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: Klasse implementiert keine Schnittstellenmethode
Es wird eine Fehlermeldung mit dem Hinweis erzeugt, dass eine Methode, die für eine Schnittstelle erforderlich ist, die die generierte Klasse implementiert, von der generierten Klasse nicht implementiert wird. Wenn Sie den generierten Code betrachten, sehen Sie jedoch, dass die-Methode implementiert ist.
Hier sehen Sie ein Beispiel für den Fehler:
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ögliche Ursachen:
Dieses Problem tritt bei der Bindung von Java-Methoden mit kovarianten Rückgabetypen auf. In diesem Beispiel muss die Methode Oauth.Signpost.Http.IHttpRequest.UnWrap()Java.Lang.Object zurückgeben. Die Methode Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() gibt jedoch den Typ HttpURLConnection zurück. Es gibt zwei Möglichkeiten, dieses Problem zu beheben:
Fügen Sie eine partielle Klassendeklaration für
HttpURLConnectionRequestAdapterhinzu, und implementieren SieIHttpRequest.Unwrap()explizit:namespace Oauth.Signpost.Basic { partial class HttpURLConnectionRequestAdapter { Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() { return Unwrap(); } } }Entfernen Sie die Kovarianz aus dem generierten C#-Code. Dazu muss die folgende Transformation in Transforms\Metadata.xml hinzugefügt werden, die bewirkt, dass der generierte C#-Code den Rückgabetyp
Java.Lang.Objectaufweist:<attr path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@name='unwrap']" name="managedReturn">Java.Lang.Object </attr>
Problem: Namenskonflikte bei inneren Klassen / Eigenschaften
Widersprüchliche Sichtbarkeit bei geerbten Objekten.
In Java muss eine abgeleitete Klasse nicht die gleiche Sichtbarkeit wie das zugehörige übergeordnete Element aufweisen. Java löst dies automatisch. In C# muss dies explizit erfolgen. Sie müssen also sicherstellen, dass alle Klassen in der Hierarchie die entsprechende Sichtbarkeit aufweisen. Im folgenden Beispiel wird gezeigt, wie ein Java-Paketname von com.evernote.android.job in Evernote.AndroidJob geändert wird:
<!-- 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: Eine .so Bibliothek, die für die Bindung erforderlich ist, wird nicht geladen.
Einige Bindungsprojekte können auch von Funktionen in einer .so-Bibliothek abhängen. Es ist möglich, dass .NET für Android die .so-Bibliothek nicht automatisch lädt. Wenn der eingeschlossene Java-Code ausgeführt wird, wird .NET für Android mit dem JNI-Aufruf scheitern und die Fehlermeldung java.lang.UnsatisfiedLinkError: Native method not found: wird in der Logcat-Ausgabe der Anwendung erscheinen.
Dieses Problem kann behoben werden, indem die .so-Bibliothek manuell über einen Aufruf von Java.Lang.JavaSystem.LoadLibrary geladen wird. Angenommen, ein .NET für Android-Projekt hat eine freigegebene Bibliothek libpocketsphinx_jni.so im Bindungsprojekt mit einer Buildaktion von EmbeddedNativeLibrary enthalten, wird der folgende Codeausschnitt (ausgeführt vor der Verwendung der freigegebenen Bibliothek) die .so-Bibliothek laden:
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");