Xamarin之iOS綁定高德Amap那些坑

將iOS或Android的第三方SDK接入到Xamarin,不是一般的坑,雖然有官方文檔,奈何奈何,依然十分滴蛋疼

在此,先感謝 前輩的分享 ,我直接入坑了

0.前言

  1. 一個(gè)Native Library Binding項(xiàng)目可綁定多個(gè).Framework或.A類庫(kù)

  2. 綁定MaMapKit和綁定FoundationKit方式相同 - 基礎(chǔ)框架和地圖框架

  3. .framework結(jié)尾可能為.a靜態(tài)庫(kù),也可能為.dylib動(dòng)態(tài)庫(kù)

  4. 在Linker Flags添加動(dòng)態(tài)庫(kù)時(shí),添加-ObjC -all_load,之后再添加動(dòng)態(tài)庫(kù):各動(dòng)態(tài)庫(kù)以中橫線開(kāi)頭

必須去掉lib的ib字母:官方說(shuō)法要簡(jiǎn)寫(xiě),如libz需要添加中橫線且去掉ib:-lz(模擬器Debug編譯OK,運(yùn)行報(bào)錯(cuò)無(wú)效 IL Code,真機(jī)Release運(yùn)行OK:猜測(cè)是模擬器可能沒(méi)有加載進(jìn)動(dòng)態(tài)庫(kù),真機(jī)在Debug下編譯報(bào)錯(cuò):找不到引用的動(dòng)態(tài)庫(kù))- 在Xcode內(nèi)添加動(dòng)態(tài)庫(kù)依然是需要中橫線打頭的

  1. 尤其重要的聲明:一定要在真機(jī)且Release下運(yùn)行,否則可能編譯失敗或運(yùn)行Crash:模擬器可訪問(wèn)靜態(tài)方法 - 8.21 編譯的DLL真機(jī)DEBUG下也能調(diào)試,DLL的DEBUG和RELEASE是一樣的文件 - 若是引用DLL則DEBUG下也可運(yùn)行,希望僅僅是我遇到這個(gè)BUG

  2. 無(wú)效 IL Code是針對(duì)創(chuàng)建對(duì)象的:雖然可以通過(guò)KVC賦值取值,通過(guò)運(yùn)行時(shí)特性判斷方法是否實(shí)現(xiàn),但這些都是針對(duì)對(duì)象:C#不支持指針,我是沒(méi)法寫(xiě)調(diào)用的了;這些方式都是針對(duì)于對(duì)象,類加[Static],若是類在模擬器的Debug下即使對(duì)象存在,訪問(wèn)其屬性方法也會(huì)導(dǎo)致Crash

  3. 修改iOS項(xiàng)目的iOS Build下的Linker behavior為L(zhǎng)ink Framework SDKs Only:加載依賴庫(kù)

  4. 集成MaMapKit時(shí),需要在iOS項(xiàng)目下的Resources下添加MaMap.bundle,一些地圖顯示本地資源

1.語(yǔ)言轉(zhuǎn)換

  • MaMapKit
sharpie bind --output=/users/timas-malk/desktop/MAMapKit --namespace=MAMapKit -framework /Users/timas-malk/Desktop/MAMapKit.framework -sdk iphoneos10.3
  • AMapFoundationKit
sharpie bind --output=/users/timas-malk/desktop/AMapFoundationKit --namespace=AMapFoundationKit -framework /Users/timas-malk/Desktop/AMapFoundationKit.framework -sdk iphoneos10.3
在此備注下說(shuō)明:

1.sharpie bind 為Xamarin提供的將OC代碼轉(zhuǎn)為C#代碼的工具,僅僅針對(duì)調(diào)用,會(huì)將OC中的類轉(zhuǎn)為C#內(nèi)的接口形式進(jìn)行調(diào)用
2.output=為輸出轉(zhuǎn)換后文件夾的路徑,默認(rèn)就在當(dāng)前用戶目錄下,整理修改為桌面
3.--namespace為轉(zhuǎn)換的代碼咋C#內(nèi)添加一個(gè)命名空間,命名空間定義不清楚自行百度
4.-framework為當(dāng)前綁定SDK的類型,后接的是需要轉(zhuǎn)換的SDK路徑
5.-sdk iphoneos10.3需要適配到的iOS系統(tǒng)版本

