Поделиться через


Миграция проекта привязки Xamarin.Android

В .NET отсутствует концепция проекта привязки Android в качестве отдельного типа проекта. Любые группы элементов MSBuild или действия сборки, которые работают в проектах привязки Xamarin.Android, поддерживаются с помощью приложения или библиотеки .NET для Android.

Чтобы перенести библиотеку привязок Xamarin.Android в библиотеку классов .NET для Android:

  1. В Visual Studio создайте проект привязки библиотеки Java для Android с тем же именем, что и проект привязки Xamarin.Android:

    Снимок экрана: создание проекта привязки библиотеки Java для Android в Visual Studio.

    Открытие файла проекта подтвердит наличие проекта в стиле пакета SDK для .NET:

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

    Примечание.

    Файл проекта библиотеки привязки Android идентичен файлу проекта для библиотеки классов Android.

  2. Добавьте в проект архив Java (JAR) или Архив Android (AAR) и убедитесь, что его действие сборки установлено на AndroidLibrary.

  3. Скопируйте любые преобразования или дополнения из библиотеки привязок Xamarin.Android.

Неподдерживаемые устаревшие параметры

Следующие устаревшие параметры больше не поддерживаются. Поддерживаемые альтернативные варианты доступны в течение нескольких лет, и самый плавный вариант миграции — обновить и протестировать текущие проекты с этими параметрами, прежде чем переносить их в .NET.

AndroidClassParser

jar2xml Больше не является допустимым параметром $(AndroidClassParser) для свойства. class-parse теперь используется параметр по умолчанию и поддерживается только для этого параметра.

class-parse использует преимущества многих новых современных функций, недоступных в jar2xml, например:

  • Автоматические имена параметров для методов класса (если код Java компилируется с javac -parameters).
  • Поддержка Kotlin.
  • Поддержка статических и стандартных элементов интерфейса (DIM).
  • Поддержка примечаний ссылочного типа (NRT) для Java NULL.

AndroidCodegenTarget

XamarinAndroid Больше не является допустимым параметром $(AndroidCodegenTarget) для свойства. XAJavaInterop1 теперь используется параметр по умолчанию и поддерживается только для этого параметра.

Если у вас есть ручной код в Additions файлах, взаимодействующих с созданным кодом привязки, его может потребоваться обновить, чтобы быть совместимым с XAJavaInterop1.

Включение файлов по умолчанию

Учитывая следующую структуру файлов:

Transforms/
    Metadata.xml
foo.jar

Transforms\*.xmlфайлы автоматически включаются в качестве @(TransformFile) элемента, а.aar .jar/файлы автоматически включаются в качестве @(AndroidLibrary) элемента. Это привязывает типы C# для типов Java, найденных при foo.jar использовании исправлений метаданных из Transforms\Metadata.xml.

Поведение глоббинга файлов android по умолчанию определяется в autoImport.props. Это поведение можно отключить для элементов Android, присвоив $(EnableDefaultAndroidItems) свойству falseзначение , или все поведение включения элементов по умолчанию можно отключить, задав $(EnableDefaultItems) для свойства значение false.

Нежелательные .jar или .aar файлы могут быть включены в дикие файлы по умолчанию карта. Например, следующие ошибки компилятора C# приводят к AndroidStudio\gradle\wrapper\gradle-wrapper.jar непреднамеренно привязанному файлу:

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

Чтобы устранить эту проблему, можно удалить конкретный файл в файле проекта:

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

Кроме того, можно исключить все файлы в папке:

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

Новые имена групп элементов

<AndroidLibrary> Теперь рекомендуется использовать группу элементов для всех .jar файлов и .aar файлов. В Xamarin.Android использовались следующие группы элементов, которые могут вместо этого использовать метаданные элементов для достижения того же результата:

Устаревшая группа элементов Новая группа элементов Метаданные элементов Устаревший тип проекта
AndroidAarLibrary AndroidLibrary Bind="false" Приложение
AndroidJavaLibrary AndroidLibrary Bind="false" Библиотека приложений или классов
EmbeddedJar AndroidLibrary Н/Д Проект привязки
EmbeddedReferenceJar AndroidLibrary Bind="false" Проект привязки
InputJar AndroidLibrary Pack="false" Проект привязки
LibraryProjectZip AndroidLibrary Н/Д Проект привязки

Рассмотрим .aar или .jar файл, в котором вы не заинтересованы, включая привязку C#. Это часто происходит в тех случаях, когда у вас есть зависимости Java или Kotlin, которые не нужно вызывать из C#. В этом случае можно задать Bind для метаданных falseзначение . По умолчанию файл выбирается по умолчанию дикими карта. Атрибут можно также использовать Update для задания Bind метаданных:

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

В проекте библиотеки классов Android этот файл будет распространяться .jar внутри результирующего пакета NuGet как есть. В проекте приложения Android это будет включать .jar файл в результирующий .apk или .aab файл. Ни в коем случае не будет включать привязку C# для этой библиотеки Java.

