開始使用原生連結庫 Interop

本文說明如何使用 Maui.NativeLibraryInterop 開始進行原生程式庫互通操作,以簡化設定流程。

這些指示概述透過原生連結庫 Interop 建立系結的基本步驟、關鍵決策點和指引範例。 如需有關特定 API 和實作細節的更多指引,請參閱您感興趣的相關原生 SDK 和程式庫文件。

必要條件

安裝必要條件:

注意

可以獨立方式安裝 Android SDK 和/或 Xcode 命令行工具 。 不過,Xcode 命令行工具的安裝通常是透過 Xcode 來處理。 同樣地, Android SDK 安裝通常是透過 Android Studio 和 /或 .NET MAUI VS Code 擴充 功能,根據 .NET MAUI 用戶入門 文件來處理。

建立新的系結

若要開始建立新的系結,最簡單的方式是在Maui.NativeLibraryInterop存放庫中複製範本,並從該處進行修改。 若要進一步瞭解 Maui.NativeLibraryInterop 目前設定方式的完整範圍,請參閱概觀文件。

設定 .NET 繫結程式庫

此 範本 包含適用於 Android 的入門 .NET 和適用於 iOS 系結連結庫的 .NET。

更新系結連結庫,以反映 .NET 應用程式中所需的目標平臺和 .NET 版本。

注意

例如:如果您的目標是只使用 .NET 9 建立 iOS 系結,您可以:

  1. 刪除位於 template/android/NewBinding.Android.Binding 的 Android 繫結程式庫,以及
  2. 更新 template/macios/NewBinding.MaciOS.Binding/NewBinding.MaciOS.Binding.maciOS.Binding.csproj 中的目標架構,以設定為 net9.0-ios。

設定原生包裝器專案和程式庫

此 範本 也包含入門 Android Studio 專案和 Xcode 專案。

更新原生專案,以視需要在 .NET 應用程式中反映目標平臺和版本,並在下列步驟中包含感興趣的原生連結庫。

設定:iOS 與 Mac Catalyst

Xcode 專案位於 template/macios/native/NewBinding。

更新 Xcode 專案,以反映 .NET 應用程式中支援的目標平臺和版本。 在 Xcode 專案中,點選最上層的框架,然後在 Targets >「一般」:

  1. 視需要新增/移除任何 支援目的地 。
  2. 視需要調整 iOS 版本。

透過任何最適合您連結庫和需求的方法,將 iOS 和/或 MacCatalyst 的原生連結庫帶入您的 Xcode 專案(例如 CocoaPods、Swift 封裝管理員)。

安裝程式:Android

Android Studio 專案位於 template/android/native。

更新 Android Studio 專案,以反映 .NET 應用程式中支援的目標版本。

  1. 流覽至 build.gradle.kts (:app) 檔案
  2. 視需要更新 compileSdk 版本

透過 Gradle 引入 Android 原生程式庫

  1. 在 build.gradle.kts (:app) 檔案的相依性區塊中新增套件相依性。
  2. 將存放庫新增至 dependencyResolutionManagementrepositories settings.gradle.kts 檔案中的 區塊。
  3. 將專案與 gradle 檔案同步處理(透過 Android Studio 右上角的按鈕)。

建立 API 介面

使用下列步驟,在原生專案與 .NET 系結項目之間建立 API 介面。

API 定義:iOS 和 Mac Catalyst

在原生端,於 template/macios/native/NewBinding/NewBinding/DotnetNewBinding.swift 中進行更新:

  1. 新增一個 import 陳述式,以匯入您剛新增的原生程式庫。
  2. 為感興趣的原生連結庫 API 撰寫 API 定義。
  3. 請確定 Xcode 專案建置成功,且您對 API 感到滿意。