2.代碼修改

  1. 修改ApiDefine文件的BuildAction為ObjcBindingAPIDefinition ; Struct文件BuildAction修改為ObjcBindingCoreSource

  2. 將Stucts文件內(nèi)的uint更改為ulong:有負(fù)數(shù)則修改為int;C#不允許字符作為枚舉類型,因此修改為數(shù)值

  3. [Verity]核對(duì)正確后注釋掉 ; 在ApiDefine內(nèi)將Constants的[Static]注釋掉

  4. OC和C#方法命名方式不一樣:因此Sharpie轉(zhuǎn)換會(huì)出現(xiàn)很多同名方法,這不是重載。C#聲明修改為不一樣即可

  5. 合并同名的Constants接口,報(bào)錯(cuò)Unsupported type for Fields

  6. 某些類繼承/接口,出現(xiàn)找不到該類,注釋掉繼承即可:C#實(shí)現(xiàn)都是通過(guò)接口形式,而不是類

  7. 去掉所有聲明里面的*:C#沒(méi)有指針概念

  8. OC點(diǎn)語(yǔ)法是編譯器特性,其本質(zhì)還是調(diào)用方法發(fā)送消息,因此若出現(xiàn)訪問(wèn)屬性Crash可嘗試將屬性定義為方法

3.引用和依賴

  1. 引用:添加 Native References引用的framework文件:將引用的Framework文件拷貝到該綁定項(xiàng)目下,因?yàn)檫@是引用(引用的項(xiàng)目可以是.framework整個(gè)包,也可以是framework下的該類庫(kù)文件:沒(méi)有后綴)
  2. 依賴:右擊添加引用的類庫(kù),彈出選擇Properies,勾選Force Load和Smart Link;在Frameworks下添加.framework結(jié)尾的系統(tǒng)依賴庫(kù)(.framework可能為.a,也可能為.dylib),在Linker Flags其她后綴的依賴庫(kù),這里基本為動(dòng)態(tài)庫(kù)
  3. 修改iOS項(xiàng)目的iOS Build下的Linker behavior為L(zhǎng)ink Framework SDKs Only:加載依賴庫(kù)
  4. 集成MaMapKit時(shí),需要在iOS項(xiàng)目下的Resources下添加MaMap.bundle,一些地必須的顯示本地資源
添加的內(nèi)容

1.Frameworks

OpenGLES UIKit Foundation CoreGraphics QuartzCore CoreLocation CoreTelephony SystemConfiguration Security AdSupport JavaScriptCore GLKit

2.Linker Flags

全寫(xiě):-ObjC -all_load -libz -libc++ -libstdc++.6.0.9 (復(fù)制簡(jiǎn)寫(xiě))
簡(jiǎn)寫(xiě)(官方說(shuō)法:過(guò)長(zhǎng)的描述可能導(dǎo)致引用失敗):-ObjC -all_load -lz -lstdc++ -lc++

在Linker Flags添加動(dòng)態(tài)庫(kù)時(shí),添加-ObjC -all_load,之后再添加動(dòng)態(tài)庫(kù):各動(dòng)態(tài)庫(kù)以中橫線開(kāi)頭:必須去掉lib的ib字母:官方說(shuō)法要簡(jiǎn)寫(xiě),如libz需要添加中橫線且去掉ib:-lz(模擬器Debug編譯OK,運(yùn)行報(bào)錯(cuò)無(wú)效 IL Code,真機(jī)Release運(yùn)行OK:猜測(cè)是模擬器可能沒(méi)有加載進(jìn)動(dòng)態(tài)庫(kù),真機(jī)在Debug下編譯報(bào)錯(cuò):找不到引用的動(dòng)態(tài)庫(kù))

4.權(quán)限設(shè)置