Внедренные JAR/AAR-файлы

В Xamarin.Android Java .jar или .aar часто был внедрен в привязку .dll как внедренный ресурс. Однако это привело к медленным сборкам, так как каждый из них .dll должен быть открыт и сканирован для кода Java. При обнаружении его необходимо извлечь на диск.

В .NET код Java больше не внедряется в .dll. Процесс сборки приложения автоматически включает любые .jar или .aar файлы, которые он находит в том же каталоге, что и ссылка .dll.

Если проект ссылается на привязку через <PackageReference> или <ProjectReference> затем все работает, и никаких дополнительных рекомендаций не требуется. Однако если проект ссылается на привязку через<Reference>,.aar .jar/он должен находиться рядом .dllс ним. То есть для следующей ссылки:

<Reference Include="MyBinding.dll" />

Каталог, такой как в следующем примере, не будет работать:

lib/
    MyBinding.dll

Вместо этого каталог должен содержать собственный код:

lib/
    MyBinding.dll
    mybinding.jar

Вопросы миграции

По умолчанию существует несколько новых функций, которые помогают создавать привязки, которые лучше соответствуют их аналогам Java. Однако при переносе существующего проекта привязки эти функции могут создавать привязки, несовместимые с существующими привязками. Для обеспечения совместимости может потребоваться отключить или изменить эти новые функции.

Константы интерфейса

Традиционно C# не позволяет объявлять константы в виде interfaceобщей модели в Java:

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

Этот шаблон ранее поддерживался путем создания альтернативы class , содержащей константы:

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

При использовании C# 8 эти константы помещаются в interface:

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

Однако это означает, что альтернативный класс, от который существующий код может зависеть, больше не создается.

$(AndroidBoundInterfacesContainConstants) Установка свойства false в файле проекта будет отменить изменения в устаревшем поведении.

Типы вложенных интерфейсов

Традиционно C# не разрешает объявлять вложенные типы в java interface.

public interface Foo {
     public class Bar { }
}

Этот шаблон поддерживается путем перемещения вложенного типа в тип верхнего уровня с созданным именем, состоящим из интерфейса и вложенным именем типа:

public interface IFoo { }

public class IFooBar : Java.Lang.Object { }

При использовании C# 8 вложенные типы могут размещаться в следующих interfaceтипах:

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

Однако это означает, что класс верхнего уровня, от который существующий код может зависеть, больше не создается.

$(AndroidBoundInterfacesContainTypes) Установка свойства false в файле проекта будет отменить изменения в устаревшем поведении.

Если вы хотите использовать гибридный подход, например, чтобы сохранить существующие вложенные типы, перемещаемые в тип верхнего уровня, но разрешить будущим вложенным типам оставаться вложенными, можно указать это на interface уровне, используя metadata для задания атрибута unnest . Если задать его значение true , это приведет к "отмене вложения" любых вложенных типов (устаревшее поведение):

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

При задании этого false значения вложенные типы остаются вложенными в interface поведении (.NET):

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

С помощью этого подхода можно оставить $(AndroidBoundInterfacesContainTypes) свойство как true и задать true unnest для каждого interface из вложенных типов, которые в настоящее время есть. Они всегда будут оставаться типами верхнего уровня, а все новые вложенные типы, представленные позже, будут вложены.

Статические и стандартные элементы интерфейса (DIM)

Традиционно C# не разрешает интерфейсам содержать static элементы и default методы:

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

Статические члены интерфейсов поддерживаются путем перемещения их в одноуровневый classэлемент:

public interface IFoo { }

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

default Методы интерфейса традиционно не привязаны, так как они не требуются, и для их поддержки не было конструкции C#.

С C# 8 static и default члены поддерживаются в интерфейсах, зеркало интерфейс Java:

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

Однако это означает, что альтернативный одноуровневый элемент class , содержащий static элементы, больше не будет создан.

$AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods Установка свойства false в файле проекта будет отменить изменения в устаревшем поведении.

Ссылочные типы, допускающие значение null

Добавлена поддержка ссылочных типов, допускающих значение NULL (NRT), в Xamarin.Android 11.0. Поддержка NRT может быть включена с помощью стандартного механизма .NET:

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

Так как по умолчанию для .NET используется disable, то же самое относится к проектам Xamarin.Android.

Resource.designer.cs

В Xamarin.Android проекты привязки Java не поддерживали Resource.designer.cs создание файла. Так как проекты привязки являются просто библиотеками классов в .NET, этот файл будет создан. Это может быть критическое изменение при переносе существующих проектов.

Один из примеров сбоя из этого изменения заключается в том, что привязка создает класс с именем Resource в корневом пространстве имен:

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

Или в случае AndroidX существуют файлы проекта с - таким именем, как androidx.window/window-extensions.csproj. Это приводит к созданию корневого пространства window-extensions имен и недопустимому C# в 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

Чтобы отключить Resource.designer.cs создание, задайте $(AndroidGenerateResourceDesigner) для свойства false значение в файле проекта:

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