跟我做⼀个⾼德地图的 iOS / Android MAUI控件(Android 原⽣库绑定)

我们已经介绍了如何通过 .NET 绑定 iOS 原⽣库 ,本篇开始介绍⼀下如何通过 .NET 绑定 Android 原⽣库。

Android的库

Android 的库以 .jar 做打包, 通过⼯具你可以将多个 .jar 完成绑定,然后通过 C# 调⽤原⽣的 Java 库。对⽐起 iOS , Android 的库绑定简单很多。

60e4475cb179e7e053756c2453e8a8ae.png

从上图可以看到 Xamarin.Android / .NET for Android 通过使⽤托管可调⽤包装器 (MCW) 实现绑定。MCW 是⼀个 JNI 桥,在托管代码需要调⽤ Java 代码时会使⽤它。托管可调⽤包装器还⽀持对 Java 类型进⾏⼦类化以及覆盖 Java 类型的虚拟⽅法。同样,每当 Android 运⾏时 (ART) 代码需要调⽤托管代码时,它都会通过另⼀个称为 Android 可调⽤包装器 (ACW) 的 JNI 桥来实现。

创建⼀个 Android 原⽣库绑定项⽬

通过命令⾏创建⼀个 Android 原⽣库绑定项⽬

dotnet new android-bindinglib -o Droid.AMap

进⼊该项⽬我们看看⽂件结构

c9a203b6a1dd0651acade0d45b521e50.png

项⽬⾥⾯有 Transforms ⽂件夹有对应的三个 xml ⽂件,分别是 EnumFields.xml ,EnumMethods.xml , Metadata.xml , 各⾃作⽤如下 :

MetaData.xml – 允许对最终 API 进⾏更改,例如更改⽣成的绑定的命名空间。

EnumFields.xml – 包含 Java int 常量与 C# enums 之间的映射。

EnumMethods.xml – 允许将⽅法参数和返回类型从 Java int 常量更改为 C# enums

其中 MetaData.xml ⽂件是这些⽂件中的最常⻅的导⼊,因为它允许对绑定进⾏⼀般⽤途的更改,例如:

重命名命名空间、类、⽅法或字段,使其遵循 .NET 约定。

删除不需要的命名空间、类、⽅法或字段。

将类移到不同的命名空间。

添加其他⽀持类以使绑定的设计遵循 .NET 框架模式。

01

把 jar ⽂件添加到绑定项⽬

在项⽬在项⽬中添加 Jars ⽬录 ,把⾼德地图的 jar 包添加到该⽬录下 ,并把 arm64-v8a ,armeabi-v7a ,x86_64 ,这三个⽬录添加进来:

2dcf74443f1a2c24776104651c7ffe38.png

添加完成后,修改 .csproj ⽂件

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0-android</TargetFramework>
    <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <EmbeddedNativeLibrary Include="Jars\arm64-v8a\libAMapSDK_MAP_v9_3_0.so" />
    <EmbeddedNativeLibrary Include="Jars\armeabi-v7a\libAMapSDK_MAP_v9_3_0.so" />
    <EmbeddedNativeLibrary Include="Jars\x86_64\libAMapSDK_MAP_v9_3_0.so" /> 
  </ItemGroup>
  <ItemGroup>
    <TransformFile Include="Transforms\Metadata.xml" />
    <TransformFile Include="Transforms\EnumFields.xml" />
    <TransformFile Include="Transforms\EnumMethods.xml" />
  </ItemGroup>
  <ItemGroup>
    <EmbeddedJar Include="Jars\AMap3DMap_9.3.0_AMapSearch_9.2.0_AMapLocation_6.1.0_20220608.jar" />
  </ItemGroup>
</Project>

这样就把项⽬添加好了,没有像 iOS 原⽣库绑定那么繁琐。然后编译⼀下 ,凡尔赛 + 星⾠⼤海了。

395494e2b9616fba596df367aceddcba.png

02

排雷工作

