Udostępnij za pośrednictwem


Migracja projektu powiązania platformy Xamarin.Android

Na platformie .NET nie ma pojęcia projektu powiązania systemu Android jako oddzielnego typu projektu. Wszystkie grupy elementów programu MSBuild lub akcje kompilacji, które działają w projektach powiązań platformy Xamarin.Android, są obsługiwane za pośrednictwem aplikacji lub biblioteki platformy .NET dla systemu Android.

Aby przeprowadzić migrację biblioteki powiązań platformy Xamarin.Android do biblioteki klas platformy .NET dla systemu Android:

  1. W programie Visual Studio utwórz nowy projekt powiązania biblioteki Java systemu Android o takiej samej nazwie jak projekt powiązania platformy Xamarin.Android:

    Zrzut ekranu przedstawiający tworzenie projektu powiązania biblioteki Java systemu Android w programie Visual Studio.

    Otwarcie pliku projektu potwierdzi, że masz projekt w stylu zestawu SDK platformy .NET:

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

    Uwaga

    Plik projektu dla biblioteki powiązań systemu Android jest identyczny z plikiem projektu dla biblioteki klas systemu Android.

  2. Dodaj archiwum Java (JAR) lub Archiwum systemu Android (AAR) do projektu i upewnij się, że jego akcja kompilacji jest ustawiona na AndroidLibrary.

  3. Skopiuj wszelkie przekształcenia lub dodatki z biblioteki powiązań platformy Xamarin.Android.

Nieobsługiwane opcje starszej wersji

Następujące starsze opcje nie są już obsługiwane. Obsługiwane alternatywy są dostępne od kilku lat, a najbardziej płynną opcją migracji jest zaktualizowanie i przetestowanie bieżących projektów przy użyciu tych opcji przed migracją ich do platformy .NET.

AndroidClassParser

jar2xml nie jest już prawidłową opcją $(AndroidClassParser) dla właściwości . class-parse jest teraz opcją domyślną i obsługiwaną tylko.

class-parse korzysta z wielu nowych nowoczesnych funkcji, które nie są dostępne w systemie jar2xml, takich jak:

  • Automatyczne nazwy parametrów dla metod klas (jeśli kod Java jest kompilowany za pomocą polecenia javac -parameters).
  • Obsługa Kotlin.
  • Obsługa elementu członkowskiego interfejsu statycznego/domyślnego (DIM).
  • Obsługa adnotacji typu odwołania o wartości null języka Java (NRT).

AndroidCodegenTarget

XamarinAndroid nie jest już prawidłową opcją $(AndroidCodegenTarget) dla właściwości . XAJavaInterop1 jest teraz opcją domyślną i obsługiwaną tylko.

Jeśli masz ręcznie powiązany kod w Additions plikach, który współdziała z wygenerowanym kodem powiązania, może być konieczne zaktualizowanie go tak, aby był zgodny z elementem XAJavaInterop1.

Domyślne dołączanie plików

Biorąc pod uwagę następującą strukturę plików:

Transforms/
    Metadata.xml
foo.jar

Transforms\*.xml pliki są automatycznie dołączane jako @(TransformFile) element, a .jar/.aar pliki są automatycznie dołączane jako @(AndroidLibrary) element. Spowoduje to powiązanie typów języka C# dla typów języka Java znalezionych przy foo.jar użyciu poprawek metadanych z witryny Transforms\Metadata.xml.

Domyślne zachowanie tworzenia globbingu pliku powiązanego z systemem Android jest definiowane w pliku AutoImport.props. To zachowanie można wyłączyć dla elementów systemu Android, ustawiając $(EnableDefaultAndroidItems) właściwość na false, lub wszystkie domyślne zachowanie dołączania elementów można wyłączyć, ustawiając $(EnableDefaultItems) właściwość na false.

.jar Niepożądane lub .aar pliki mogą być dołączone do domyślnych symboli wieloznacznych. Na przykład następujące błędy kompilatora języka C# wynikają z AndroidStudio\gradle\wrapper\gradle-wrapper.jar niezamierzonego powiązania pliku:

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

Aby rozwiązać ten problem, możesz usunąć określony plik w pliku projektu:

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

