Migrace projektu bindingu Xamarin.Android

V .NET neexistuje koncept projektu Android binding jako samostatného typu projektu. Všechny skupiny položek MSBuild nebo akce sestavení, které fungují v projektech vazeb Xamarin.Android, jsou podporovány prostřednictvím aplikace nebo knihovny .NET pro Android.

Migrace knihovny vazeb Xamarin.Android do knihovny tříd .NET pro Android:

  1. V sadě Visual Studio vytvořte nový projekt vazby knihovny Java pro Android se stejným názvem jako projekt vazby Xamarin.Android.

    Snímek obrazovky projektu vazby Android Java knihovny ve Visual Studio.

    Otevřením souboru projektu potvrdíte, že máte projekt ve stylu sady .NET SDK:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net8.0-android</TargetFramework>
        <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
      </PropertyGroup>
    </Project>
    

    Poznámka:

    Soubor projektu pro knihovnu vazeb pro Android je stejný jako soubor projektu pro knihovnu tříd Androidu.

  2. Přidejte do projektu soubor Java Archive (JAR) nebo AAR (Android Archive) a ujistěte se, že je jeho akce sestavení nastavená na AndroidLibrary.

  3. Zkopírujte všechny transformace nebo doplňky z knihovny vazeb Xamarin.Android.

Nepodporované starší možnosti

Následující starší verze už nejsou podporované. Podporované alternativy jsou k dispozici několik let a nejhladší možností migrace je aktualizovat a otestovat aktuální projekty s těmito možnostmi před jejich migrací na .NET.

AndroidClassParser

jar2xml již není platnou možností vlastnosti $(AndroidClassParser). class-parse je teď výchozí a pouze podporovaná možnost.

class-parse využívá mnoho nových moderních funkcí, které nejsou k dispozici, jar2xmlnapříklad:

  • Automatické názvy parametrů pro metody tříd (pokud je kód Java zkompilován pomocí javac -parameters).
  • Podpora Kotlinu.
  • Podpora člena statického nebo výchozího rozhraní (DIM).
  • Podpora poznámek k referenčnímu typu NRT (Java Nullable).

AndroidCodegenTarget

XamarinAndroid již není platnou možností vlastnosti $(AndroidCodegenTarget). XAJavaInterop1 je teď výchozí a pouze podporovaná možnost.

Pokud máte v Additions souborech ručně svázaný kód, který komunikuje s vygenerovaným kódem vazby, bude možná potřeba ho aktualizovat, aby byl kompatibilní s XAJavaInterop1.

Výchozí zahrnutí souborů

Vzhledem k následující struktuře souborů:

Transforms/
    Metadata.xml
foo.jar

Transforms\*.xml soubory jsou automaticky zahrnuty jako @(TransformFile) položka a .jar/.aar soubory jsou automaticky zahrnuty jako @(AndroidLibrary) položka. Tím se vytvoří vazba typů jazyka C# pro typy Javy nalezené v foo.jar, přičemž se použijí opravy metadat z Transforms\Metadata.xml.

Výchozí chování globování souborů Androidu je definováno v AutoImport.props. Toto chování lze pro položky Androidu zakázat nastavením $(EnableDefaultAndroidItems) vlastnosti na falsehodnotu , nebo je možné zakázat chování zahrnutí všech výchozích položek nastavením $(EnableDefaultItems) vlastnosti na falsehodnotu .

Nežádoucí .jar nebo .aar soubory můžou být zahrnuty ve výchozích zástupných znacích. Například následující chyby kompilátoru jazyka C# jsou výsledkem neúmyslně vázaného AndroidStudio\gradle\wrapper\gradle-wrapper.jar souboru:

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)'

Pokud chcete tento problém vyřešit, můžete konkrétní soubor v souboru projektu odebrat:

<ItemGroup>
  <AndroidLibrary Remove="AndroidStudio\gradle\wrapper\gradle-wrapper.jar" />
</ItemGroup>

Případně můžete vyloučit všechny soubory ve složce:

<AndroidLibrary Remove="AndroidStudio\**\*" />

