技术速递|使用 Native Library Interop 为 .NET MAUI 创建绑定

news2024/11/26 20:51:10

作者:Rachel Kang
排版:Alan Wang

在当今的应用开发领域,通过利用本机功能来扩展 .NET 应用程序的能力非常宝贵。.NET MAUI 处理程序架构使开发人员能够使用 .NET 代码直接操作本机控件,甚至允许无缝创建跨平台自定义控件。然而,其潜力不仅限于原生平台 API。如果您还能利用本机库 API,将会解锁更多可能性。

适用于 .NET MAUI 的 Native Library Interop(以前称为 Slim Binding 方法)是将本机库集成到 .NET MAUI 应用程序(包括 .NET for Android、.NET for iOS 和 .NET for Mac Catalyst)的替代方法。这种方法能够以既精简又易于维护的方式直接访问本机库 API,从而无需通过传统方法绑定整个库。

您可能会问自己,什么是绑定?当您想要使用不是用 C# 编写的第三方 iOS 或 Android 库时,您需要一种在 .NET MAUI 应用程序中使用它的方法。这就是绑定项目的作用所在,它使您能够创建 C# API 定义来描述本机 API 在 .NET 中的公开方式,以及它如何映射到底层库。建立此定义后,您可以对其进行编译以生成可在 .NET MAUI 应用程序中使用的“绑定”程序集。此过程反映了适用于 iOS 和 Android 的 .NET 的功能;当您在 C# 中使用本机 iOS 或 Android API 时,由于为核心 API 创建的绑定,它是可访问的。

Maui.NativeLibraryInterop 存储库是社区精选示例的宝贵资源,为 .NET 开发人员提供了一个深入研究和受益于共享知识以及贡献自己见解的机会。通过用于创建新绑定的现成模板,它为开发人员从概念到执行的旅程奠定了良好的基础。Native Library Interop 的优点在于它是一种更通用的绑定创建方式,不局限于绑定库,而且从技术上可用于更深入地挖掘原生平台 SDK。

在这篇文章中,我将分享我自己使用 .NET MAUI 的 Native Library Interop 的经验,并提供了一个实际示例来说明如何在 .NET MAUI 应用程序中使用这种创新的方法。请跟随我的步伐,使用模板并遵循入门文档的指导,来实现一个绑定。

开始使用 Native Library Interop 模板

首先,我克隆了 Maui.NativeLibraryInterop 存储库。如果想从现有的绑定示例(Facebook、Firebase、GoogleCast)开始构建,则应从相应文件夹中包含的示例开始。然而,由于我有兴趣从一个完全不同的库创建绑定,因此我将从模板开始!该模板包含使用 Native Library Interop 创建 Android 绑定、iOS 和 Mac Catalyst 绑定以及使用两者的 .NET MAUI 示例应用程序的基础。

获取先决条件
在继续操作之前,请确保您已安装所有先决条件。如果您是长期的 .NET MAUI 开发人员,那么您可能已经像我一样安装了大部分(如果不是全部)先决条件,但请务必检查先决条件的完整列表。

我将绑定什么?

那么我要绑定什么呢?好吧,我想在我的应用程序中包含一个漂亮的饼图!然而 .NET MAUI SDK 目前还没有内置的控件。

虽然我可以使用图表库创建的所有图表都非常漂亮,但我选择了 Native Library Interop 方法,因为我现在只需要在 .NET MAUI 应用程序中使用饼图,所以我只想绑定饼图的 API,仅此而已。

为了创建图表绑定,我将使用适用于 Android 的 MPAndroidChart 库以及适用于 iOS 和 Mac Catalyst 的等效图表库。

因此,我希望绑定名称能够反映这一点。对于 Android,我重命名了 android/native/newbinding/src/main/java/com/example/newbinding/DotnetNewBinding.java 中的类、文件名和 DotnetNewBinding 的所有引用。对于 MaciOS,我对 macios/native/NewBinding/NewBinding/DotnetNewBinding.swift 执行了同样的操作。虽然这是可选的,但我还是决定将项目中的所有文件夹、文件和“newBinding”实例重命名为“charts”。

很好,很简单。接下来是什么?

设置 .NET 绑定库

我计划为 Android、iOS 和 Mac Catalyst 绑定库,我很幸运能够使用我找到的库来支持这三个平台!如果我对所有平台都不感兴趣,我只需删除我不感兴趣平台的文件夹、目标框架和引用即可。