Alternatywnie można wykluczyć wszystkie pliki w folderze:

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

Nazwy nowych grup elementów

<AndroidLibrary> jest teraz zalecaną grupą elementów do użycia dla wszystkich .jar plików i .aar . W środowisku Xamarin.Android użyto następujących grup elementów, które mogą zamiast tego użyć metadanych elementu, aby uzyskać ten sam wynik:

Starsza grupa elementów Nowa grupa elementów Metadane elementu Starszy typ projektu
AndroidAarLibrary AndroidLibrary Bind="false" Aplikacja
AndroidJavaLibrary AndroidLibrary Bind="false" Biblioteka aplikacji lub klas
EmbeddedJar AndroidLibrary nie dotyczy Wiązanie projektu
EmbeddedReferenceJar AndroidLibrary Bind="false" Wiązanie projektu
InputJar AndroidLibrary Pack="false" Wiązanie projektu
LibraryProjectZip AndroidLibrary nie dotyczy Wiązanie projektu

Rozważ plik .aar lub .jar , w którym nie interesuje Cię dołączenie powiązania w języku C#. Jest to typowe w przypadku, gdy masz zależności języka Java lub Kotlin, których nie trzeba wywoływać z języka C#. W takim przypadku można ustawić Bind metadane na falsewartość . Domyślnie plik jest pobierany do domyślnych symboli wieloznacznych. Możesz również użyć atrybutu Update Bind , aby ustawić metadane:

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

W projekcie biblioteki klas systemu Android będzie to redystrybuować .jar plik wewnątrz wynikowego pakietu NuGet, tak jak to jest. W projekcie aplikacji systemu Android będzie to zawierać .jar plik w wynikowym .apk pliku lub .aab pliku. Żadna z nich nie zawiera powiązania języka C# dla tej biblioteki Języka Java.

Osadzone pliki JAR/AAR

W środowisku Xamarin.Android środowisko Java .jar lub .aar często było osadzone w powiązaniu .dll jako zasób osadzony. Doprowadziło to jednak do spowolnienia kompilacji, ponieważ każdy z nich .dll musi być otwarty i zeskanowany pod kątem kodu Java. W przypadku znalezienia należy wyodrębnić go do dysku, aby można go było użyć.

Na platformie .NET kod Języka Java nie jest już osadzony w elemecie .dll. Proces kompilacji aplikacji będzie automatycznie uwzględniać wszystkie .jar znalezione pliki lub .aar w tym samym katalogu co przywoływny .dllplik .

Jeśli projekt odwołuje się do powiązania za pośrednictwem metody <PackageReference> lub <ProjectReference> wszystko działa i nie są wymagane żadne dodatkowe zagadnienia. Jeśli jednak projekt odwołuje się do powiązania za pomocą metody <Reference>, .jar/.aar element musi znajdować się obok elementu ..dll Oznacza to, że w przypadku następującego odwołania:

<Reference Include="MyBinding.dll" />

Katalog podobny do tego w poniższym przykładzie nie będzie działać:

lib/
    MyBinding.dll

Zamiast tego katalog musi również zawierać kod natywny:

lib/
    MyBinding.dll
    mybinding.jar

Zagadnienia dotyczące migracji

Istnieje kilka nowych funkcji ustawionych domyślnie, aby ułatwić tworzenie powiązań, które lepiej pasują do ich odpowiedników w języku Java. Jednak w przypadku migrowania istniejącego projektu powiązania te funkcje mogą tworzyć powiązania, które nie są zgodne z istniejącymi powiązaniami interfejsu API. Aby zachować zgodność, możesz wyłączyć lub zmodyfikować te nowe funkcje.

Stałe interfejsu

Tradycyjnie język C# nie zezwalał na deklarowanie stałych w obiekcie , który jest typowym wzorcem interfacew języku Java:

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

Ten wzorzec był wcześniej obsługiwany przez utworzenie alternatywy class zawierającej stałe:

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

W języku C# 8 te stałe są umieszczane w obiekcie interface:

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

Oznacza to jednak, że klasa alternatywna, od którego może zależeć istniejący kod, nie jest już generowana.