看⻅这么多错,真的要考虑⼀下是不是放弃,其实这也⾮常治愈,我们逐个来排雷。

*'PoiCreator' does not implement interface member 'IParcelableCreator.NewArray(int)'.

'PoiCreator.NewArray(int)' cannot implement 'IParcelableCreator.NewArray(int)'

错误对应的是这个⽅法 ,实际就是返回类型出错了,我们先根据源⽂件看看 path 路径就可以解决

// Metadata.xml XPath method reference: path="/api/package[@name='com.amap.api.maps.model']/class[@name='PoiCreator']/method[@name='newArray' and count(parameter)=1 and parameter[1][@type='int']]"
[Register ("newArray", "(I)[Lcom/amap/api/maps/model/Poi;", "GetNewArray_IHandler")]
public virtual unsafe global::Com.Amap.Api.Maps.Model.Poi[]? NewArray (int p0)
{
  const string __id = "newArray.(I)[Lcom/amap/api/maps/model/Poi;";
  try {
      JniArgumentValue* __args = stackalloc JniArgumentValue [1];
      __args [0] = new JniArgumentValue (p0);
      var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args);
      return (global::Com.Amap.Api.Maps.Model.Poi[]?) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (global::Com.Amap.Api.Maps.Model.Poi));
      } finally {
  }
    
}

确认好后,需要在 Metadata.xml 做添加

<attr path="/api/package[@name='com.amap.api.maps.model']/class[@name='PoiCreator']/method[@name='newArray' and count(parameter)=1 and parameter[1][@type='int']]" name="managedReturn">Java.Lang.Object[]</attr>

*The type 'AMap' already contains a definition for 'MarkerDragEnd'

这个是重复定义导致的,只需要添加如下代码删除就可以了,如

<remove-node path="/api/package[@name='com.amap.api.maps']/interface[@name='AMap.OnCameraChangeListener']" />

*'BusLineSearch': member names cannot be the same as their enclosing type

重命名导致的错误 ,把名字修改⼀下即可,如

<attr path="/api/package[@name='com.amap.api.services.busline']/class[@name='BusLineSearch']" name="managedName">AmapBusLineSearch</attr>

*cannot change access modifiers when overriding 'protected'

重载的时候出现权限问题,这个时候你需要的是把权限修正好,如

<attr path="/api/package[@name='com.amap.api.maps.model']/class[@name='PolygonOptions']/method[@name='getUpdateFlags' and count(parameter)=0]"name="visibility">protected</attr>

解决上述的所有问题,基本上就可以治愈了,当编译通过⼀刻你会⾮常兴奋

54918823709b6c39853ee7a7962955ae.png

找个 .NET for Android 项⽬看看

86bc7100cb78aec6f37827dd6192dd0e.jpeg

⼤家可以去我的 GitHub 下载该示例

https://github.com/kinfey/AMapMAUIControls/tree/main/samples/Droid.Bindings

小结

Android 的原⽣绑定⽐ iOS 的简单得多,所以更容易⼊⼿。希望各位⼩伙伴能多动⼿,有时候也是⼀个很好的体验。经过两篇⽂章的学习,相信⼤家也掌握了如何⽤ .NET 绑定 iOS 和 Android 的原⽣库了。最后⼀篇⽂章我们来讨论下如何做⼀个适配 MAUI 的原⽣控件。

*相关资料

1. 通过 Microsoft Docs 了解 MAUI 

https://aka.ms/Docs.MAUI

2. 通过 Microsoft Learn 学习 MAUI 

https://aka.ms/Learn.MAUI

3.使⽤⾼德地图 SDK for Android 请访问

https://developer.amap.com/api/android-sdk/gettingstarted

4.了解 Android 原⽣库绑定的内容,请访问 https://docs.microsoft.com/enus/xamarin/android/platform/binding-java-library/

CA周记往期回顾:

8091d09db99ebf2d1182808af407629a.jpeg

更多原创文章与资源共享

请关注Kinfey Techtalk

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值