Migration d’un projet de liaison Xamarin.Android
Dans .NET, il n’existe aucun concept de projet de liaison Android en tant que type de projet distinct. Les groupes d’éléments MSBuild ou les actions de génération qui fonctionnent dans des projets de liaison Xamarin.Android sont pris en charge via une application ou une bibliothèque .NET pour Android.
Pour migrer une bibliothèque de liaisons Xamarin.Android vers une bibliothèque de classes .NET pour Android :
Dans Visual Studio, créez un projet de liaison de bibliothèques Java Android portant le même nom que votre projet de liaison Xamarin.Android :
L’ouverture du fichier projet confirmera que vous disposez d’un projet de style SDK .NET :
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0-android</TargetFramework> <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> </Project>
Remarque
Le fichier projet d’une bibliothèque de liaisons Android est identique au fichier projet d’une bibliothèque de classes Android.
Ajoutez votre archive Java (JAR) ou Android (AAR) au projet et vérifiez que son action de génération est définie sur AndroidLibrary.
Copiez les transformations ou ajouts à partir de votre bibliothèque de liaisons Xamarin.Android.
Options héritées non prises en charge
Les options héritées suivantes ne sont plus prises en charge. Des alternatives prises en charge sont disponibles depuis plusieurs années, et l’option de migration la plus fluide consiste à mettre à jour et tester vos projets actuels avec ces options avant de les migrer vers .NET.
AndroidClassParser
jar2xml
n’est plus une option valide de la propriété $(AndroidClassParser)
. class-parse
est désormais l’option par défaut et la seule option prise en charge.
class-parse
bénéficie des nombreuses nouvelles fonctionnalités modernes qui n’étaient pas disponibles dans jar2xml
, telles que :
- Noms des paramètres automatiques des méthodes de classe (si votre code Java est compilé avec
javac -parameters
). - Prise en charge Kotlin.
- Prise en charge du membre d’interface statique/par défaut (DIM).
- Prise en charge des annotations de type référence pouvant accepter la valeur Null (NRT) de Java.
AndroidCodegenTarget
XamarinAndroid
n’est plus une option valide de la propriété $(AndroidCodegenTarget)
. XAJavaInterop1
est désormais l’option par défaut et la seule option prise en charge.
Si vos fichiers Additions
contiennent du code écrit manuellement qui interagit avec le code de liaison généré, il peut être nécessaire de le mettre à jour pour qu’il soit compatible avec XAJavaInterop1
.
Inclusion de fichier par défaut
Étant donné la structure de fichier suivante :
Transforms/
Metadata.xml
foo.jar
Des fichiers Transforms\*.xml
sont automatiquement inclus comme élément @(TransformFile)
et des fichiers .jar
/.aar
sont automatiquement inclus comme élément @(AndroidLibrary)
. Cela lie les types C# des types Java trouvés dans foo.jar
à l’aide des correctifs de métadonnées de Transforms\Metadata.xml
.
Le comportement de globbing de fichier associé à un Android par défaut est défini dans AutoImport.props. Ce comportement peut être désactivé sur des éléments Android en définissant la propriété $(EnableDefaultAndroidItems)
sur false
, ou les comportements d’inclusion d’élément par défaut peuvent être désactivés en définissant la propriété $(EnableDefaultItems)
sur false
.
Les fichiers .jar
ou .aar
non souhaités peuvent être inclus avec les caractères génériques par défaut. Par exemple, les erreurs du compilateur C# suivantes proviennent d’un fichier AndroidStudio\gradle\wrapper\gradle-wrapper.jar
lié involontairement :
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)'
Pour résoudre ce problème, vous pouvez supprimer le fichier spécifique dans votre fichier projet :
<ItemGroup>
<AndroidLibrary Remove="AndroidStudio\gradle\wrapper\gradle-wrapper.jar" />
</ItemGroup>
Vous pouvez également exclure tous les fichiers d’un dossier :
<AndroidLibrary Remove="AndroidStudio\**\*" />
Nouveaux noms de groupes d’éléments
<AndroidLibrary>
est désormais le groupe d’éléments qu’il est recommandé d’utiliser pour les fichiers .jar
et .aar
. Dans Xamarin.Android, les groupes d’éléments suivants, qui peuvent utiliser à la place des métadonnées d’élément pour obtenir le même résultat, ont été utilisés :
Groupe d’éléments hérité | Nouveau groupe d’éléments | Métadonnées d’élément | Type de projet hérité |
---|---|---|---|
AndroidAarLibrary |
AndroidLibrary |
Bind="false" |
Application |
AndroidJavaLibrary |
AndroidLibrary |
Bind="false" |
Bibliothèque de classes ou d’applications |
EmbeddedJar |
AndroidLibrary |
n/a | Projet de liaison |
EmbeddedReferenceJar |
AndroidLibrary |
Bind="false" |
Projet de liaison |
InputJar |
AndroidLibrary |
Pack="false" |
Projet de liaison |
LibraryProjectZip |
AndroidLibrary |
n/a | Projet de liaison |
Prenez un fichier .aar
ou .jar
que vous ne souhaitez pas inclure dans une liaison C#. Cela est courant si vous avez des dépendances Java ou Kotlin que vous n’avez pas besoin d’appeler à partir de C#. Dans ce cas, vous pouvez définir les métadonnées Bind
sur false
. Par défaut, le fichier est récupéré selon les caractères génériques par défaut. Vous pouvez également utiliser l’attribut Update
pour définir les métadonnées Bind
:
<ItemGroup>
<AndroidLibrary Update="foo.jar" Bind="false">
</ItemGroup>
Dans un projet de bibliothèque de classes Android, cela redistribue tel quel le fichier .jar
à l’intérieur du package NuGet résultant. Dans un projet d’application Android, cela inclut le fichier .jar
dans le fichier .apk
ou .aab
résultant. Aucun des deux n’inclurait de liaison C# pour cette bibliothèque Java.
Fichiers JAR/AAR incorporés
Dans Xamarin.Android, les fichiers .jar
ou .aar
Java ont souvent été incorporés dans la liaison .dll
comme ressource incorporée. Toutefois, cela a ralenti les générations, car chaque .dll
doit être ouvert et son code Java analysé. S’il est trouvé, il doit être extrait sur le disque pour être utilisé.
Dans .NET, le code Java n’est plus incorporé dans le .dll
. Le processus de génération de l’application inclut automatiquement les fichiers .jar
ou .aar
qu’il trouve dans le même répertoire que le .dll
référencé.
Si un projet fait référence à une liaison via <PackageReference>
ou <ProjectReference>
, tout fonctionne et aucune autre considération n’est requise. Toutefois, si un projet fait référence à une liaison via <Reference>
, le .jar
/.aar
doit être situé à côté du .dll
. Autrement dit, pour la référence suivante :
<Reference Include="MyBinding.dll" />
Un répertoire tel que celui de l’exemple suivant ne fonctionnera pas :
lib/
MyBinding.dll
En revanche, le répertoire doit également contenir le code natif :
lib/
MyBinding.dll
mybinding.jar
Considérations relatives à la migration
Il existe plusieurs nouvelles fonctionnalités définies par défaut pour aider à produire des liaisons qui correspondent mieux à leurs équivalents Java. Toutefois, si vous migrez un projet de liaison existant, ces fonctionnalités peuvent créer des liaisons qui ne sont pas compatibles avec les API de vos liaisons existantes. Pour maintenir la compatibilité, vous souhaiterez peut-être désactiver ou modifier ces nouvelles fonctionnalités.
Constantes d’interface
Traditionnellement, C# ne permet pas de déclarer de constantes dans une interface
, ce qui est un modèle courant en Java :
public interface Foo {
public static int BAR = 1;
}
Ce modèle était précédemment pris en charge en créant une autre class
qui contient les constantes :
public abstract class Foo : Java.Lang.Object
{
public static int Bar = 1;
}
Avec C# 8, ces constantes sont placées sur l’interface
:
public interface IFoo
{
public static int Bar = 1;
}
Toutefois, cela signifie que l’autre classe, dont peut dépendre le code existant, n’est plus générée.
La définition de la propriété $(AndroidBoundInterfacesContainConstants)
sur false
dans votre fichier projet rétablit le comportement hérité.
Types d'interface imbriqués
Traditionnellement, C# ne permet pas de déclarer des types imbriqués dans une interface
, ce qui est autorisé en Java :
public interface Foo {
public class Bar { }
}
Ce modèle était pris en charge en déplaçant le type imbriqué vers un type de niveau supérieur avec un nom généré composé de l’interface et du nom du type imbriqué :
public interface IFoo { }
public class IFooBar : Java.Lang.Object { }
Avec C# 8, les types imbriqués peuvent être placés dans l’interface
:
public interface IFoo
{
public class Bar : Java.Lang.Object { }
}
Toutefois, cela signifie que la classe de niveau supérieur, dont peut dépendre le code existant, n’est plus générée.
La définition de la propriété $(AndroidBoundInterfacesContainTypes)
sur false
dans votre fichier projet rétablit le comportement hérité.
Si vous souhaitez utiliser une approche hybride, par exemple pour conserver les types imbriqués existants déplacés vers un type de niveau supérieur, mais autoriser les futurs types imbriqués à rester imbriqués, vous pouvez le spécifier au niveau de l’interface
à l’aide de metadata
pour définir l’attribut unnest
. La définition de ce paramètre sur true
entraîne « l’annulation de l’imbrication » de tous les types imbriqués (comportement hérité) :
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>
La définition sur la valeur false
se traduit par des types imbriqués restants imbriqués dans l’interface
(comportement .NET) :
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>
Avec cette approche, vous pouvez laisser la propriété $(AndroidBoundInterfacesContainTypes)
comme true
et définir unnest
sur true
pour chaque interface
ayant les types imbriqués actuels. Ces types restent toujours de niveau supérieur, tandis que les nouveaux types imbriqués créés ultérieurement seront imbriqués.
Membres d’interface statiques et par défaut (DIM)
Traditionnellement, C# n’autorise pas les interfaces à contenir des membres static
et des méthodes default
:
public interface Foo {
public static void Bar () { ... }
public default void Baz () { ... }
}
Les membres statiques sur les interfaces étaient pris en charge en les déplaçant vers une class
sœur :
public interface IFoo { }
public class Foo
{
public static void Bar () { ... }
}
Les méthodes d’interface default
n’étaient traditionnellement pas liées, car elles n’étaient pas requises et il n’y avait pas de construction C# pour les prendre en charge.
Avec C# 8, les membres static
et default
sont pris en charge sur les interfaces, à l’instar de l’interface Java :
public interface IFoo
{
public static void Bar () { ... }
public default void Baz () { ... }
}
Toutefois, cela signifie que l’autre class
sœur contenant les membres static
ne sera plus générée.
La définition de la propriété $AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods
sur false
dans votre fichier projet rétablit le comportement hérité.
Types références Nullables
La prise en charge des types de référence pouvant accepter la valeur Null (NRT) a été ajoutée dans Xamarin.Android 11.0. La prise en charge des NRT peut être activée à l’aide du mécanisme .NET standard :
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
La valeur par défaut de .NET étant disable
, il en est de même pour les projets Xamarin.Android.
Resource.designer.cs
Dans Xamarin.Android, les projets de liaison Java ne prenaient pas en charge la génération d’un fichier Resource.designer.cs
. Les projets de liaison étant uniquement des bibliothèques de classes dans .NET, ce fichier sera généré. Il peut s’agir d’un changement cassant lors de la migration de projets existants.
L’un des exemples d’échec de cette modification est la génération par votre liaison d’une classe nommée Resource
dans l’espace de noms racine :
error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'
Ou dans le cas d’AndroidX, l’existence de fichiers projet dont le nom contient un -
tel que androidx.window/window-extensions.csproj
. Cela génère un espace de noms racine window-extensions
et un fichier Resource.designer.cs
non valide dans C# :
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
Pour désactiver la génération du fichier Resource.designer.cs
, définissez la propriété $(AndroidGenerateResourceDesigner)
sur false
dans votre fichier projet :
<PropertyGroup>
<AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>