點擊上方藍字
關注我們
(本文閱讀時間:10分鐘)
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/AMapMAUIControls 使?體驗 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/AMapMAUIControls/tree/main/Samples/iOS.Bindings/AMap.iOS.Demo
小結
原?庫綁定雖然?較多繁瑣的事情,但是實際上也是?分治愈的,當你看到編譯通過的那?刻,你就會明?個中的快樂。還有?點,很多?認為跨平臺移動開發不需要平臺的基礎知識了,實際還是需要。特別在這種原?庫的綁定上,就需要你既會 C# ?會 Objective-C 。希望該例?能給各位有所啟發。請?家期待下?篇 Android 原生庫綁定。
相關資源
通過 Microsoft Docs 了解 MAUI :
https://aka.ms/Docs.MAUI
通過 Microsoft Learn 學習 MAUI :
https://aka.ms/Learn.MAUI
通過 Microsoft Docs 了解 :
MAUI https://aka.ms/Docs.MAUI
通過 Microsoft Learn 學習 MAUI:
https://aka.ms/Learn.MAUI
使??德地圖 SDK for iOS 請訪問:
https://developer.amap.com/api/ios-sdk/gettingstarted
了解 iOS 原?庫綁定的內容,請訪問 :
https://docs.microsoft.com/zh-cn/xamarin/cross-platform/macios/binding/?context=xamarin%2Fios
謝謝你讀完了本文~相信你一定有一些感想、觀點、問題想要表達。歡迎在評論區暢所欲言,期待聽到你的“聲音”哦!
同時,喜歡的內容也不要忘記轉發給你的小伙伴們,謝謝你的支持!
長按識別二維碼
關注微軟中國MSDN
點擊「閱讀原文」了解MAUI~