关于android:做⼀个⾼德地图的-iOS-Android-MAUI-控件下

6次阅读

共计 8385 个字符,预计需要花费 21 分钟才能阅读完成。

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

Android 的库

Android 的库以 .jar 做打包,通过⼯具你能够将多个 .jar 实现绑定,而后通过 C# 调⽤原⽣的 Java 库。对⽐起 iOS,Android 的库绑定简略很多。

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

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

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

otnet new android-bindinglib -o Droid.AMap

进⼊该项⽬咱们看看⽂件构造

项⽬⾥⾯有 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 框架模式。

▌把 jar ⽂件增加到绑定项⽬

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

增加实现后,批改 .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\armeabiv7a\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 原⽣库绑定那么繁琐。而后编译⼀下,凡尔赛 + 星⾠⼤海了

排雷工作

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

  • ‘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='PoiCreato
r']/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='PoiCreato
r']/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.OnCame
raChangeListener']" />
  • ‘BusLineSearch’: member names cannot be the same as their enclosing type 

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

<attr
path="/api/package[@name='com.amap.api.services.busline']/class[@name='Bus
LineSearch']" name="managedName">AmapBusLineSearch</attr>
  • cannot change access modifiers when overriding ‘protected’ 

重载的时候呈现权限问题,这个时候你须要的是把权限修改好,如

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

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

找个 .NET for Android 项⽬看看

  • ⼤家能够去我的 GitHub 下载该示例

Android 的原⽣绑定⽐ iOS 的简略得多,所以更容易⼊⼿。心愿各位⼩搭档能多动⼿,有时候也是⼀个很好的体验。通过学习,置信⼤家也把握了如何⽤ .NET 绑定 iOS 和 Android 的原⽣库了。


咱们晓得 MAUI 是开发跨平台应⽤的解决⽅案,⽤ C# 能够间接把 iOS , Android , Windows , macOS , Linux ,Tizen 等应⽤开发进去。那咱们在这个框架除了⽤底层⾃定义的 UI 控件外,如果咱们要⽤如⾼德地图这样的 第三⽅控件,要如何做呢?接下来我就和⼤家介绍⼀下。

如果你还没有学习原⽣库绑定的常识,能够到以下链接学习相干内容:

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

在上⾯两个例⼦中咱们学习到把原⽣⾼德的 iOS / Android SDK 绑定,也⽤ .NET for iOS 和 .NET for Android 进⾏了调⽤。但要⽤ MAUI 就意味着调⽤⽅式扭转,⼀次性编写多平台使⽤。要实现这个成果,先看看 MAUI 的基础架构。

咱们能够分明看到,MAUI 除了公⽤的 xmal ⽂件外,实际上也把特定平台的⼀些设定搁置到 Platforms 的⽂件夹内,Platforms 的⾃⽂件夹就是对应的平台。咱们晓得能够依据不同平台去渲染平台界⾯。这就是咱们 常说的⾃定义平台控件了。

在前⾔局部咱们也提到了 MAUI 采⽤ Handler 模式去设定平台界⾯。如果咱们要实现⼀个⾼德地图的 MAUI 控件,具体的架构是这样的

咱们须要去创立如上图的⼀个构造,咱们须要为 AMap 增加⼀个共享⽂件 AMap.shared.cs,这个⽂件 AMapHandler 继⾃ ViewHandler。

 public interface IAMap : IView
 { }
 public class AMap : View, IAMap
 { }
 partial class AMapHandler
 {
 public static IPropertyMapper<AMap, AMapHandler> MapMapper = new
PropertyMapper<AMap, AMapHandler>(ViewHandler.ViewMapper)
 { };
 public AMapHandler() : base(MapMapper)
 {}}

而后在 Platforms 下的 Android 和 iOS ⽂件夹增加各⾃的平台 AMap 调⽤⽅法。

为 AMap.Android.cs 增加 Android 环境下⾼德地图的渲染⽅式

namespace AMap.UI.Apps
{
 public partial class AMapHandler : ViewHandler<IAMap, MapView>
 {
 private AMapHelper _mapHelper;
 private MapView mapView;
 internal static Bundle Bundle {get; set;}
 public AMapHandler(IPropertyMapper mapper, CommandMapper
commandMapper = null) : base(mapper, commandMapper)
 { }
 protected override MapView CreatePlatformView()
 {mapView = new Com.Amap.Api.Maps.MapView(Context);
03.UIControls.md 7/5/2022
4 / 8
 return mapView;
 }
 protected override void ConnectHandler(MapView platformView)
 {base.ConnectHandler(platformView);
 AMapLocationClient.UpdatePrivacyAgree(Context, true);
 AMapLocationClient.UpdatePrivacyShow(Context, true, true);
 _mapHelper = new AMapHelper(Bundle, platformView);
 mapView = _mapHelper.CallCreateMap();}
 }
 class AMapHelper : Java.Lang.Object
 {
 private Bundle _bundle;
 private MapView _mapView;
 public event EventHandler MapIsReady;
 public MapView Map {get; set;}
 public AMapHelper(Bundle bundle, MapView mapView)
 {
 _bundle = bundle;
 _mapView = mapView;
 }
 public MapView CallCreateMap()
 {
​
 _mapView.OnCreate(_bundle);
 return _mapView;
 }
 }
}

