Migrazione del progetto di associazione Xamarin.Android
In .NET non esiste alcun concetto di progetto di associazione Android come tipo di progetto separato. Qualsiasi gruppo di elementi MSBuild o azioni di compilazione che funzionano nei progetti di associazione Xamarin.Android è supportato tramite un'app o una libreria .NET per Android.
Per eseguire la migrazione di una libreria di binding Xamarin.Android a una libreria di classi .NET per Android:
In Visual Studio creare un nuovo progetto di associazione di librerie Java Android con lo stesso nome del progetto di associazione Xamarin.Android:
L'apertura del file di progetto consentirà di verificare di avere un progetto di tipo .NET SDK:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0-android</TargetFramework> <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> </Project>
Nota
Il file di progetto per una libreria di associazioni Android è identico al file di progetto per una libreria di classi Android.
Aggiungere l'archivio Java (JAR) o Android Archive (AAR) al progetto e assicurarsi che l'azione di compilazione sia impostata su AndroidLibrary.
Copiare eventuali trasformazioni o aggiunte dalla libreria di associazioni di Xamarin.Android.
Opzioni legacy non supportate
Le opzioni legacy seguenti non sono più supportate. Le alternative supportate sono disponibili per diversi anni e l'opzione di migrazione più fluida consiste nell'aggiornare e testare i progetti correnti con queste opzioni prima di eseguirne la migrazione a .NET.
AndroidClassParser
jar2xml
non è più un'opzione valida per la $(AndroidClassParser)
proprietà . class-parse
è ora l'opzione predefinita e supportata solo.
class-parse
sfrutta molte nuove funzionalità moderne non disponibili in jar2xml
, ad esempio:
- Nomi di parametri automatici per i metodi di classe (se il codice Java viene compilato con
javac -parameters
). - Supporto di Kotlin.
- Supporto del membro di interfaccia statico/predefinito ( DIM).
- Supporto delle annotazioni NRT (Java Nullable Reference Type).
AndroidCodegenTarget
XamarinAndroid
non è più un'opzione valida per la $(AndroidCodegenTarget)
proprietà . XAJavaInterop1
è ora l'opzione predefinita e supportata solo.
Se nei file è presente Additions
codice associato a mano che interagisce con il codice di associazione generato, potrebbe essere necessario aggiornarlo per essere compatibile con XAJavaInterop1
.
Inclusione file predefinita
Data la struttura di file seguente:
Transforms/
Metadata.xml
foo.jar
Transforms\*.xml
i file vengono inclusi automaticamente come @(TransformFile)
elemento e.aar
.jar
/i file vengono inclusi automaticamente come @(AndroidLibrary)
elemento. In questo modo verranno associati tipi C# per i tipi Java trovati in foo.jar
usando le correzioni dei metadati da Transforms\Metadata.xml
.
Il comportamento predefinito del globbing del file correlato ad Android è definito in AutoImport.props. Questo comportamento può essere disabilitato per gli elementi Android impostando la $(EnableDefaultAndroidItems)
proprietà su false
oppure è possibile disabilitare il comportamento di inclusione di tutti gli elementi predefiniti impostando la $(EnableDefaultItems)
proprietà su false
.
I file o .aar
non indesiderati .jar
possono essere inclusi con i caratteri jolly predefiniti. Ad esempio, gli errori del compilatore C# seguenti generano un'associazione involontaria di un AndroidStudio\gradle\wrapper\gradle-wrapper.jar
file:
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)'
Per risolvere questo problema, è possibile rimuovere il file specifico nel file di progetto:
<ItemGroup>
<AndroidLibrary Remove="AndroidStudio\gradle\wrapper\gradle-wrapper.jar" />
</ItemGroup>
In alternativa, è possibile escludere tutti i file all'interno di una cartella:
<AndroidLibrary Remove="AndroidStudio\**\*" />
Nomi di nuovi gruppi di elementi
<AndroidLibrary>
è ora il gruppo di elementi consigliato da usare per tutti i .jar
file e .aar
. In Xamarin.Android sono stati usati i gruppi di elementi seguenti, che possono invece usare i metadati degli elementi per ottenere lo stesso risultato:
Gruppo di elementi legacy | Nuovo gruppo di elementi | Metadati degli elementi | Tipo di progetto legacy |
---|---|---|---|
AndroidAarLibrary |
AndroidLibrary |
Bind="false" |
Applicazione |
AndroidJavaLibrary |
AndroidLibrary |
Bind="false" |
Libreria di applicazioni o classi |
EmbeddedJar |
AndroidLibrary |
n/d | Progetto di associazione |
EmbeddedReferenceJar |
AndroidLibrary |
Bind="false" |
Progetto di associazione |
InputJar |
AndroidLibrary |
Pack="false" |
Progetto di associazione |
LibraryProjectZip |
AndroidLibrary |
n/d | Progetto di associazione |
Si consideri un .aar
file o .jar
, in cui non si è interessati a includere un'associazione C#. Questo è comune per i casi in cui si hanno dipendenze Java o Kotlin che non è necessario chiamare da C#. In questo caso, è possibile impostare i Bind
metadati su false
. Per impostazione predefinita, il file viene prelevato dai caratteri jolly predefiniti. È anche possibile usare l'attributo Update
per impostare i Bind
metadati:
<ItemGroup>
<AndroidLibrary Update="foo.jar" Bind="false">
</ItemGroup>
In un progetto di libreria di classi Android, questo ridistribuirà il .jar
file all'interno del pacchetto NuGet risultante così come è. In un progetto di applicazione Android, questo includerà il .jar
file nel file o .aab
risultante.apk
. Nessuno dei due include un'associazione C# per questa libreria Java.
File JAR/AAR incorporati
In Xamarin.Android, Java .jar
o .aar
è stato spesso incorporato nell'associazione .dll
come risorsa incorporata. Tuttavia, questo ha portato a compilazioni lente, perché ogni .dll
compilazione deve essere aperta e analizzata per il codice Java. Se trovato, deve essere estratto su disco da usare.
In .NET il codice Java non è più incorporato in .dll
. Il processo di compilazione dell'app include automaticamente tutti i .jar
file o .aar
trovati nella stessa directory di un riferimento .dll
.
Se un progetto fa riferimento a un'associazione tramite <PackageReference>
o <ProjectReference>
quindi tutto funziona e non sono necessarie considerazioni aggiuntive. Tuttavia, se un progetto fa riferimento a un'associazione tramite <Reference>
, deve.aar
.jar
/trovarsi accanto a ..dll
Vale a dire, per il riferimento seguente:
<Reference Include="MyBinding.dll" />
Una directory come quella nell'esempio seguente non funzionerà:
lib/
MyBinding.dll
La directory deve invece contenere anche il codice nativo:
lib/
MyBinding.dll
mybinding.jar
Considerazioni sulla migrazione
Esistono diverse nuove funzionalità impostate per impostazione predefinita per produrre associazioni che corrispondano meglio alle controparti Java. Tuttavia, se si esegue la migrazione di un progetto di associazione esistente, queste funzionalità possono creare associazioni non compatibili con le API con le associazioni esistenti. Per mantenere la compatibilità, è possibile disabilitare o modificare queste nuove funzionalità.
Costanti di interfaccia
In genere, C# non ha consentito la dichiarazione di costanti in un interface
oggetto , che è un modello comune in Java:
public interface Foo {
public static int BAR = 1;
}
Questo modello è stato precedentemente supportato creando un'alternativa class
che contiene le costanti:
public abstract class Foo : Java.Lang.Object
{
public static int Bar = 1;
}
Con C# 8, queste costanti vengono posizionate in interface
:
public interface IFoo
{
public static int Bar = 1;
}
Ciò significa tuttavia che la classe alternativa da cui dipende il codice esistente non viene più generata.
Se si imposta la $(AndroidBoundInterfacesContainConstants)
proprietà su false
nel file di progetto, verrà ripristinato il comportamento legacy.
Tipi di interfaccia annidati
In genere, C# non ha consentito la dichiarazione di tipi annidati in un interface
oggetto , che è consentito in Java:
public interface Foo {
public class Bar { }
}
Questo modello è stato supportato spostando il tipo annidato in un tipo di primo livello con un nome generato composto dall'interfaccia e dal nome del tipo annidato:
public interface IFoo { }
public class IFooBar : Java.Lang.Object { }
Con C# 8, i tipi annidati possono essere inseriti in interface
:
public interface IFoo
{
public class Bar : Java.Lang.Object { }
}
Ciò significa tuttavia che la classe di primo livello da cui il codice esistente può dipendere non viene più generato.
Se si imposta la $(AndroidBoundInterfacesContainTypes)
proprietà su false
nel file di progetto, verrà ripristinato il comportamento legacy.
Se si vuole usare un approccio ibrido, ad esempio, per mantenere i tipi annidati esistenti spostati in un tipo di primo livello, ma consentire a qualsiasi tipo annidato futuro di rimanere annidati, è possibile specificarlo a interface
livello usando metadata
per impostare l'attributo unnest
. L'impostazione di su true
comporterà l'annullamento dell'annidamento di qualsiasi tipo annidato (comportamento legacy):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>
Impostandolo su false
, i tipi annidati rimangono annidati nel interface
comportamento (.NET):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>
Usando questo approccio, è possibile lasciare la $(AndroidBoundInterfacesContainTypes)
proprietà come true
e impostare su true
unnest
per ogni interface
con tipi annidati attualmente disponibili. Questi rimarranno sempre tipi di primo livello, mentre tutti i nuovi tipi annidati introdotti in un secondo momento verranno annidati.
Membri di interfaccia statici e predefiniti (DIM)
In genere, C# non ha consentito alle interfacce di contenere static
membri e default
metodi:
public interface Foo {
public static void Bar () { ... }
public default void Baz () { ... }
}
I membri statici nelle interfacce sono stati supportati spostandoli in un elemento di pari livello class
:
public interface IFoo { }
public class Foo
{
public static void Bar () { ... }
}
default
I metodi di interfaccia non sono tradizionalmente associati, poiché non sono necessari e non c'era un costrutto C# per supportarli.
Con C# 8 static
e default
i membri sono supportati nelle interfacce, eseguendo il mirroring dell'interfaccia Java:
public interface IFoo
{
public static void Bar () { ... }
public default void Baz () { ... }
}
Ciò significa tuttavia che l'elemento di pari livello class
alternativo contenente static
i membri non verrà più generato.
Se si imposta la $AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods
proprietà su false
nel file di progetto, verrà ripristinato il comportamento legacy.
Tipi riferimento nullable
Il supporto per i tipi di riferimento nullable (NRT) è stato aggiunto in Xamarin.Android 11.0. Il supporto NRT può essere abilitato usando il meccanismo .NET standard:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Poiché l'impostazione predefinita per .NET è disable
, lo stesso vale per i progetti Xamarin.Android.
Resource.designer.cs
In Xamarin.Android i progetti di associazione Java non supportano la generazione di un Resource.designer.cs
file. Poiché i progetti di associazione sono solo librerie di classi in .NET, questo file verrà generato. Potrebbe trattarsi di una modifica che causa un'interruzione durante la migrazione di progetti esistenti.
Un esempio di errore di questa modifica è se l'associazione genera una classe denominata Resource
nello spazio dei nomi radice:
error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'
In alternativa, nel caso di AndroidX, sono presenti file di progetto con -
nel nome, ad androidx.window/window-extensions.csproj
esempio . Ciò comporta lo spazio dei nomi window-extensions
radice e C# non valido 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
Per disabilitare Resource.designer.cs
la generazione, impostare la $(AndroidGenerateResourceDesigner)
proprietà su false
nel file di progetto:
<PropertyGroup>
<AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>