共计 9535 个字符,预计需要花费 24 分钟才能阅读完成。
Microsoft Build 2022 ⼤会上正式公布了 .NET MAUI , 对于 .NET 开发者能够⽤ C# 实现跨平台的前端应⽤开发。对⽐起 MAUI 的前身 Xamarin , MAUI 除了能够⽤传统的原⽣开发模式外,还⽀持了 Blazor 的混合式开发。这也让更多⽅向的开发⼈员能进⼊到跨平台的应⽤开发中来。有⼈会提出云原⽣时代,前端开发还重要吗?实际上,多端应⽤兼容是云原⽣不可短少的⻔⾯。互联⽹时代,有很多出⾊的应⽤,并公布了针对第三⽅应⽤的 SDK,开发者能够联合这些 SDK 做相干的解决⽅案。通过 MAUI 能调⽤这些 SDK 吗?我会通过系列⽂章去和⼤家介绍。
为何要绑定原⽣ SDK
咱们晓得⼀个应⽤能够融⼊不同的场景,例如⼀个打⻋应⽤就须要地图,例如⼀个拍照应⽤就须要社交,例如⼀个如果你是传统的物联⽹应⽤你须要⼀个蓝⽛的通信协议。拿来主义就是⼀个节俭的⽅式,能够联合第三⽅提供的 SDK 来实现应⽤的开发。对于 .NET 开发⼈员会是⼀个难点,因为习惯性地去调⽤ DLL,但在 iOS / Android 原⽣开发上,实际上是有不同的库调⽤机制。在 Xamarin 时代,就有不少开发者去⽤ C# 绑定第三⽅的库,例如在中国市场就有⽀付宝,微信,⾼德地图等。到了 MAUI 有什么不⼀样呢?在⼤致上是和 Xamarin 绑定⽅式⼀样。但因为 MAUI 融⼊到了 .NET 6,实际上就是⼀个项⽬⽂件格局的扭转。现阶段你能够通过命令⾏的⽅式疾速构建 iOS / Android 的绑定项⽬。
▌MAUI iOS 库的绑定
dotnet new iosbinding -o iOS.AMapSDK.Binding
要做 iOS / macOS 的绑定你除了创立绑定项⽬外,你还须要装置 Shapie ⼯具 (https://aka.ms/objectivesharpie)做对应转换, 能够通过命令⾏去针对 iOS 的动静库和动态库做对应转换。这⾥补充⼀点你的 Xcode 环境是必须要装置的。下⾯是⼀个简略的转换语句,更多具体⼤家能够关注我的该系列的 iOS 库⽂件绑定⽂章。
sharpie bind -framework /your path/AMapFoundationKit.framework -sdk
iphoneos15.5
▌MAUI Android 库的绑定
dotnet new android-bindinglib -o Droid.AMapSDK.Binding
Android 的绑定和 iOS 不⼀样,间接把第三⽅库 Android SDK 的 jar 或者 aar 包放进去编译即可。
如果你心愿理解更多能够关注本系列 Android 库绑定的系列⽂章。
控件定制
在 Xamarin.Forms 中,通过渲染器机制对跨平台各⾃控件的引⽤,并且依赖于 INotifyPropertyChanged。.NET MAUI 没勾销了渲染器机制,⽽是引⼊了⼀种称为 Handler 的模式。有了 Handlers 更灵便,⽽且在须要时更容易扩大或笼罩。
这是 MAUI 全新的 Handler 模式
咱们通过 Handler 机制能够构建好⾼德地图的 MAUI 控件
你能够通过 https://github.com/kinfey/AMa… 使⽤体验 MAUI 的⾼德 Android / iOS 控件
介绍了⼀些做⾼德地图的 iOS / Android MAUI 控件的次要常识之后,接下来将重点介绍 iOS 原⽣库绑定的常识,并通知⼤家在绑定原⽣库过程的⼀些技巧,心愿给到⼩搭档⼀些启发。
意识 iOS 动静库和动态库
在绑定之前,咱们须要学习⼀下 iOS 的动静库和动态库。最简略了解的⽅式是在 iOS 中动态库是以 .a 后缀结尾,动静库是以 .dylib 后缀结尾。⽆论动态库和动静库都能够打包成 Framework。
▌动态库和动静库的区别
- 动态库的特点是编译时会把库⽂件间接拷⻉⼀份到⽬标应⽤程序,⽽这个拷⻉是驻留在⽬标应⽤程序⾥⾯的,所以编译实现后,动态库的⽂件就没有⽤了。但有个毛病就是,因为须要拷⻉,所以⽣成的应⽤程序的容量会较⼤。
- 动静库和动态库刚好是相同,编译的时候是不会拷⻉到⽬标应⽤程序⾥⾯的,所以⽣成应⽤程序的体积较⼩,⽽且⼀个动静库能够共享给多个应⽤程序使⽤。但⽣成应⽤程序是依赖于动静库,这也导致常常会呈现动静库找不到的状况。
咱们来拆解⼀下⾼德地图根底的 SDK – AMapFoundationKit.framework
这⾥就蕴含了对应的头⽂件信息,模块信息,以及动态库。你能够清晰看到⾼德地图打包成 Framrwork 的实现。这也是咱们对库概念的意识,编译好的⼆进制代码,向外裸露头⽂件给第三⽅开发者使⽤。
通过 Sharpie ⼯具⽣成 C# 调⽤的接⼝
Shapie 是⼀个⾮常好⽤的转换⼯具,它⽀持在 macOS 下对 Objective-C 的库的转。通过 Sharpie 能够对库⽂件给出的头⽂件进⾏转换实现 C# 的绑定。在 MAUI 前身 Shapie ⼯具就曾经存在,我常常就利⽤这个⼯具做转换。
因为这次⾼德地图的性能我⽤到 3D,所以我会对⾼德的 AMapFoundationKit.Framework 和 MAMapKit.framework 两个 Framework 进⾏绑定转换。
▌转换 AMapFoundationKit.Framework
sharpie bind -framework AMapFoundationKit.framework -sdk iphoneos15.5
▌转换 MAMapKit.framework
sharpie bind -framework MAMapKit.framework -sdk iphoneos15.5
补充:MAMapKit.framework 依赖于 AMapFoundationKit.framework,所以要放在⼀个雷同的⽬录下。
这⾥⾯要留神,你须要装置好 Xcode,倡议装置到最新,并对应最新的 iOS SDK , 当然你也能够依据须要绑定不同版本的 iOS SDK , 你能够通过⼀次是命令查看环境
sharpie xcode -sdks
通过命令⾏绑定⽣成的是两个⽂件是 StructsAndEnums.cs 和 ApiDefinitions.cs,StructsAndEnums.cs 对应的是⼀些常量和枚举类型,ApiDefinitions.cs 对应的是⼀些接⼝和⽅法。
创立 MAUI 的 iOS 绑定项⽬
这⾥创立须要留神,当初 Visual Studio 2022 的模版都没有实现,当初⼤家⽤命令⾏创立,因为咱们有两个项⽬,须要创立两个 Binding 的项⽬别离是针对于 AMapFoundationKit.Framework 的项⽬构建
dotnet new iosbinding -o iOS.AMap.Foundation
针对于 MAMapKit.framework 的项⽬构建
`
dotnet new iosbinding -o iOS.AMap.3D
`
⽣成好后,须要把 AMapFoundationKit.framework 放到 iOS.AMap.Foundation 的⽬录下,MAMapKit.framework 放到 iOS.AMap.3D ⽬录下。并把⽣成的 StructsAndEnums.cs 和 ApiDefinitions.cs 放到对应⽬录。
项⽬设置调整
1. 在 Sharpie ⽣成的⽬录下 StructsAndEnum.cs,⽽在构建的 Binding ⽬录下是 ApiDefinition.cs,要把它替换掉。所以要对 .csproj 项⽬进⾏批改
<ItemGroup>
<ObjcBindingApiDefinition Include="ApiDefinitions.cs" />
<ObjcBindingCoreSource Include="StructsAndEnums.cs" />
</ItemGroup>
2. 对 iOS.AMap.Foundation 进⾏编译
▌在 AMapFoundationKit.framework.csproj 减少对 Framework 的引⽤
<ItemGroup>
<NativeReference Include="AMapFoundationKit.framework">
<Kind>Framework</Kind>
<ForceLoad>True</ForceLoad>
<SmartLink>False</SmartLink>
</NativeReference>
</ItemGroup>
Kind:原⽣绑定类型能够是 Framwork 也能够是 StaticLibary
ForceLoad:强加载,抉择 True
SmartLink:智能链接
实现的项⽬.csproj 设置为
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-ios</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<IsBindingProject>true</IsBindingProject>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoBindingEmbedding>false</NoBindingEmbedding>
</PropertyGroup>
<ItemGroup>
<ObjcBindingApiDefinition Include="ApiDefinitions.cs" />
<ObjcBindingCoreSource Include="StructsAndEnums.cs" />
</ItemGroup>
<ItemGroup>
<NativeReference Include="AMapFoundationKit.framework">
<Kind>Framework</Kind>
<ForceLoad>True</ForceLoad>
<SmartLink>False</SmartLink>
</NativeReference>
</ItemGroup>
</Project>
编译 iOS.AMap.Foundation,你会感觉奔溃,因为⾮常多的出错信息。这是因为 Shapie 做转换时,⼀些转换没做好导致的,这个时候你就须要⼀个⼀个进⾏调整
▌归类⼀下出错信息
- The type or namespace name ‘VerifyAttribute’ could not be found
这类信息时因为转换时候没有确认好属性,所以会减少 VerifyAttribute 字段,这个⼀般状况下把这个字段正文掉就能够了,如
static class CFunctions
{// NSString * AMapEmptyStringIfNil (NSString *s);
[DllImport ("__Internal")]
// [Verify (PlatformInvoke)]
static extern NSString AMapEmptyStringIfNil (NSString s);
// extern CLLocationCoordinate2D AMapCoordinateConvert
(CLLocationCoordinate2D coordinate, AMapCoordinateType type);
[DllImport ("__Internal")]
// [Verify (PlatformInvoke)]
static extern CLLocationCoordinate2D AMapCoordinateConvert
(CLLocationCoordinate2D coordinate, AMapCoordinateType type);
// extern BOOL AMapDataAvailableForCoordinate (CLLocationCoordinate2D
coordinate);
[DllImport ("__Internal")]
// [Verify (PlatformInvoke)]
static extern bool AMapDataAvailableForCoordinate
(CLLocationCoordinate2D coordinate);
}
The type or namespace name 'AMapFoundationKit'
命名空间问题,这个你须要为 StructsAndEnums.cs 和 ApiDefinitions.cs 减少命名控件就能够了,你能够间接⽤ AMapFoundationKit,也能够⾃⼰批改喜爱的名字,我这⾥⽤ iOS.AMap.Foundation 名字和项⽬对应
- Duplicate ‘Static’ attribute
这个是因为 ApiDefinitions.cs 的 Constants 反复定义了,这个就须要重新整理归并为⼀个就能够了
- Unsupported type for Fields: bool for ‘iOS.AMap.Foundation.Constants _amapLocationOverseas’.e
类型不对应导致编译不通过,这个时候我批改为
[Field ("_amapLocationOverseas", "__Internal")]
IntPtr _amapLocationOverseas {get;}
这样你就能够编译通过 iOS.AMap.Foundation
3. 对 iOS.AMap.3D 进⾏编译
▌增加对 iOS.AMap.Foundation 的引⽤
因为 MAMapKit.framework 依赖于 AMapFoundationKit.framework,所以 iOS.AMap.3D 是依赖于 iOS.AMap.Foundation
<ItemGroup>
<ProjectReference
Include="..\iOS.Amap.Foundation\iOS.Amap.Foundation.csproj" />
</ItemGroup>
▌引⼊ MAMapKit.framework
<ItemGroup>
<NativeReference Include="MAMapKit.framework">
<Kind>Framework</Kind>
<ForceLoad>True</ForceLoad>
<SmartLink>True</SmartLink>
<Frameworks>GLKit OpenGLES UIKit Foundation CoreGraphics QuartzCore
CoreLocation CoreTelephony SystemConfiguration Security AdSupport
JavaScriptCore</Frameworks>
<LinkerFlags>-lz -lstdc++ -lc++</LinkerFlags>
</NativeReference>
</ItemGroup>
这个和 AMapFoundationKit.framework 不⼀样的,须要增加 Framework 编译时须要依赖的项,以及⽤到的编译⽅式,这个和你绑定的 framework 无关,我这⾥抉择⾼德地图,所以依照它们的⽂档要求做了相干设置。
实现的项⽬.csproj 设置为
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-ios</TargetFramework>
<RootNamespace>iOS.Amap._3D</RootNamespace>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<IsBindingProject>true</IsBindingProject>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoBindingEmbedding>false</NoBindingEmbedding>
</PropertyGroup>
<ItemGroup>
<ObjcBindingApiDefinition Include="ApiDefinitions.cs" />
<ObjcBindingCoreSource Include="StructsAndEnums.cs" />
</ItemGroup>
<ItemGroup>
<NativeReference Include="MAMapKit.framework">
<Kind>Framework</Kind>
<ForceLoad>True</ForceLoad>
<SmartLink>True</SmartLink>
<Frameworks>GLKit OpenGLES UIKit Foundation CoreGraphics QuartzCore
CoreLocation CoreTelephony SystemConfiguration Security AdSupport
JavaScriptCore</Frameworks>
<LinkerFlags>-lz -lstdc++ -lc++</LinkerFlags>
</NativeReference>
</ItemGroup>
<ItemGroup>
<ProjectReference
Include="..\iOS.Amap.Foundation\iOS.Amap.Foundation.csproj" />
</ItemGroup>
</Project>
编译 iOS.AMap.3D,你会⽐之前更奔溃,这个时候你须要有⾜够的耐⼼,除了和之前差不多的出错信息外,还有⼀些新的情况,我这⾥列举⼀下
- Type ‘MAMapViewDelegate’ already defines a member called ‘MapView’ with the same parameter types
造成这个起因是因为⽅法重名了,这也是 Objective-C 申明式语法和传统语法不⼀样的地⽅,所以你要针对这个做重命名
如这个
// @optional -(void)mapView:(MAMapView *)mapView didAnnotationViewTapped:
(MAAnnotationView *)view;
[Export ("mapView:didAnnotationViewTapped:")]
void MapView (MAMapView mapView, MAAnnotationView view);
批改为
// @optional -(void)mapView:(MAMapView *)mapView didAnnotationViewTapped:
(MAAnnotationView *)view;
[Export ("mapView:didAnnotationViewTapped:")]
void MapViewDidAnnotationViewTapped (MAMapView mapView, MAAnnotationView
view);
-
The type or namespace name ‘IMAOverlay’ could not be found
这个是命名出错,在 ApiDefinitions.cs ⽂件中你能够找到 MAOverlay[Protocol] interface MAOverlay : IMAAnnotation {// @required -(CLLocationCoordinate2D)coordinate; [Abstract] [Export ("coordinate")] // [Verify (MethodToProperty)] CLLocationCoordinate2D Coordinate {get;} // @required -(MAMapRect)boundingMapRect; [Abstract] [Export ("boundingMapRect")] // [Verify (MethodToProperty)] MAMapRect BoundingMapRect {get;} }
所以把所有 IMAOverlay 替换为 MAOverlay 即可。
- The type or namespace name ‘AutoGeneratedName’ could not be found
把 AutoGeneratedName 勾销
- Constant value ‘-1’ cannot be converted to a ‘ulong’
指定类型谬误 AllCorners = ~0x0 改为 AllCorners = 0x0
Do not know how to make a signature for CoreLocation.CLLocationCoordinate2D in parameter`coordinates’
C# 是没有指针的,在 Sharpie 转换时出错了
- ‘MAMapView_UserLocation.HeadingFilter’: cannot declare instance members in a static class
// @property (nonatomic) CLLocationDegrees headingFilter;
[Export ("headingFilter")]
double HeadingFilter({ get; set;})
这个定义要换成
// @property (nonatomic) CLLocationDegrees headingFilter;
[Export ("headingFilter")]
double HeadingFilter();
- Cannot convert type ‘Foundation.NSObject’ to ‘nint’
- // @property (nonatomic, weak) id<MAOverlayRenderDelegate>
- rendererDelegate;
- [NullAllowed, Export (“rendererDelegate”, ArgumentSemantic.Weak)]
- NSObject WeakRendererDelegate {get; set;}
批改为
// @property (nonatomic, weak) id<MAOverlayRenderDelegate>
rendererDelegate;
[NullAllowed, Export ("rendererDelegate", ArgumentSemantic.Weak)]
IntPtr WeakRendererDelegate {get; set;}
或者排除是⼀个漫⻓的过程,但编译胜利⼀刻你会⾮常兴奋,这样咱们就把 AMapFoundationKit.framework 和 MAMapKit.framework 绑定胜利了。
尝试创立⼀个 .NET for iOS 项⽬验证⼀下
- 具体实现请到我的 GitHub Repo 下载:
https://github.com/kinfey/AMa…
小结
原⽣库绑定尽管⽐较多繁琐的事件,然而实际上也是⼗分治愈的,当你看到编译通过的那⼀刻,你就会明⽩个中的高兴。还有⼀点,很多⼈认为跨平台挪动开发不须要平台的基础知识了,理论还是须要。特地在这种原⽣库的绑定上,就须要你既会 C# ⼜会 Objective-C。心愿该例⼦能给各位有所启发。请⼤家期待下⼀篇 Android 原生库绑定。
相干资源
- 通过 Microsoft Docs 理解 MAUI
- 通过 Microsoft Learn 学习 MAUI
- 通过 Microsoft Docs 理解
- 通过 Microsoft Learn 学习 MAUI
- 使⽤⾼德地图 SDK for iOS 请拜访
- 理解 iOS 原⽣库绑定的内容,请拜访
长按辨认二维码
关注微软中国 MSDN
点击理解 MAUI