Writing / Archive / 2017

Xamarin.iOS 集成第三方库

最近公司用 Xamarin 开发的项目里需要集成一个第三方 SDK,名字叫做听云,一个应用性能监控平台。听云提供的 SDK 是用 OC 写的,而 Xamarin 要用的话需要先转成它可以使用的形式,所以花了几天时间研究这个东西。坑很多…

Published
Topic
Engineering
Status
Historical archive

这篇文章保留原始正文、图片和发布日期,并使用当前网站的统一阅读界面。

最近公司用 Xamarin 开发的项目里需要集成一个第三方 SDK,名字叫做听云,一个应用性能监控平台。听云提供的 SDK 是用 OC 写的,而 Xamarin 要用的话需要先转成它可以使用的形式,所以花了几天时间研究这个东西。坑很多,我先踏为敬。

iOS 第三方库一般分为静态库和动态库,前者通常以 .a 为后缀,后者以 .framework 为后缀。两者的区别如下:

静态库(Static Library) — 源代码编译形成目标文件的合集,本质上是源代码的实现所对应的二进制实现。配合上一起提供的 .h 文件,可以获取到静态库中暴露的属性和方法。

动态库(Dynamic Framework) — 相当于一个随时可调用包,比如 iOS SDK 的 UIKit 之类的系统库就是动态库。相比静态库来说,动态库不需要 .h 文件就可以直接调用,而且只需要加载一次,对程序的执行效率相对于静态库有所提高。

动态库相比静态库有许多优点,可以控制加载时机,这意味着通过服务端下发动态库可以对 App 实现热更新,包括但不局限与修复 bug,同时也可以动态更新 App 界面布局和业务逻辑,也就意味着可以像前端一样,抛弃版本的概念,所有用户每次进入应用获取的都是最新版。

但遗憾的是,Apple 不允许第三方框架使用动态库,只有系统框架可以通过动态方式加载。不然广大开发者又何必费尽心思搞出各种 patch,各种混合开发框架又怎会大行其道,一声叹息啊。

下面以一个最近做的例子,听云 SDK 的集成,来具体说明下如何将 OC 原生动态库转换成 Xamarin.iOS 能够使用的 dll 动态链接库。

下载下来的 SDK 目录如下所示:

首先将图中用红框圈起来的文件 tingyunApp 名称改为 tingyunApp.a,然后需要用到 Sharpie 这个 Xamarin 官方提供的命令行工具,可以在官方网站下载安装。安装完成之后,在终端 cd 到 Headers 的上一级,键入下面的命令:

sharpie bind –output=tingyunApp.iOS –namespace=tingyunApp.iOS –sdk=iphoneos10.2 /Users/xxpang/Desktop/tingyun/tingyunApp.framework/Versions/A/Headers/NBSAppAgent.h /Users/xxpang/Desktop/tingyun/tingyunApp.framework/Versions/A/Headers/NBSGCDOverrider.h

如果路径没错的话,在终端可以看到如下界面:

然后在 Finder 用户文件夹下可以看到生成的 tingyunApp.iOS 文件夹,里面有刚才生成的 ApiDefinitions.cs 和 StructsAndEnums.cs 两个文件。

至此,我们完成了将 OC 库 转为 C# 库的第一步。下面在 Xamarin Studio 里新建一个 Binding Library 项目,如下所示:

新建的 Binding Library 项目目录结构如下:

下一步就用到我们第一步里改名的文件:tingyunApp.a,在 本机引用 上右击 Add Native Reference,将 framework 中的 tingyunApp.a 添加到项目中,然后在添加的文件上右击属性,在 IDE 右侧出现的面板里填写需要用到的系统库,比如 Security.framework、CoreTelephony.framework 等,如果需要添加 libz.tbd 等类库的话,需要在 Linker Flags 后面加上相应描述,具体如下图所示:

完成这些之后,下面需要进行的是将命令行生成的两个文件里面的内容,复制替换掉原来的内容,需要注意的是,namespace 名称需要跟项目名称保持一致。替换完成后,正常情况下编译运行是会报错的,这是做 Xamarin 应该有的基本觉悟了。当然,如果你编译通过了,说明你很幸运,恭喜。

Sharpie 这个命令行工具的原理,是将 OC 的头文件以及对应的方法实现,一一映射成 C# 可以直接调用的方法,再结合 tingyunApp.a 文件生成 Xamarin 可以使用的类库,原理如下图所示。

上面说了,Sharpie 的作用是将原生库里的方法一一映射成 C# 的类和方法,类似的还有他们用 C# 重写了 iOS SDK 的所有方法。不过呢,说是一一映射,还是有一些不合适的转换,所以才会编译报错,接下来会是一个比较痛苦的过程。

如上图所示,在 ApiDefinition.h 文件中我们可以看到很多划红线的地方,这些有的不影响编译和运行,有的会影响,又不能简单粗暴地删除或者注释,因为他们都对应着原生库里面的方法,不处理又不能编译运行通过。

如上图,在 Structs.h 文件中有一些 [Verify] 标签,这些标签是系统用来提示开发者需要确认的地方,修改完错误之后需要删掉。说到这里就得再说一个大坑了,官方提供了一个原生方法和 C# 方法转换方法的说明,欢迎点击 Binding Types Reference 查看学习。这就要求你既懂 OC 的语法,又要懂 C# 的语法,不然有些报错无法处理,话说回来,如果已经会 OC 了,为什么还要用这个坑如此多的东西。。

言归正传,修改完上面那些 bug,编译运行通过之后,我们的工作基本就完成了。之后打开 Finder 在项目文件夹的 bin -> debug 目录下可以找到生成的 dll 文件,引入到需要的项目里就可以使用了。至此,OC 的 framework 转为 C# 的 dll 就完成了,祝你一切顺利!