至于 .NET 版本,我目前会继续使用 .NET 8。不过,当我准备使用 .NET 9 时,我会分别更新 Charts.MaciOS.Binding.csproj 和 Charts.Android.Binding.csproj 中的 TargetFrameworks 和版本。

就是这样!虽然我可以选择在这里进行自定义,但除了模板已经为我设置的内容之外,我不需要采取任何额外的步骤来设置 .NET 绑定库。

设置本机包装器项目和库

现在,让我们确保相同的内容反映在本机项目中,并引入本机库!

iOS & Mac Catalyst

首先,我在 Xcode 中打开本机项目 macios/native/Charts/Charts.xcodeproj。我在 Targets > General 中检查支持的目标和 iOS 版本是否符合我的需求,这里我已经准备好了。在这里插入图片描述
​现在,是时候引入本机 Charts 库了!由于引入本机库有多种选择,因此此步骤将根据最适合特定库和个人偏好的方式而有所不同。在我的例子中,我将选择使用 Swift 包管理器,方法是导航至 File > Add Package Dependencies…
在这里插入图片描述
搜索图表库包,
在这里插入图片描述
然后单击添加包。图表库已添加到我的本机 Xcode 项目中!

Android

现在,是时候在 Android 领域做同样的事情了!首先,我在 Android Studio 中打开本机项目 android/native。项目加载后,我打开 build.gradle.kts (:charts) 并确认 compileSdk 版本反映了我的需求。

现在,为了引入本机图表库,我在 build.gradle.kts 中进行了以下编辑:

dependencies {
    // 添加绑定库的包依赖
    implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
    // 复制绑定库的依赖项
     "copyDependencies"("com.github.PhilJay:MPAndroidChart:v3.1.0")
}

我还在 settings.gradle.kts 中添加了相关的 maven 存储库:

dependencyResolutionManagement {
    ...
    repositories {
        ...
        // 在此处添加存储库
        maven { url = uri("https://jitpack.io") }
    }
}

最后但同样重要的一点是,我点击右上角的“Sync Project with Gradle Files”按钮,让可爱的 Gradle 大象开心。

创建 API 接口

现在我们已经引入了本机库,是时候构建我们将在 .NET 应用程序中使用的 API 了!Native Library Interop 方法的妙处在于所有这些都发生在本机端。这意味着我们可以利用库提供的任何现有文档直接用本机语言编写 - 适用于 iOS 和 Mac Catalyst 的 Swift / Objective-C,以及适用于 Android 的 Java / Kotlin。这也意味着我们可以更轻松地更新这些 API,而无需手动将所有内容翻译成 .NET 术语所带来的额外负担。

iOS & Mac Catalyst

在 DotnetCharts.swift 中,我定义了所有我想要的 API。虽然这实际上意味着我可以在 Swift 中定义任何 API,但正如模板字符串示例所示,我现在将专注于创建图表 API 接口的任务,并将在文件顶部导入 DGCharts。

然后,我编写了创建饼图的 API 定义。作为一名 .NET 开发人员,我不能说我是 Swift 方面的专家,但可以直接从 Charts 库存储库中利用 Swift 示例,并获得 GitHub Copilot 的帮助,这无疑是一个改变游戏规则的举措,使这一部分变得不再那么令人生畏。

一旦我通过成功构建 Xcode 项目来确保我的 Swift 代码有效后,我就会尽快回到 .NET 这边,以确保本机库确实可以互操作。

我从 macios/Charts.MaciOS.Binding 运行 dotnet build。这会在 macios/native/Charts/bin/Release/net8.0-ios/sharpie/Charts/ApiDefinitions.cs 中生成 .NET API 定义,然后我将其复制到 charts/macios/Charts.MaciOS.Binding/ApiDefinition.cs 中。

然后,我再次运行 dotnet build 以确保一切正常。🙂
在这里插入图片描述

Android

现在又回到 Android 世界了!在 DotnetCharts.java 中,我可以用 Java 定义任何 API,正如这里的模板字符串示例所示。不过,为了专注于图表,我将导入我需要的所有内容。虽然这些库非常相似,但它们的实现略有不同,这也会影响我在此处导入和定义 API 的方式。

因此,我从 com.github.mikephil.charting 导入以下内容:

import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.utils.ColorTemplate;

然后,我再次编写了创建饼图的 API 定义。正如我不是最精通 Swift 的专家一样,我也不是最精通 Android 的专家……但我仍然是一名移动应用开发人员!能够直接利用在线资源和 GitHub Copilot 使这一切变得非常可行。🙂