回到 .NET 這一端,我們現在已準備好與原生程式庫進行互通:

  1. 從 template/macios/NewBinding.MaciOS.Binding 執行 dotnet build,以測試所有項目都已正確接妥,並可正常運作。
  2. 使用 Objective Sharpie 生成 C# 系結以供 Swift API 更新:
    1. 流覽至 template/macios/NewBinding.MaciOS.Binding/bin/Debug/net9.0-ios/NewBinding.MaciOS.Binding.resources/NewBindingiOS.xcframework/ios-arm64/NewBinding.framework 在 MaciOS 系結項目輸出資料夾中。
    2. 執行 sharpie xcode -sdks,以取得系結命令的有效目標 SDK 值清單。 選取與你要在下一個指令中使用的平臺和版本相符合的值,例如 iphoneos18.0。
    3. 針對系結專案所建立的 xcframework 中的標頭檔執行 sharpie bind:
      sharpie bind --output=sharpie-out --namespace=NewBindingMaciOS --sdk=iphoneos18.0 --scope=Headers Headers/NewBinding-Swift.h
      
    4. 更新 template/macios/NewBinding.MaciOS.Binding/ApiDefinition.cs的內容,將其替換為 template/macios/NewBinding.MaciOS.Binding/bin/Debug/net9.0-ios/NewBinding.MaciOS.Binding.resources/NewBindingiOS.xcframework/ios-arm64/NewBinding.framework/sharpie-out/ApiDefinitions.cs的內容,並視需要進行調整(例如:命名)。
    5. 從 template/macios/NewBinding.MaciOS.Binding 再次執行 dotnet build。

另請參閱 objective-sharpie 文件,以瞭解更多有關此工具的資訊。

API 定義:Android

在原生端,在 範本/android/native/newbinding/src/main/java/com/example/newbinding/DotnetNewBinding.java中進行更新:

  1. 新增 import 陳述式,以匯入您剛才新增的原生程式庫。
  2. 為感興趣的原生連結庫 API 撰寫 API 定義。
  3. 請確定 Android Studio 專案建置成功,且您滿意 API。

回到 .NET 這一端,我們現在已經準備好與原生程式庫進行互通操作:

  1. 從 template/android/NewBinding.Android.Binding 執行 dotnet build,以測試所有設定皆已正確就緒且可正常運作。 (注意:此步驟會要求您安裝 JDK 17)
  2. 藉由在本機 Android 專案中每個要綁定的 maven 相依項目,將 @(AndroidMavenLibrary) 項目新增到 template/sample/MauiSample.csproj 來參考任何 Android 綁定相依性。 這會啟用專案的 Java 相依性驗證,並導致後續組建產生遺漏相依性的建置警告或錯誤。 您可以新增 @(AndroidMavenLibrary) 或 @(PackageReference) 元素,以滿足您所系結的原生程式庫的 Java 相依鏈結,從而解決這些警告/錯誤。 注意:Gradle/Maven 相依關係通常需要明確參考,因為它們不會自動納入到您的程式庫中。)
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <AndroidMavenLibrary Include="{DependencyGroupId}:{DependencyName}" Version="{DependencyVersion}" Bind="false" />
</ItemGroup>

如需了解此流程的更多資訊,另請參閱 AndroidMavenLibrary 參考 和 Java 相依性驗證 文檔。

注意

您可以將作為預留位置的 DotnetNewBinding 類別重新命名,使其更能反映所封裝的原生程式庫。 如需撰寫 API 定義的更多範例和秘訣,請參閱下 一節:修改現有的系結。

在您的 .NET 應用程式中取用 API

此範本在 template/sample/MauiSample 中包含一個 .NET MAUI 範例應用程式,其會參考 .NET 繫結專案,讓原生程式庫可立即使用!

如果您有興趣使用自己的 .NET MAUI、適用於 Android 的 .NET、適用於 iOS 的 .NET 和/或適用於 Mac Catalyst 的 .NET 應用程式,您可以修改 .NET 應用程式專案檔,以參考繫結程式庫:

<!-- Reference to MaciOS Binding project -->
<ItemGroup Condition="$(TargetFramework.Contains('ios')) Or $(TargetFramework.Contains('maccatalyst'))">
    <ProjectReference Include="..\..\macios\NewBinding.MaciOS.Binding\NewBinding.MaciOS.Binding.csproj" />
</ItemGroup>

<!-- Reference to Android Binding project -->
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <ProjectReference Include="..\..\android\NewBinding.Android.Binding\NewBinding.Android.Binding.csproj" />
</ItemGroup>

修改現有的系結

如果現有的 API 介面未公開您自己專案中所需的功能,是時候進行自己的修改了!

iOS 和 Mac Catalyst

在 Xcode 專案中,您會發現一或多個 Swift 檔案,這些檔案會定義系結的公用 API 介面。 例如,Firebase Messaging 的 register 方法定義如下:

@objc(MauiFIRMessaging)
public class MauiFIRMessaging : NSObject {

    @objc(register:completion:)
    public static func register(apnsToken: NSData, completion: @escaping (String?, NSError?) -> Void) {
        let data = Data(referencing: apnsToken);
        Messaging.messaging().apnsToken = data
        Messaging.messaging().token(completion: { fid, error in
            completion(fid, error as NSError?)
        })
    }
    // ...
}

