将iOS或Android的第三方SDK接入到Xamarin,不是一般的坑,虽然有官方文档,奈何奈何,依然十分滴蛋疼
在此,先感谢 前辈的分享 ,我直接入坑了
0.前言
-
一个Native Library Binding项目可绑定多个.Framework或.A类库
-
绑定MaMapKit和绑定FoundationKit方式相同 - 基础框架和地图框架
-
.framework结尾可能为.a静态库,也可能为.dylib动态库
-
在Linker Flags添加动态库时,添加-ObjC -all_load,之后再添加动态库:各动态库以中横线开头
必须去掉lib的ib字母:官方说法要简写,如libz需要添加中横线且去掉ib:-lz(模拟器Debug编译OK,运行报错无效 IL Code,真机Release运行OK:猜测是模拟器可能没有加载进动态库,真机在Debug下编译报错:找不到引用的动态库)- 在Xcode内添加动态库依然是需要中横线打头的
-
尤其重要的声明:一定要在真机且Release下运行,否则可能编译失败或运行Crash:模拟器可访问静态方法 - 8.21 编译的DLL真机DEBUG下也能调试,DLL的DEBUG和RELEASE是一样的文件 - 若是引用DLL则DEBUG下也可运行,希望仅仅是我遇到这个BUG
-
无效 IL Code是针对创建对象的:虽然可以通过KVC赋值取值,通过运行时特性判断方法是否实现,但这些都是针对对象:C#不支持指针,我是没法写调用的了;这些方式都是针对于对象,类加[Static],若是类在模拟器的Debug下即使对象存在,访问其属性方法也会导致Crash
-
修改iOS项目的iOS Build下的Linker behavior为Link Framework SDKs Only:加载依赖库
-
集成MaMapKit时,需要在iOS项目下的Resources下添加MaMap.bundle,一些地图显示本地资源
1.语言转换
- 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
在此备注下说明:
1.sharpie bind 为Xamarin提供的将OC代码转为C#代码的工具,仅仅针对调用,会将OC中的类转为C#内的接口形式进行调用
2.output=为输出转换后文件夹的路径,默认就在当前用户目录下,整理修改为桌面
3.--namespace为转换的代码咋C#内添加一个命名空间,命名空间定义不清楚自行百度
4.-framework为当前绑定SDK的类型,后接的是需要转换的SDK路径
5.-sdk iphoneos10.3需要适配到的iOS系统版本
2.代码修改
-
修改ApiDefine文件的BuildAction为ObjcBindingAPIDefinition ; Struct文件BuildAction修改为ObjcBindingCoreSource
-
将Stucts文件内的uint更改为ulong:有负数则修改为int;C#不允许字符作为枚举类型,因此修改为数值
-
[Verity]核对正确后注释掉 ; 在ApiDefine内将Constants的[Static]注释掉
-
OC和C#方法命名方式不一样:因此Sharpie转换会出现很多同名方法,这不是重载。C#声明修改为不一样即可
-
合并同名的Constants接口,报错Unsupported type for Fields
-
某些类继承/接口,出现找不到该类,注释掉继承即可:C#实现都是通过接口形式,而不是类
-
去掉所有声明里面的*:C#没有指针概念
-
OC点语法是编译器特性,其本质还是调用方法发送消息,因此若出现访问属性Crash可尝试将属性定义为方法
3.引用和依赖
- 引用:添加 Native References引用的framework文件:将引用的Framework文件拷贝到该绑定项目下,因为这是引用(引用的项目可以是.framework整个包,也可以是framework下的该类库文件:没有后缀)
- 依赖:右击添加引用的类库,弹出选择Properies,勾选Force Load和Smart Link;在Frameworks下添加.framework结尾的系统依赖库(.framework可能为.a,也可能为.dylib),在Linker Flags其她后缀的依赖库,这里基本为动态库
- 修改iOS项目的iOS Build下的Linker behavior为Link Framework SDKs Only:加载依赖库
- 集成MaMapKit时,需要在iOS项目下的Resources下添加MaMap.bundle,一些地必须的显示本地资源
添加的内容
1.Frameworks
OpenGLES UIKit Foundation CoreGraphics QuartzCore CoreLocation CoreTelephony SystemConfiguration Security AdSupport JavaScriptCore GLKit
2.Linker Flags
全写:-ObjC -all_load -libz -libc++ -libstdc++.6.0.9 (复制简写)
简写(官方说法:过长的描述可能导致引用失败):-ObjC -all_load -lz -lstdc++ -lc++
在Linker Flags添加动态库时,添加-ObjC -all_load,之后再添加动态库:各动态库以中横线开头:必须去掉lib的ib字母:官方说法要简写,如libz需要添加中横线且去掉ib:-lz(模拟器Debug编译OK,运行报错无效 IL Code,真机Release运行OK:猜测是模拟器可能没有加载进动态库,真机在Debug下编译报错:找不到引用的动态库)
4.权限设置
1.NSAppTransportSecurity字典下NSAllowsArbitraryLoads为BOOL类型其值为YES:兼容iOS 9 下版本
2.NSLocationUsageDescription:App需要您的同意,才能访问位置
3.NSLocationWhenInUseUsageDescription:App需要您的同意,才能在使用期间访问位置
4.NSLocationAlwaysUsageDescription:App需要您的同意,才能始终访问位置
若要后台定位,需要开启设置
5.新增接口
-
若该类有这个方法实现,Sharpie转换后没有生成,或是其父类的代码:此时都可以添加接口声明进行调用
-
若方法通过init...方式初始化,那么将alloc方法声明为[Static],之后init照常声明,调用时先调用alloc导出方法,在对应init...方法:这两个方法都是返回相同的对象,这是alloc没有参数:本质是alloc分配内存和初始化属性,iniit...才是自定义,因此init...在iOS中成为伪构造方法,若是init不做任何事,可直接调用new即可,new在C#中是可行的
6.代理使用
-
C#将类库的所有调用都转为接口形式,协议只是加了 [Protocol, Model] 修饰,因此在C#调用还是要基于接口形式(在OC中协议有optional和require两种形式,Xamarin默认实现是通过类,声明其方法未virtual和abstract形式)
-
C#也没有多继承,OC的多继承可通过协议实现;在C#中若要实现OC的协议,需要添加一个类,继承于该接口,在类的实现内重写接口内的实现,即OC协议的实现;将该类的对象赋值给代理,高德MaMapView代理有强弱两个,赋值其中一个就行:C#来实现OC协议可能会出现嵌套情况,因为针对没有协议都需要实现一个类
7.新增:地位集成(地位和地图是两套框架)
== 定位模块支持真机Debug和Release;模拟器只能获取到经纬度且不准确,没有地址描述 ==
== iOS项目在引用DLL时,需要设置iOS项目的iOS Build下的Linker Behavior为Link Framework SDKs Only ==
- 语言转换
sharpie bind --output=/users/timas-malk/desktop/AMapLocationKit --namespace=AMapLocationKit -framework /Users/timas-malk/Desktop/AMapLocationKit.framework -sdk iphoneos10.3
备注:Define内的最外层 [Static] 是需要被注释掉的,Structs内是不用
== iOS的协议在C#中是通过类建立一对一联系的,因此若出现回调,需要将调用类继承于定位类:作强制类型转换后回调源对象代理事件 ==== 无效:高德地图的类映射到C#变成了接口,而不再是类了。例如,继承AMapLocationManager,定位会不准确,而且永远获取不到逆地理编码:定位失败 - base调用也不可行;因此回调事件为静态事件 ==
再次备注 参考链接,感谢作者的入门分享
网友评论