$(AndroidBoundInterfacesContainConstants) Ustawienie właściwości na false wartość w pliku projektu spowoduje przywrócenie starszego zachowania.

Typy zagnieżdżonych interfejsów

Tradycyjnie język C# nie zezwalał na deklarowanie typów zagnieżdżonych w obiekcie , który jest dozwolony w interfacejęzyku Java:

public interface Foo {
     public class Bar { }
}

Ten wzorzec był obsługiwany przez przeniesienie typu zagnieżdżonego do typu najwyższego poziomu o wygenerowanej nazwie składającej się z interfejsu i nazwy typu zagnieżdżonego:

public interface IFoo { }

public class IFooBar : Java.Lang.Object { }

W języku C# 8 zagnieżdżone typy można umieścić w pliku interface:

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

Oznacza to jednak, że klasa najwyższego poziomu, od którego może zależeć istniejący kod, nie jest już generowana.

$(AndroidBoundInterfacesContainTypes) Ustawienie właściwości na false wartość w pliku projektu spowoduje przywrócenie starszego zachowania.

Jeśli na przykład chcesz użyć podejścia hybrydowego, aby zachować istniejące zagnieżdżone typy przeniesione do typu najwyższego poziomu, ale zezwolić na pozostanie zagnieżdżonych typów w przyszłości, możesz określić je na interface poziomie , używając metadata polecenia , aby ustawić unnest atrybut. Ustawienie tej true wartości spowoduje "anulowanie zagnieżdżania" wszystkich typów zagnieżdżonych (zachowanie starszej wersji):

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

Ustawienie tej false wartości spowoduje zagnieżdżenia typów pozostałych zagnieżdżonych w zachowaniu (zachowanie platformy interface .NET):

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

Korzystając z tego podejścia, można pozostawić $(AndroidBoundInterfacesContainTypes) właściwość jako true i ustawioną unnest na true dla każdego interface z aktualnie zagnieżdżonych typów. Będą one zawsze pozostawać typami najwyższego poziomu, podczas gdy wszystkie nowe typy zagnieżdżone wprowadzone później zostaną zagnieżdżone.

Statyczne i domyślne elementy członkowskie interfejsu (DIM)

Tradycyjnie język C# nie zezwala na interfejsy zawierające static elementy członkowskie i default metody:

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

Statyczne elementy członkowskie w interfejsach zostały obsługiwane przez przeniesienie ich do elementu równorzędnego class:

public interface IFoo { }

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

default Metody interfejsu tradycyjnie nie były powiązane, ponieważ nie są wymagane i nie było konstrukcji języka C#, aby je obsługiwać.

W języku C# 8 static i default elementy członkowskie są obsługiwane w interfejsach, dublując interfejs Java:

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

Oznacza to jednak, że alternatywne elementy równorzędne class static zawierające elementy członkowskie nie będą już generowane.

$AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods Ustawienie właściwości na false wartość w pliku projektu spowoduje przywrócenie starszego zachowania.

Typy referencyjne dopuszczające wartość null

Dodano obsługę typów odwołań dopuszczanych do wartości null (NRT) na platformie Xamarin.Android 11.0. Obsługę nrT można włączyć przy użyciu standardowego mechanizmu .NET:

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

Ponieważ ustawieniem domyślnym dla platformy .NET jest disable, dotyczy to również projektów platformy Xamarin.Android.

Resource.designer.cs

W środowisku Xamarin.Android projekty powiązań Języka Java nie obsługiwały generowania Resource.designer.cs pliku. Ponieważ projekty powiązań to tylko biblioteki klas na platformie .NET, ten plik zostanie wygenerowany. Może to być zmiana powodująca niezgodność podczas migrowania istniejących projektów.

Przykładem niepowodzenia tej zmiany jest wygenerowanie klasy o nazwie Resource w głównej przestrzeni nazw:

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

Lub w przypadku systemu AndroidX istnieją pliki projektu z - nazwą, taką jak androidx.window/window-extensions.csproj. Powoduje to, że główna przestrzeń nazw window-extensions i nieprawidłowy język C# w pliku 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

Aby wyłączyć Resource.designer.cs generowanie $(AndroidGenerateResourceDesigner) , ustaw właściwość na false w pliku projektu:

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