再次回到舒适的 .NET,我导航到 android/Charts.Android.Binding 并运行 dotnet build。
在这里插入图片描述
这将在 android/native/charts/bin/Release/net8.0-android/outputs/deps/MPAndroidChart-v3.1.0.aar 中生成依赖项的副本,与 iOS 和 Mac Catalyst 不同,我需要在我的 .NET 示例应用程序中直接引用它,方法是将以下内容添加到 MauiSample.csproj:

<!-- Reference the Android binding dependencies -->
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <AndroidLibrary Include="..\android\native\charts\bin\Release\net8.0-android\outputs\deps\MPAndroidChart-v3.1.0.aar">
        <Bind>false</Bind>
        <Visible>false</Visible>
    </AndroidLibrary>
</ItemGroup>

在 .NET 应用中使用 API

现在是关键时刻! 图表绑定现在可以用于任何新的或现有的 .NET MAUI 应用程序,包括任何 .NET for iOS、.NET for Mac Catalyst 和 .NET for Android 应用程序。为了简单起见,我将在模板附带的 .NET MAUI 示例应用程序中使用它,该示例应用程序已在 MauiSample.csproj 中为我引用了 .NET 绑定库:

<!-- 参考 MaciOS Binding 项目 -->
<ItemGroup Condition="$(TargetFramework.Contains('ios')) Or $(TargetFramework.Contains('maccatalyst'))">
    <ProjectReference Include="..\macios\Charts.MaciOS.Binding\Charts.MaciOS.Binding.csproj" />
</ItemGroup>
<!-- 参考Android Binding项目 -->
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <ProjectReference Include="..\android\Charts.Android.Binding\Charts.Android.Binding.csproj" />
</ItemGroup>

在 MainPage.xaml.cs 中,我导入 ChartsMaciOS.DotnetCharts 和 ChartsAndroid.DotnetCharts,并使用平台指令来直接利用我创建的 API,就像我在 .NET MAUI 中使用任何其他特定于平台的实现一样。

public class MauiPieChart : View
{
    public List<PieChartSlice> Slices { get; set; } = new List<PieChartSlice>();
}
public class PieChartSlice
{
    public string Name { get; set; } = string.Empty;
    public int Count { get; set; }
    public Color Color
    {
        get => _color ??= GenerateRandomColor();
        set => _color = value;
    }
    private Color? _color = null;
    private Color GenerateRandomColor()
    {
        Random random = new Random();
        return new Color(random.Next(256), random.Next(256), random.Next(256));
    }
}
public partial class MauiPieChartHandler
{
    public static IPropertyMapper<MauiPieChart, MauiPieChartHandler> PropertyMapper = new PropertyMapper<MauiPieChart, MauiPieChartHandler>(ViewHandler.ViewMapper)
    {
    };
    public MauiPieChartHandler() : base(PropertyMapper)
    {
    }
}
#if IOS || MACCATALYST
public partial class MauiPieChartHandler : ViewHandler<MauiPieChart, UIKit.UIView>
{
    protected override UIKit.UIView CreatePlatformView()
    {   
        var data = Foundation.NSDictionary<Foundation.NSString, Foundation.NSNumber>.FromObjectsAndKeys (
            VirtualView.Slices.Select(s => new Foundation.NSNumber(s.Count)).ToArray(),
            VirtualView.Slices.Select(s => s.Name).ToArray()
        );
        var colors = VirtualView.Slices.Select(s => s.Color.ToPlatform()).ToArray();
        var pieChart = Charts.CreatePieChartWithData(data, colors);
        return pieChart;
    }
}
#elif ANDROID
public partial class MauiPieChartHandler : ViewHandler<MauiPieChart, Android.Views.View>
{
    protected override Android.Views.View CreatePlatformView()
    {
        var data = new Java.Util.LinkedHashMap();
        var colors = new List<Java.Lang.Integer>();
        foreach (var slice in VirtualView.Slices) {
            data.Put(slice.Name, slice.Count);
            colors.Add(new Java.Lang.Integer(slice.Color.ToPlatform().ToArgb()));
        }
        var pieChart = Charts.CreatePieChart(Microsoft.Maui.ApplicationModel.Platform.CurrentActivity, data, colors);
        return pieChart;
    }
}
#endif

现在,我可以从我的用户界面访问这个新的 MauiPieChart:

<local:MauiPieChart WidthRequest="300" HeightRequest="300">
    <local:MauiPieChart.Slices>
        <local:PieChartSlice Name="Dave's fans" Count="1" />
        <local:PieChartSlice Name="Rachel's fans" Count="5" />
        <local:PieChartSlice Name="Maddy's fans" Count="7" />
        <local:PieChartSlice Name="Beth's fans" Count="10" />
    </local:MauiPieChart.Slices>
</local:MauiPieChart>

瞧!我向您展示了 .NET MAUI 中漂亮的饼图!
在这里插入图片描述

您要绑定什么?

感谢你跟随我创建图表绑定的 Native Library Interop 之旅!若要查看所有代码,包括我的 API 定义和示例用法的详细信息,您可以在 https://github.com/rachelkang/MauiCharts 找到完整示例。若要了解有关 Native Library Interop 方法的更多信息,发现简化这一过程的内在魔力,并更好地了解何时使用它,请务必查看我们的文档。

我希望看到我的过程能够给您带来一些令人兴奋的想法,让您了解使用 Native Library Interop 的无限可能性!

请务必亲自查看 CommunityToolkit/Maui.NativeLibraryInterop。我很想看看您创建了哪些绑定,并听听您的使用体验!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035371.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【星闪开发连载】WS63E开发板Windows环境的构建

目录 HiSpark Studio安装 Python环境配置 SDK代码下载 新建工程 海思官方在gitee仓库中提供了一个文档介绍fbb_ws63: fbb_ws63代码仓为支持ws63和ws63e解决方案SDK。技术论坛&#xff1a;https://developer.hisilicon.com/forum/0133146886267870001 - Gitee.comhttps://gi…

WPF 数据模板DataTemplate、控件模板ControlTemplate、Style、ItemsPreseter

一言蔽之&#xff0c;Template就是“外衣”—— ControlTemplate是控件的外衣&#xff0c; DataTemplate是数据的外衣。 DataTemplate 它定义了一个数据对象的可视化结构 DataTemplate常用的地方有3处&#xff0c;分别是&#xff1a; ContentControl的ContentTemplate属性&…

提升体验:UI设计的可用性原则

在中国&#xff0c;每年都有数十万设计专业毕业生涌入市场&#xff0c;但只有少数能够进入顶尖企业。尽管如此&#xff0c;所有设计师都怀揣着成长和提升的愿望。在评价产品的用户体验时&#xff0c;我们可能会依赖直觉来决定设计方案&#xff0c;或者在寻找改善产品体验的切入…

八股总结----计算机网络

0.OSI七层模型 自己的理解&#xff1a;应用层&#xff1a;生成HTTP请求报文-----表示层&#xff1a;将请求报文转换成适合网络传输的数据格式&#xff0c;加密压缩编码等-----会话层&#xff1a;管理两个应用程序之间的会话&#xff0c;包括连接中断等------传输层&#xff1a…

HAProxy 效能飞跃先锋队

目录 一 负载均衡 1.1 四层负载 1.2 七层负载 1.3 四层负载和七层负载的区别 二 Haproxy简介 2.1 概念和内容 2.2 haproxy的基本配置信息 2.2.1 global 配置 2.2.2 proxies 配置 三 Haproxy的算法 3.1 静态算法 3.2 动态算法 3.3 其他算法 四 高级功能及配置 4.…

进程编程及其函数的使用

1. 创建进程 创建进程的核心操作是使用 fork() 系统调用。 1.1 fork() 系统调用 fork() 创建一个新进程&#xff08;子进程&#xff09;&#xff0c;新进程几乎是父进程的完整拷贝。fork() 返回两次&#xff1a; 在父进程中&#xff0c;返回子进程的 PID。在子进程中&#…

Typescript在AI产品中应用越来越广泛

AI产品中的应用 TypeScript 在 AI 产品中的应用逐渐增多&#xff0c;主要得益于其提供的类型安全、面向对象编程和模块化等特性&#xff0c;这些特性使得开发者能够构建可维护、可扩展和高性能的应用程序。 首先&#xff0c;TypeScript 作为 JavaScript 的超集&#xff0c;通…

C++类和对象(2)——取地址运算符重载

一、const成员函数 const放在成员函数参数列表后面进行修饰&#xff0c;那么这个成员函数就是const成员函数&#xff1b;const实际修饰的是成员函数形参中包含的this指针的形参&#xff0c;表明在这个成员函数内部不能对成员进行修改。 例如日期类里面的Print成员函数&#x…