为 AMap.iOS.cs 增加 iOS 环境下⾼德地图的渲染⽅式

namespace AMap.UI.Apps
{
 public partial class AMapHandler : ViewHandler<IAMap, MAMapView>
 {
 public AMapHandler(IPropertyMapper mapper, CommandMapper
commandMapper = null) : base(mapper, commandMapper)
 { }
 protected override MAMapView CreatePlatformView()
 {
 MAMapView.UpdatePrivacyShow(AMapPrivacyShowStatus.DidShow,
AMapPrivacyInfoStatus.DidContain);
 MAMapView.UpdatePrivacyAgree(AMapPrivacyAgreeStatus.DidAgree);
 AMapServices.SharedServices.ApiKey = "";
 AMapServices.SharedServices.EnableHTTPS = true;
 //try
 //{MAMapView map = new MAMapView();
 map.SetShowsUserLocation(true);
 map.SetUserTrackingMode(MAUserTrackingMode.Follow);
 return map;
 }
 protected override void ConnectHandler(MAMapView PlatformView)
 { }
 protected override void DisconnectHandler(MAMapView PlatformView)
 {if (PlatformView.Delegate != null)
 {PlatformView.Delegate.Dispose();
 PlatformView.Delegate = null;
 }
 PlatformView.RemoveFromSuperview();}
 }
}

这⾥咱们要批改 MAUI 的项⽬⽂件,这⾥有⼏个设定须要留神的

  1. 因为这个控件只是针对 iOS / Android 两个平台,所以咱们只保留 net6.0-android 和 net6.0-ios 
  2. ⾼德 SDK 运⾏倡议在真机下使⽤,特地是 iOS,须要制订版本号,还有编译环境,我的环境是在 Apple silicon 下所以也要设定好 RuntimeIdentifier,还有就是编译的时候,我花了特地多工夫在这⾥,⼤家能够参考我这个在 GitHub 上⾃问⾃答的 Issue
    https://github.com/xamarin/xa… macios/issues/15372
 <PropertyGroup Condition="$(TargetFramework.Contains('-ios'))">
 <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
 <UseMSBuildEngine>true</UseMSBuildEngine>
 <WarningLevel>4</WarningLevel>
 <MtouchLink>SdkOnly</MtouchLink>
 <SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
 <DeviceSpecificBuild>true</DeviceSpecificBuild>
 <MtouchDebug>true</MtouchDebug>
 <MtouchFastDev>true</MtouchFastDev>
 <MtouchProfiling>true</MtouchProfiling>
 <MtouchUseSGen>true</MtouchUseSGen>
 <MtouchUseRefCounting>true</MtouchUseRefCounting>
 <MtouchFloat32>true</MtouchFloat32>
 </PropertyGroup>

3. 记得依照平台引⼊原⽣库的绑定

 <ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'ios' ">
 <ProjectReference
Include="..\iOS.AmapSDK.Foundation\iOS.AmapSDK.Foundation.csproj" />
 <ProjectReference Include="..\iOS.AmapSDK.3D\iOS.AmapSDK.3D.csproj" /> 
 </ItemGroup>

 <ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'android' ">
 <ProjectReference Include="..\Droid.AmapSDK\Droid.AmapSDK.csproj" />
 </ItemGroup>
  • 查看残缺项⽬⽂件,请点击该链接
  • 也别忘记去把⼀些平台特有的设定设置好,具体能够 iOS 设定请点击该链接
  • Android 设定请点击该链接

最初⼀步就是在 MauiProgram.cs 上注册

builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
 .ConfigureMauiHandlers(handlers =>
 {handlers.AddHandler(typeof(AMap), typeof(AMapHandler));
});

抉择编译运⾏就能够看到⾼德地图终于能够在 MAUI 环境下跑起来了

小结

对于很多⼈来说或者都是初步接触了 MAUI,实际上要做好多平台的兼容还要有⾮常⻓的路要⾛。心愿通过这个系列的⽂章,能给⼀些第三⽅⼚商和开发者⼀些帮忙,能尽快提供 MAUI 的⽀持。这样能力为这个新的技术注⼊活⼒。

相干材料:

  • . 通过 Microsoft Docs 理解 MAUI
  • 通过 Microsoft Learn 学习 MAUI
  • 使⽤⾼德地图 SDK for Android 请拜访
  • 理解 Android 原⽣库绑定的内容,请拜访
  • 学习 ViewHandler ⾃定义 MAUI 组件 请点击拜访该链接

长按辨认二维码
关注微软中国 MSDN                        

点击理解 MAUI~

正文完
 0