注意

.NET 繫結將會使用的原生包裝 API 類型必須宣告為 public,並且需要加上 @objc(NameOfType) 註解,而方法也必須為 public;此外,也可以利用類似的註解 @objc(methodName:parameter1:) 來指定名稱和參數,這有助於影響 Objective Sharpie 所產生的繫結。

您可以在此方法中看到,公用 API 介面只會使用 iOS 的 .NET 已經知道的類型:NSData、 StringNSError 和回呼。

在 Firebase.MaciOS.Binding 專案中, ApiDefinitions.cs 檔案包含這個原生包裝函式 API 的系結定義:

using System;
using Foundation;

namespace Firebase
{
    // @interface MauiFIRMessaging : NSObject
    [BaseType (typeof(NSObject))]
    interface MauiFIRMessaging
    {
        [Static]
        [Export ("register:completion:")]
        [Async]
        void Register (NSData apnsToken, Action<string?, NSError?> completion);
        // ...
    }

假設您想要新增取消註冊的方法。 Swift 程式代碼看起來會像這樣:

@objc(unregister:)
public static func unregister(completion: @escaping (NSError?) -> Void) {
    // need delegate to watch for fcmToken updates
    Messaging.messaging().deleteToken(completion: { error in
        completion(error as NSError?)
    })
}

另一部分是更新系結專案中的 ApiDefinitions.cs 檔案,以公開此新方法。 有兩種方式可以解決此問題:

  1. 您可以手動新增必要的程式碼
  2. 建置系結項目之後,您可以運行 Objective Sharpie 工具來產生 ApiDefinitions.cs 檔案。 您可以嘗試尋找此檔案的相關變更,並手動複製這些變更,或嘗試複製整個檔案,並查看差異以尋找您需要的部分。

在此情況下,ApiDefinitions.cs的變更會是:

[Static]
[Export("unregister:")]
[Async]
void UnRegister(Action completion);

完成這些變更後,您可以重新建置繫結專案,新的 API 即可在您的 .NET MAUI 專案中使用。

注意

Mac/iOS 的系結專案未使用來源產生器,因此在您重新建置系結專案並重新載入解決方案,讓專案參考取得更新後的組件之前,專案系統和 IntelliSense 可能無法辨識新的 API。 即使有 IntelliSense 錯誤,您的應用程式專案仍應該能成功編譯。

Android

在 Android Studio 專案中,您會發現模組目錄,其中包含定義系結之公用 API 介面的 Java 檔案。 例如, initialize Facebook 的 方法定義如下:

package com.microsoft.mauifacebook;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

import com.facebook.LoggingBehavior;
import com.facebook.appevents.AppEventsLogger;

public class FacebookSdk {

    static AppEventsLogger _logger;

    public static void initialize(Activity activity, Boolean isDebug) {
        Application application = activity.getApplication();

        if (isDebug) {
            com.facebook.FacebookSdk.setIsDebugEnabled(true);
        }

        com.facebook.FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS);

        AppEventsLogger.activateApp(application);

        _logger = AppEventsLogger.newLogger(activity);
    }

    // ...
}

您可以在此方法中看到,公用 API 介面只會使用適用於 Android 的 .NET 已經知道的類型: Activity 和 Boolean。

在 Facebook.Android.Binding 專案中,Transforms/Metadata.xml 檔案只包含一些 XML,用來描述如何將 Java 套件名稱(com.microsoft.mauifacebook)對應到對 C# 較友善的命名空間(Facebook)。 一般而言,Android 系結比目前 Mac/iOS 更「自動」,您很少需要對這些轉換檔案進行變更。

<metadata>
    <attr path="/api/package[@name='com.microsoft.mauifacebook']" name="managedName">Facebook</attr>
</metadata>

假設您想要新增方法來記錄事件。 Java 程式代碼看起來會像這樣:

public static void logEvent(String eventName) {
    _logger.logEvent(eventName);
}

從這個簡單的變更中,系結專案不需要更新 Transforms/Metadata.xml 或其他檔案。 您只要重新建置繫結專案,即可在您的 .NET MAUI 專案中使用新的 API。

注意

Android 的系結專案未使用來源產生器,因此在您重建系結專案並重新載入方案,讓專案參考取得較新的組件之前,專案系統和 IntelliSense 可能都無法識別新的 API。 即使有 IntelliSense 錯誤,您的應用程式專案仍應該能成功編譯。