1.NSAppTransportSecurity字典下NSAllowsArbitraryLoads為BOOL類型其值為YES:兼容iOS 9 下版本
2.NSLocationUsageDescription:App需要您的同意,才能訪問(wèn)位置
3.NSLocationWhenInUseUsageDescription:App需要您的同意,才能在使用期間訪問(wèn)位置
4.NSLocationAlwaysUsageDescription:App需要您的同意,才能始終訪問(wèn)位置

若要后臺(tái)定位,需要開(kāi)啟設(shè)置

5.新增接口

  1. 若該類有這個(gè)方法實(shí)現(xiàn),Sharpie轉(zhuǎn)換后沒(méi)有生成,或是其父類的代碼:此時(shí)都可以添加接口聲明進(jìn)行調(diào)用

  2. 若方法通過(guò)init...方式初始化,那么將alloc方法聲明為[Static],之后init照常聲明,調(diào)用時(shí)先調(diào)用alloc導(dǎo)出方法,在對(duì)應(yīng)init...方法:這兩個(gè)方法都是返回相同的對(duì)象,這是alloc沒(méi)有參數(shù):本質(zhì)是alloc分配內(nèi)存和初始化屬性,iniit...才是自定義,因此init...在iOS中成為偽構(gòu)造方法,若是init不做任何事,可直接調(diào)用new即可,new在C#中是可行的

6.代理使用

  1. C#將類庫(kù)的所有調(diào)用都轉(zhuǎn)為接口形式,協(xié)議只是加了 [Protocol, Model] 修飾,因此在C#調(diào)用還是要基于接口形式(在OC中協(xié)議有optional和require兩種形式,Xamarin默認(rèn)實(shí)現(xiàn)是通過(guò)類,聲明其方法未virtual和abstract形式)

  2. C#也沒(méi)有多繼承,OC的多繼承可通過(guò)協(xié)議實(shí)現(xiàn);在C#中若要實(shí)現(xiàn)OC的協(xié)議,需要添加一個(gè)類,繼承于該接口,在類的實(shí)現(xiàn)內(nèi)重寫(xiě)接口內(nèi)的實(shí)現(xiàn),即OC協(xié)議的實(shí)現(xiàn);將該類的對(duì)象賦值給代理,高德MaMapView代理有強(qiáng)弱兩個(gè),賦值其中一個(gè)就行:C#來(lái)實(shí)現(xiàn)OC協(xié)議可能會(huì)出現(xiàn)嵌套情況,因?yàn)獒槍?duì)沒(méi)有協(xié)議都需要實(shí)現(xiàn)一個(gè)類

7.新增:地位集成(地位和地圖是兩套框架)

== 定位模塊支持真機(jī)Debug和Release;模擬器只能獲取到經(jīng)緯度且不準(zhǔn)確,沒(méi)有地址描述 ==
== iOS項(xiàng)目在引用DLL時(shí),需要設(shè)置iOS項(xiàng)目的iOS Build下的Linker Behavior為L(zhǎng)ink Framework SDKs Only ==

  • 語(yǔ)言轉(zhuǎn)換
sharpie bind --output=/users/timas-malk/desktop/AMapLocationKit --namespace=AMapLocationKit -framework /Users/timas-malk/Desktop/AMapLocationKit.framework -sdk iphoneos10.3

備注:Define內(nèi)的最外層 [Static] 是需要被注釋掉的,Structs內(nèi)是不用

== iOS的協(xié)議在C#中是通過(guò)類建立一對(duì)一聯(lián)系的,因此若出現(xiàn)回調(diào),需要將調(diào)用類繼承于定位類:作強(qiáng)制類型轉(zhuǎn)換后回調(diào)源對(duì)象代理事件 ==== 無(wú)效:高德地圖的類映射到C#變成了接口,而不再是類了。例如,繼承AMapLocationManager,定位會(huì)不準(zhǔn)確,而且永遠(yuǎn)獲取不到逆地理編碼:定位失敗 - base調(diào)用也不可行;因此回調(diào)事件為靜態(tài)事件 ==

再次備注 參考鏈接,感謝作者的入門(mén)分享

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容