Názvy nových skupin položek

<AndroidLibrary> je teď doporučená skupina položek, která se má použít pro všechny .jar soubory a .aar soubory. V Xamarin.Androidu byly použity následující skupiny položek, které místo toho můžou použít metadata položek k dosažení stejného výsledku:

Skupina starších položek Nová skupina položek Metadata položek Starší typ projektu
AndroidAarLibrary AndroidLibrary Bind="false" Aplikace
AndroidJavaLibrary AndroidLibrary Bind="false" Knihovna aplikace nebo třídy
EmbeddedJar AndroidLibrary není k dispozici Projekt propojení
EmbeddedReferenceJar AndroidLibrary Bind="false" Projekt propojení
InputJar AndroidLibrary Pack="false" Projekt propojení
LibraryProjectZip AndroidLibrary není k dispozici Projekt propojení

Zvažte soubor .aar nebo .jar, ve kterém nemáte zájem zahrnout vazbu C#. To je běžné v případech, kdy máte závislosti Java nebo Kotlin, které nepotřebujete volat z jazyka C#. V tomto případě můžete nastavit Bind metadata na false. Ve výchozím nastavení se soubor vyzvedne pomocí výchozích zástupných znaků. Atribut Update můžete také použít k nastavení metadat Bind.

<ItemGroup>
  <AndroidLibrary Update="foo.jar" Bind="false">
</ItemGroup>

V projektu třídní knihovny pro Android by se soubor .jar redistribuoval uvnitř výsledného balíčku NuGet v původní podobě. V projektu aplikace pro Android by to zahrnovalo .jar soubor do výsledného .apk souboru nebo .aab souboru. Žádná z nich nezahrnuje vazbu jazyka C# pro tuto knihovnu Java.

Vložené soubory JAR/AAR

V Xamarin.Android byla Java .jar nebo .aar často vložena do vazby .dll jako embedded resource. To však vedlo k pomalým sestavením, protože každý .dll musí být otevřen a prohledáván kvůli kódu jazyka Java. Pokud se najde, musí se extrahovat na disk, který se má použít.

V .NET už kód Java není vložen do .dllsouboru . Proces sestavení aplikace automaticky zahrne všechny .jar soubory nebo .aar soubory, které najde ve stejném adresáři jako odkazovaný .dll.

Pokud projekt odkazuje na vazbu prostřednictvím <PackageReference> nebo <ProjectReference>, pak všechno funguje a nejsou potřeba žádné další úvahy. Pokud však projekt odkazuje na vazbu prostřednictvím <Reference>, .jar/.aar musí být umístěny vedle .dll. To znamená, že pro následující odkaz:

<Reference Include="MyBinding.dll" />

Adresář podobný adresáři v následujícím příkladu nebude fungovat:

lib/
    MyBinding.dll

Místo toho musí adresář obsahovat také nativní kód:

lib/
    MyBinding.dll
    mybinding.jar

Úvahy o migraci

Ve výchozím nastavení je několik nových funkcí, které pomáhají vytvářet vazby, které lépe odpovídají jejich protějškům v Javě. Pokud ale migrujete existující projekt vazeb, mohou tyto funkce vytvářet vazby, které nejsou kompatibilní s vašimi existujícími vazbami. Chcete-li zachovat kompatibilitu, můžete tyto nové funkce zakázat nebo upravit.

Konstanty rozhraní

Tradičně jazyk C# nepovolil deklaraci konstant v jazyce interface, což je běžný vzor v Javě:

public interface Foo {
     public static int BAR = 1;
}

Tento model byl dříve podporován vytvořením alternativy class , která obsahuje konstanty:

public abstract class Foo : Java.Lang.Object
{
   public static int Bar = 1;
}

V jazyce C# 8 jsou tyto konstanty umístěny na interface:

public interface IFoo
{
    public static int Bar = 1;
}

To však znamená, že alternativní třída, na které existující kód může záviset, se už nevygeneruje.

Nastavením vlastnosti $(AndroidBoundInterfacesContainConstants) na false ve vašem souboru projektu se vrátí ke staršímu chování.

