开始使用本机库互操作
本文介绍了如何使用 Maui.NativeLibraryInterop 开始使用本机库互操作来简化设置。
这些说明概述了通过本机库互操作创建绑定的基本步骤、关键决策点和指导示例。 有关特定 API 和实现详细信息的进一步指南,请参阅相关本机 SDK 和库的文档。
先决条件
安装系统必备组件:
- .NET 8.0 SDK
- .NET MAUI 工作负载(通过 Visual Studio 或 CLI
dotnet workload install maui
) - Android SDK
- Android Studio
- Objective-Sharpie(需要自动生成 C# API)
- Xamarin.iOS(Objective-Sharpie 需要工作)
- Visual Studio 或 Visual Studio Code
- Xcode
- Xcode 命令行工具 (
xcode-select --install
)
注意
可以独立安装Android SDK和/或Xcode 命令行工具。 但是,通常通过Xcode处理Xcode 命令行工具的安装。 同样,Android SDK安装通常也根据.NET MAUI 入门文档通过Android Studio和/或.NET MAUI VS Code 扩展进行处理。
新建绑定
开始新建绑定的最简单方法是在maui.NativeLibraryInterop存储库中克隆模板,并从那里进行修改。 要更好地了解 Maui.NativeLibraryInterop 当前如何设置的完整范围,请阅读概述文档。
设置 .NET 绑定库
模板包括适用于 Android 的初学者 .NET 和适用于 iOS 绑定库的 .NET。
更新绑定库,以反映 .NET 应用中所需的目标平台和 .NET 版本。
注意
例如:如果只想使用 .NET 9 创建 iOS 绑定,则可以:
- 在template/android/NewBinding.Android.Binding中删除 Android 绑定库,并
- 在template/macios/NewBinding.MaciOS.Binding/NewBinding.MaciOS.Binding.csproj中更新目标框架,以设置为
net9.0-ios
。
设置本机包装器项目和库
模板还包括初学者 Android Studio 项目和 Xcode 项目。
更新本机项目以反映 .NET 应用中所需的目标平台和版本,并在以下步骤中包含感兴趣的本机库。
设置:iOS 和 Mac Catalyst
Xcode 项目位于 template/macios/native/NewBinding。
更新 Xcode 项目,以反映 .NET 应用中受支持的目标平台和版本。 在 Xcode 项目中,点击顶级框架,并在目标 >常规中:
- 根据需要添加/删除任何支持目标。
- 根据需要调整 iOS 版本。
通过最适合库和需求的方法(例如 CocoaPods、Swift 包管理器),将适用于 iOS 和/或 MacCatalyst 的本机库引入 Xcode 项目。
设置:Android
Android Studio 项目位于template/android/native上。
更新 Android Studio 项目,以反映 .NET 应用中受支持的目标版本。
- 导航到build.gradle.kts (:app)文件
- 根据需要更新
compileSdk
版本
通过 gradle 引入 Android 本机库
- 在build.gradle.kts (:app)文件的依赖项块中添加包依赖项。
- 将存储库添加到settings.gradle.kts文件中的
dependencyResolutionManagement
repositories
块。 - 使用 gradle 文件同步项目(通过 Android Studio 右上角的按钮)。
创建 API 接口
使用以下步骤在本机项目和 .NET 绑定项目之间创建 API 接口。
API 定义:iOS 和 Mac Catalyst
在本机端,在template/macios/native/NewBinding/NewBinding/DotnetNewBinding.swift中进行更新:
- 添加 import 语句以导入刚添加的本机库。
- 为感兴趣的本机库 API 编写 API 定义。
- 确保 Xcode 项目成功生成,并且你对 API 感到满意。
回到 .NET 端,我们现在可以与本机库进行互操作:
- 从template/macios/NewBinding.MaciOS.Binding运行
dotnet build
,以测试一切已正确插入并正常运行。 如果成功,应在 template/macios/native/NewBinding/bin/Release/net8.0-ios/sharpie/NewBinding/ApiDefinitions.cs 看到生成的 C# 绑定。 - 通过将 template/macios/NewBinding.MaciOS.Binding/ApiDefinition.cs 的内容替换为 template/macios/native/NewBinding/bin/Release/net8.0-ios/sharpie/NewBinding/ApiDefinitions.cs 的内容以进行更新。
- 再次从 template/macios/NewBinding.MaciOS.Binding运行
dotnet build
。
API 定义:Android
在本机端,在template/android/native/app/src/main/java/com/example/newbinding/DotnetNewBinding.java中进行更新:
- 添加 import 语句以导入刚添加的本机库。
- 为感兴趣的本机库 API 编写 API 定义。
- 确保 Android Studio 项目成功生成,并且你对 API 感到满意。
回到 .NET 端,我们现在可以与本机库进行互操作:
- 从 template/android/NewBinding.Android.Binding 运行
dotnet build
,以测试一切已正确插入并正常运行。 (注意:此步骤需要安装 JDK 17) - 通过为每个依赖项将以下代码添加到 template/sample/MauiSample.csproj 来引用任何 Android 绑定依赖项。 将 {yourDependencyLibrary.aar} 替换为要绑定的依赖项所需的 .aar 文件。 (注意:通常需要显式引用 gradle/maven 依赖项,因为它们不会自动捆绑到库中。build.gradle.kts 文件配置为将依赖项复制到 bin/outputs/deps 文件夹中,以便在应用程序中引用)
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
<AndroidLibrary Include="..\android\native\newbinding\bin\Release\net8.0-android\outputs\deps\{yourDependencyLibrary.aar}">
<Bind>false</Bind>
<Visible>false</Visible>
</AndroidLibrary>
</ItemGroup>
注意
可以重命名占位符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
、String
、NSError
和回调的类型。
在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文件以公开此新方法。 可通过两种方式实现此目的:
- 可以手动添加所需的代码
- 绑定项目生成时,会运行 objective sharpie,并在native/macios/bin/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 文件。 例如,Facebook initialize
方法的定义如下:
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或其他文件。 只需重新生成绑定项目,新的 API 即可从 .NET MAUI 项目使用。
注意
Android 的绑定项目不使用源生成器,因此,在重新生成绑定项目并重新加载解决方案,以便项目引用选取较新的程序集之前,项目系统和 intellisense 可能不知道新 API。 无论是什么 Intellisense 错误,应用项目仍应编译。