Migration von Xamarin.Android-Bindungsprojekten
In .NET gibt es kein Konzept für ein Android-Bindungsprojekt als separaten Projekttyp. Alle MSBuild-Elementgruppen oder Build-Aktionen, die in Xamarin.Android-Bindungsprojekten funktionieren, werden durch eine .NET for Android-App oder -Bibliothek unterstützt.
So migrieren Sie eine Xamarin.Android-Bindungsbibliothek zu einer .NET for Android-Klassenbibliothek:
Erstellen Sie in Visual Studio ein neues Android Java Bibliotheks-Bindungsprojekt mit demselben Namen wie Ihr Xamarin.Android Bindungsprojekt:
Wenn Sie die Projektdatei öffnen, wird bestätigt, dass es sich um ein .NET-Projekt im SDK-Format handelt:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0-android</TargetFramework> <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> </Project>
Hinweis
Die Projektdatei für eine Android-Bindungsbibliothek ist identisch mit der Projektdatei für eine Android-Klassenbibliothek.
Fügen Sie Ihr Java-Archiv (JAR) oder Android-Archiv (AAR) zum Projekt hinzu und stellen Sie sicher, dass die Build-Aktion auf AndroidLibrary festgelegt ist.
Kopieren Sie alle Transformationen oder Ergänzungen aus Ihrer Xamarin.Android-Bindungsbibliothek.
Nicht unterstützte veraltete Optionen
Die folgenden veralteten Optionen werden nicht mehr unterstützt. Die unterstützten Optionen sind bereits seit mehreren Jahren verfügbar. Die einfachste Migrationsmöglichkeit besteht darin, Ihre aktuellen Projekte mit diesen Optionen zu aktualisieren und zu testen, bevor Sie sie zu .NET migrieren.
AndroidClassParser
jar2xml
ist keine gültige Option mehr für die Eigenschaft $(AndroidClassParser)
. class-parse
ist nun die Standardeinstellung und die einzige unterstützte Option.
class-parse
verwendet viele neue und moderne Funktionen, die in jar2xml
nicht verfügbar sind, wie z. B.:
- Automatische Parameternamen für Klassenmethoden (wenn Ihr Java-Code mit
javac -parameters
kompiliert wurde). - Kotlin-Support.
- Support für statische/standardmäßige Schnittstellenmember (DIM).
- Support für Anmerkungen zu Nullable-Verweistypen (NRT) in Java.
AndroidCodegenTarget
XamarinAndroid
ist keine gültige Option mehr für die Eigenschaft $(AndroidCodegenTarget)
. XAJavaInterop1
ist nun die Standardeinstellung und die einzige unterstützte Option.
Wenn Ihre Additions
-Dateien manuell gebundenen Code enthalten, der mit dem generierten Bindungscode interagiert, muss dieser aktualisiert werden, um XAJavaInterop1
kompatibel zu sein.
Standardmäßige Dateieinbindung
Mit der folgenden Dateistruktur:
Transforms/
Metadata.xml
foo.jar
Transforms\*.xml
-Dateien sind automatisch als @(TransformFile)
-Element eingeschlossen, und .jar
/.aar
-Dateien sind automatisch als @(AndroidLibrary)
-Element eingeschlossen. Dies bindet C#-Typen für die in foo.jar
gefundenen Java-Typen unter Verwendung der Metadatenkorrekturen von Transforms\Metadata.xml
.
Das Standard-Globbingverhalten von Android-Dateien ist in AutoImport.props definiert. Sie können dieses Verhalten für Android-Elemente deaktivieren, indem Sie die Eigenschaft $(EnableDefaultAndroidItems)
auf false
setzen. Sie können auch das gesamte Standardverhalten der Elemente deaktivieren, indem Sie die Eigenschaft $(EnableDefaultItems)
auf false
setzen.
Unerwünschte .jar
- oder .aar
-Dateien können mit den Standard-Platzhaltern eingeschlossen werden. Der folgende C#-Compilerfehler resultiert z. B. aus dem unbeabsichtigten Binden einer AndroidStudio\gradle\wrapper\gradle-wrapper.jar
-Datei:
Org.Gradle.Cli.AbstractCommandLineConverter.cs(11,89): error CS0535: 'Download' does not implement interface member 'IDownload.Download(URI, File)'
Org.Gradle.Wrapper.Download.cs(10,60): error CS0535: 'AbstractCommandLineConverter' does not implement interface member 'ICommandLineConverter.Convert(ParsedCommandLine, Object)'
Um dieses Problem zu beheben, können Sie die betreffende Datei aus Ihrer Projektdatei entfernen:
<ItemGroup>
<AndroidLibrary Remove="AndroidStudio\gradle\wrapper\gradle-wrapper.jar" />
</ItemGroup>
Alternativ können Sie alle Dateien in einem Ordner ausschließen:
<AndroidLibrary Remove="AndroidStudio\**\*" />
Neue Artikelgruppennamen
<AndroidLibrary>
ist jetzt die empfohlene Artikelgruppe für alle .jar
- und .aar
-Dateien. In Xamarin.Android wurden die folgenden Artikelgruppen verwendet, die stattdessen Artikelmetadaten verwenden können, um dasselbe Ergebnis zu erzielen:
Legacy-Artikelgruppe | Neue Artikelgruppe | Artikelmetadaten | Legacy-Projekttyp |
---|---|---|---|
AndroidAarLibrary |
AndroidLibrary |
Bind="false" |
Anwendung |
AndroidJavaLibrary |
AndroidLibrary |
Bind="false" |
Anwendungs- oder Klassenbibliothek |
EmbeddedJar |
AndroidLibrary |
Nicht zutreffend | Bindungsprojekt |
EmbeddedReferenceJar |
AndroidLibrary |
Bind="false" |
Bindungsprojekt |
InputJar |
AndroidLibrary |
Pack="false" |
Bindungsprojekt |
LibraryProjectZip |
AndroidLibrary |
Nicht zutreffend | Bindungsprojekt |
Ziehen Sie eine .aar
- oder eine .jar
-Datei in Betracht, an der Sie nicht interessiert sind, eine C#-Bindung einzugeben. Dies ist üblich für Fälle, in denen Sie über Java- oder Kotlin-Abhängigkeiten verfügen, die Sie nicht von C# aufrufen müssen. In diesem Fall können Sie die Bind
-Metadaten auf false
festlegen. Standardmäßig wird die Datei von den Standardplatzhaltern ausgewählt. Sie können auch das Update
-Attribut verwenden, um die Bind
-Metadaten festzulegen:
<ItemGroup>
<AndroidLibrary Update="foo.jar" Bind="false">
</ItemGroup>
In einem Android-Klassenbibliotheksprojekt würde dies die .jar
-Datei wie folgt innerhalb des resultierenden NuGet-Pakets neu verteilen. In einem Android-Anwendungsprojekt würde dies die .jar
-Datei in die resultierende .apk
- oder .aab
-Datei einschließen. Keine würde eine C#-Bindung für diese Java-Bibliothek enthalten.
Eingebettete JAR/AAR-Dateien
In Xamarin.Android wurde Java .jar
oder .aar
häufig als Ressource in .dll
eingebettet. Dies hatte jedoch langsame Builds zur Folge, da jedes .dll
geöffnet und nach Java-Code durchsucht werden musste. Wurde Java-Code gefunden, musste er zur Verwendung auf die Festplatte extrahiert werden.
In .NET ist der Java-Code nicht mehr in die .dll
eingebettet. Der App-Buildprozess schließt automatisch alle .jar
- oder .aar
-Dateien ein, die sich im selben Verzeichnis wie eine referenzierte .dll
-Datei befinden.
Wenn ein Projekt eine Bindung über <PackageReference>
oder <ProjectReference>
verweist, funktioniert alles und es sind keine zusätzlichen Überlegungen erforderlich. Wenn ein Projekt jedoch eine Bindung über <Reference>
verweist, muss sich die .jar
/.aar
neben der .dll
befinden. Das bedeutet für den folgenden Verweis:
<Reference Include="MyBinding.dll" />
Ein Verzeichnis wie im folgenden Beispiel wird nicht funktionieren:
lib/
MyBinding.dll
Vielmehr muss das Verzeichnis auch den systemeigenen Code enthalten:
lib/
MyBinding.dll
mybinding.jar
Migrationsüberlegungen
Es gibt mehrere neue Funktionen, die standardmäßig eingestellt sind, um Bindungen zu erzeugen, die besser zu ihren Java-Entsprechungen passen. Wenn Sie jedoch ein bestehendes Bindungsprojekt migrieren, können diese Funktionen Bindungen erzeugen, die nicht API-kompatibel zu Ihren bestehenden Bindungen sind. Um die Kompatibilität zu gewährleisten, sollten Sie diese neuen Funktionen deaktivieren oder ändern.
Schnittstellenkonstanten
Traditionell ist es in C# nicht erlaubt, Konstanten in einem interface
zu deklarieren, was in Java ein gängiges Muster ist:
public interface Foo {
public static int BAR = 1;
}
Dieses Muster wurde bisher durch die Erstellung einer Alternative class
unterstützt, die die Konstanten enthält:
public abstract class Foo : Java.Lang.Object
{
public static int Bar = 1;
}
Mit C# 8 werden diese Konstanten auf interface
gesetzt:
public interface IFoo
{
public static int Bar = 1;
}
Dies hat jedoch zur Folge, dass die alternative Klasse, von der der vorhandene Code abhängig sein könnte, nicht mehr generiert wird.
Wenn Sie die Eigenschaft $(AndroidBoundInterfacesContainConstants)
in Ihrer Projektdatei auf false
setzen, wird das Legacyverhalten wiederhergestellt.
Geschachtelte Schnittstellentypen
Traditionell ist es in C# nicht erlaubt, geschachtelte Typen in einem interface
zu deklarieren, während dies in Java erlaubt ist:
public interface Foo {
public class Bar { }
}
Dieses Muster wurde unterstützt, indem der geschachtelte Typ in einen Typ der obersten Ebene mit einem generierten Namen verschoben wurde, der sich aus dem Namen der Schnittstelle und des geschachtelten Typs zusammensetzt:
public interface IFoo { }
public class IFooBar : Java.Lang.Object { }
Mit C# 8 können geschachtelte Typen in interface
platziert werden:
public interface IFoo
{
public class Bar : Java.Lang.Object { }
}
Dies hat jedoch zur Folge, dass die oberste Klasse, von der der vorhandene Code abhängig sein könnte, nicht mehr generiert wird.
Wenn Sie die Eigenschaft $(AndroidBoundInterfacesContainTypes)
in Ihrer Projektdatei auf false
setzen, wird das Legacyverhalten wiederhergestellt.
Wenn Sie einen hybriden Ansatz verwenden möchten, z. B. um bestehende geschachtelte Typen in einen Typ der obersten Ebene zu verschieben, aber weiterhin zukünftige geschachtelte Typen zuzulassen, können Sie dies auf Ebene interface
festlegen, indem Sie metadata
verwenden, um das Attribut unnest
zu setzen. Die Einstellung true
bewirkt, dass alle geschachtelten Typen „unverschachtelt“ werden (Legacyverhalten):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>
Die Einstellung false
bewirkt, dass geschachtelte Typen in interface
geschachtelt bleiben (.NET-Verhalten):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>
Mit diesem Ansatz können Sie die Eigenschaft $(AndroidBoundInterfacesContainTypes)
auf true
belassen und unnest
auf true
für jedes interface
mit geschachtelten Typen setzen, das Sie derzeit haben. Diese bleiben immer Typen der obersten Ebene, während alle später eingeführten geschachtelten Typen geschachtelt werden.
Statische und standardmäßige Schnittstellenmember (DIM)
Normalerweise ist es in C# nicht erlaubt, dass Schnittstellen static
-Member und default
-Methoden enthalten:
public interface Foo {
public static void Bar () { ... }
public default void Baz () { ... }
}
Statische Member auf Schnittstellen wurden durch Verschieben in ein gleichgeordnetes Element unterstützt class
:
public interface IFoo { }
public class Foo
{
public static void Bar () { ... }
}
default
Schnittstellenmethoden wurden normalerweise nicht gebunden, da sie nicht benötigt wurden und es kein C#-Konstrukt gab, das sie unterstützte.
Mit C# 8 werden static
- und default
-Members auf Schnittstellen unterstützt, genau wie bei der Java-Schnittstelle:
public interface IFoo
{
public static void Bar () { ... }
public default void Baz () { ... }
}
Dies bedeutet jedoch, dass das alternative gleichgeordnete Element class
mit static
-Members nicht mehr generiert wird.
Wenn Sie die Eigenschaft $AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods
in Ihrer Projektdatei auf false
setzen, wird das Legacyverhalten wiederhergestellt.
Nullwertfähige Verweistypen
Der Support für Nullwertfähige Verweistypen (Nullable Reference Types, NRT) wurde in Xamarin.Android 11.0 hinzugefügt. Der Support für NRT kann über den Standard-.NET-Mechanismus aktiviert werden:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Da die Standardeinstellung für .NET disable
ist, gilt dies auch für Xamarin.Android-Projekte.
Resource.designer.cs
In Xamarin.Android unterstützten Java-Bindungsprojekte das Generieren einer Resource.designer.cs
-Datei nicht. Diese Datei wird generiert, da es sich bei Bindungsprojekten lediglich um Klassenbibliotheken in .NET handelt. Dies könnte bei der Migration bestehender Projekte eine wichtige Änderung darstellen.
Ein Beispiel für einen Fehler aufgrund dieser Änderung ist, wenn Ihre Bindung eine Klasse mit dem Namen Resource
im Stammnamespace generiert:
error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'
Oder bei AndroidX existieren Projektdateien mit -
im Namen wie androidx.window/window-extensions.csproj
. Dies führt zu dem Stammnamespace window-extensions
und ungültigem C# in Resource.designer.cs
:
error CS0116: A namespace cannot directly contain members such as fields, methods or statements
error CS1514: { expected
error CS1022: Type or namespace definition, or end-of-file expected
Um die Generierung von Resource.designer.cs
zu deaktivieren, setzen Sie die Eigenschaft $(AndroidGenerateResourceDesigner)
in Ihrer Projektdatei auf false
:
<PropertyGroup>
<AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>