共用方式為


Xamarin.Android 系結專案移轉

在 .NET 中,沒有Android系結專案作為個別專案類型的概念。 任何在 Xamarin.Android 系結項目中運作的 MSBuild 專案群組或建置動作,都支援透過適用於 Android 應用程式或連結庫的 .NET。

若要將 Xamarin.Android 系結連結庫移轉至適用於 Android 的 .NET 類別庫:

  1. 在 Visual Studio 中,建立與 Xamarin.Android 系結專案同名的新 Android Java 連結庫系結專案:

    在 Visual Studio 中建立 Android Java 連結庫系結項目的螢幕快照。

    開啟項目檔將會確認您有 .NET SDK 樣式專案:

    <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) 支援。
  • Java 可為 Null 的參考類型 (NRT) 註釋支援。

AndroidCodegenTarget

XamarinAndroid 不再是屬性的有效選項 $(AndroidCodegenTarget)XAJavaInterop1 現在是預設且唯一支援的選項。

如果您的檔案中有 Additions 與所產生系結程式代碼互動的手動系結程序代碼,可能需要更新它才能與 XAJavaInterop1相容。

默認檔案包含

指定下列檔案結構:

Transforms/
    Metadata.xml
foo.jar

Transforms\*.xml檔案會自動包含為@(TransformFile)專案,且.aar.jar/檔案會自動包含為@(AndroidLibrary)專案。 這會使用 元數據修正從 Transforms\Metadata.xmlfoo.jar找到的Java型別系結 C# 類型。

默認Android相關檔案擷取行為定義於 AutoImport.props 中。 您可以將 屬性設定$(EnableDefaultAndroidItems)為 來停用 Android 項目的行為,或將 屬性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 n/a 系結專案
EmbeddedReferenceJar AndroidLibrary Bind="false" 系結專案
InputJar AndroidLibrary Pack="false" 系結專案
LibraryProjectZip AndroidLibrary n/a 系結專案

.aar請考慮 或 .jar 檔案,而您對此不感興趣,包括 C# 系結。 當您有不需要從 C# 呼叫的 Java 或 Kotlin 相依性時,這種情況很常見。 在這裡設定,您可以將中繼資料設定 Bindfalse。 根據預設,檔案會依預設通配符挑選。 您也可以使用 Update 屬性來設定 Bind 元資料:

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

在 Android 類別庫專案中,這會依目前的方式轉散發 .jar 產生的 NuGet 套件內的檔案。 在Android應用程式專案中,這會在 .jar 產生的 .apk.aab 檔案中包含檔案。 這兩者都不會包含此 Java 連結庫的 C# 系結。

內嵌 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 對應項的系結。 不過,如果您要移轉現有的系結專案,這些功能可能會建立與現有系結不相容的 API 系結。 若要維護相容性,您可能想要停用或修改這些新功能。

介面常數

傳統上,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# 不允許在 interfaceJava 中宣告巢狀類型:

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 設定為 會還原為舊版行為。

例如,如果您想要使用混合式方法,讓現有的巢狀類型保持移至最上層類型,但允許任何未來的巢狀類型維持巢狀狀態,您可以在層級使用 metadata 來設定 屬性來unnest指定這個interface值。 將它設定為 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 ,並針對unnest您目前擁有的巢狀類型設定interfacetrue 。 這些類型一律會維持最上層類型,而稍後引進的任何新巢狀類型都會巢狀化。

靜態和預設介面成員 (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, staticdefault 介面上支持成員,鏡像 Java 介面:

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

不過,這表示將不再產生包含static成員的替代同層級class

$AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods 項目檔中的 屬性 false 設定為 會還原為舊版行為。

可為 Null 的參考型別

在 Xamarin.Android 11.0 中新增了可為 Null 的參考型別 (NRT) 支援。 您可以使用標準 .NET 機制來啟用 NRT 支援:

<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 和 中的 Resource.designer.csC# 無效:

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>