【HarmonyOS NEXT星河版开发学习】综合测试案例-拼夕夕首页

个人主页→VON 收录专栏→鸿蒙开发小型案例总结​​​​​ 基础语法部分会发布于github 和 gitee上面&#xff08;暂未发布&#xff09; 前言 该实战案例并没有用到太多的知识点&#xff0c;只不过用到的一些新东西&#xff0c;要多花时间去熟悉手机app的一些页面&#xff0c;对…

【Python】Python单元测试基础

文章目录 01-单元测试基础什么是单元测试常用的文件结构运行单元测试 01-单元测试基础 什么是单元测试常用的文件结构编写第一个单元测试运行单元测试 什么是单元测试 单元测试是指一个自动化的测试&#xff1a; 用来验证一小段代码&#xff08;单元&#xff09;的正确性&#…

【LLM】医疗大语言模型:CareGPT

向AI转型的程序员都关注公众号 机器学习AI算法工程 CareGPT (关怀GPT)是一个医疗大语言模型&#xff0c;同时它集合了数十个公开可用的医疗微调数据集和开放可用的医疗大语言模型&#xff0c;包含LLM的训练、测评、部署等以促进医疗LLM快速发展。 特性&#xff1a; 添加ChatG…

【Datawhale AI 夏令营】动手学大模型应用开发Task1 Baseline 精读

【Datawhale AI 夏令营】动手学大模型应用开发Task1 Baseline 精读 开源大模型文件预览 Baseline 1.导入库 # 导入所需的库 from transformers import AutoTokenizer, AutoModelForCausalLM import torch import streamlit as st2.模型下载 # 源大模型下载 from modelscope…

将电脑打造成私人网盘,支持外网访问之详细操作教程

你想过把自己电脑打造成随时随地访问的网盘吗&#xff1f;就是那种拥有一个属于自己的影音库&#xff0c;不用担心被和谐&#xff0c;随时可以登录访问电脑上的各种文件&#xff0c;相比传统网盘省心又安全。 使用Everything和节点小宝将电脑搭建成私人网盘&#xff0c;可以实现…

嵌入式面经篇三——数据类型

文章目录 前言一、数据类型1、用变量 a 给出下面的定义2、下面的代码输出是什么&#xff0c;为什么&#xff1f;3、写出 float x 与“零值”比较的 if 语句。4、下面代码有什么错误&#xff1f;5、下面代码输出是什么&#xff1f;6、下面代码运行后会是什么现象&#xff1f;7、…

24年日语能力(JLPT)考试报名流程图解

报名方式 搜索JLPT中国教育考试网&#xff0c;在线报名&#xff0c;一般学生党从教育网入口登录&#xff0c;社会人士从公网入口登录 报名时间 N1-N5 8月20日 7:00 - 8月27日14:00 注册时间 8月13日7:00 - 8月27日14:00 报名步骤 阅读报考提示&#xff0c;注册个人信息→…

此处不允许使用 ‘空‘ 类型

说明&#xff1a;受最近看的书《设计模式之美》&#xff08;小争哥&#xff09;的影响&#xff0c;最近编码有意将一些业务逻辑写在对象里面&#xff0c;增强封装性。在此记录一次项目启动时的报错&#xff0c;如下&#xff1a; 原因&#xff1a;当你在实体类对象中&#xff0c…

UniApp开发的开源工厂设备管理维护系统

本文来自&#xff1a;UniApp开发的开源工厂设备管理维护系统 - 源码1688 前端小程序演示地址&#xff1a; 后台测试网址&#xff1a; https://shebeiguanli.azheteng.cn/pyswkAWtig.php/addon?refaddtabs 测试账户&#xff1a; admin 测试密码&#xff1a; admin888 前端…

【Python】python泰坦尼克号生存预测 (源码+数据集+PPT+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

黑神话悟空游戏攻略大全 黑神话悟空内存占用多少 国产3A级游戏《黑神话:悟空》评测代码已发 黑神话悟空测试画质130g MacBook可以玩黑神话悟空吗

《黑神话&#xff1a;悟空》的评测代码已向媒体与测评人员发放&#xff0c;评测解禁日期定在8月16日。目前发放的评测代码仅限于PC版&#xff0c;并未涉及PS5版。《黑神话&#xff1a;悟空》将于8月20日发售&#xff0c;登陆PC(Steam/Epic/WeGame)和PS5。玩家将扮演一位“天命人…