Vnořené typy rozhraní

Tradičně jazyk C# neumožňoval deklarovat vnořené typy uvnitř interface, což je v Javě povoleno.

public interface Foo {
     public class Bar { }
}

Tento model byl podporován přesunutím vnořeného typu na typ nejvyšší úrovně s vygenerovaným názvem složeným z rozhraní a vnořeným názvem typu:

public interface IFoo { }

public class IFooBar : Java.Lang.Object { }

V jazyce C# 8 lze vnořené typy umístit do interface:

public interface IFoo
{
    public class Bar : Java.Lang.Object { }
}

To však znamená, že třída nejvyšší úrovně, na které může stávající kód záviset, se už negeneruje.

Nastavením vlastnosti $(AndroidBoundInterfacesContainTypes) na false ve vašem souboru projektu se vrátí ke staršímu chování.

Pokud chcete použít hybridní přístup, například pokud chcete zachovat stávající vnořené typy přesunuté na typ nejvyšší úrovně, ale umožnit, aby budoucí vnořené typy zůstaly vnořené, můžete ho zadat na interface úrovni pomocí metadata nastavení atributu unnest . Pokud jej nastavíte na true, dojde k "odvnoření" všech vnořených typů (chování starší verze):

<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>

Pokud jej nastavíte na false, budou vnořené typy zůstávat vnořené v rámci interface (.NET chování):

<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>

Pomocí tohoto přístupu můžete nechat vlastnost $(AndroidBoundInterfacesContainTypes) jako true a nastavit unnest na true pro každý interface s aktuálně existujícími vnořenými typy. Tyto typy zůstanou vždy na nejvyšší úrovni, zatímco všechny nové typy zavedené později budou umístěny jako vnořené.

Statické a výchozí členy rozhraní (DIM)

Tradičně jazyk C# nepovolil rozhraní, která by obsahovala static členy a default metody:

public interface Foo {
  public static void Bar () { ... }
  public default void Baz () { ... }
}

Podpora pro statické členy na rozhraních byla zajištěna jejich přesunutím k sousednímu rozhraní class:

public interface IFoo { }

public class Foo
{
    public static void Bar () { ... }
}

default metody rozhraní tradičně nebyly vázány, protože nejsou povinné a nebyl k dispozici konstruktor jazyka C#, který je podporuje.

V C# 8 jsou static a default členy podporovány v rozhraních, podobně jako rozhraní v Java.

public interface IFoo
{
    public static void Bar () { ... }
    public default void Baz () { ... }
}

To však znamená, že alternativní sourozenec class obsahující static členy se již nebude generovat.

Nastavením vlastnosti $AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods na false ve vašem souboru projektu se vrátí ke staršímu chování.

Nulovatelné odkazové typy

Ve Xamarin.Androidu 11.0 byla přidána podpora typů odkazů s nulovou hodnotou (NRT). Podporu NRT je možné povolit pomocí standardního mechanismu .NET:

<PropertyGroup>
  <Nullable>enable</Nullable>
</PropertyGroup>

Vzhledem k tomu, že výchozí hodnota pro .NET je disable, platí totéž pro projekty Xamarin.Android.

Resource.designer.cs

V Xamarin.Androidu projekty vazeb Java nepodporují generování Resource.designer.cs souboru. Vzhledem k tomu, že vazbové projekty jsou pouze knihovny tříd v .NET, tento soubor se vygeneruje. Při migraci stávajících projektů to může být zásadní změna.

Jedním z příkladů selhání z této změny je, že vaše vazba vygeneruje třídu pojmenovanou Resource v kořenovém oboru názvů:

error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'

Nebo v případě AndroidX existují soubory projektu s - názvem, například androidx.window/window-extensions.csproj. Výsledkem je kořenový obor názvů window-extensions a neplatný C# v 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

Chcete-li zakázat generování Resource.designer.cs, nastavte vlastnost $(AndroidGenerateResourceDesigner) ve vašem projektovém souboru na false.

<PropertyGroup>
  <AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>