美文网首页
ios静态库链接的问题

ios静态库链接的问题

作者: 辣条少年J | 来源:发表于2020-12-06 16:06 被阅读0次

    uni-app开发原生插件

      公司用uni-app开发的h5程序,然后使用云打包的方式生成包。需要使用支付宝的原生插件,虽然uni-app集成了支付宝支付功能,但是由于我们面对的是外币支付,所以需要通过一个第三方(方圆支付),将订单转化为一个外币订单然后再来支付,方圆支付提供了sdk,sdk里方圆集成了两个逻辑,一:生成外币订单逻辑,二:调用支付宝的逻辑。所以我们只能使用开发原生插件的方式通过调用方圆支付来实现支付宝外币支付。uni-app提供了离线sdk:

    image.png
      下载下来是一个配置好的xcode工程,工程结构如下:
    image.png
      该工程里的主工程Hbuilder-uniPlugin里依赖了一个名为DCTestUniPlugin的静态库工程,简而言之,我要在这个静态库里实现方圆支付的功能供主工程调用。如何编写原生插件及如何调用的配置在uni-app的官网都能找到,这里不再赘述,给出链接:
    https://nativesupport.dcloud.net.cn/NativePlugin/course/ios

    插件的调用

      配置文件里配置好js方法和ios原生工程的类和方法之间的映射,demo里的调用函数是:


    image.png

    这里坑就来了!
      我在这个方法里集成了方圆支付(实际是重新实现了一个插件类并编写了方法,笔者还是很讲究代码优雅,这里暂且使用它来说明_),将库导入静态库工程,添加头文件

    #import <OTTPaySDK/OTTPaySDK.h>
    

    方法里调用支付接口,但是报错了,xcode代码行直接提示#import <OTTPaySDK/OTTPaySDK.h>找不到。不是知道是哪里出了问题,按理说静态链接库的导入就那几步,就以下三个位置


    image.png
    • 1、Framework search paths里添加framework的路径,注意最好是绝对路径哦,方便代码移植。
    • 2、Header Search Paths写入framework的头文件路径
    • 3、Library Search Paths写入framework的路径。

      我都反复对照并检查过了,都是添加了的。正当我烦躁不安困顿之际,突然发现工程是放在一个中文目录下,静态链接库的引用路径有中文路径,会不会是这个原因呢,抱着试一试的心态我将工程关闭并且把中文路径改成了英文。奇迹发生了,#import <OTTPaySDK/OTTPaySDK.h>能够被找到了!

    主工程引用静态库子工程里的第三方库

      然后我在静态库工程里添加了一个Trans.h文件,把#import <OTTPaySDK/OTTPaySDK.h>写在里面,暴露接口给主工程引用,由于要被外部引用,Trans.h这个头文件在build phases里的头文件引用要用public方式才能被外部引用到。注意:如果是该头文件里引用了其他自定义的类,也要将那个自定义类的头文件加入public里,如下:

    image.png

      但是奇怪的是,运行主工程的时候始终报Trans.h里的#import <OTTPaySDK/OTTPaySDK.h>无法找到,第三库无法链接,这是啥情况呢。
      网上查了很多资料,这种引用方式应该是没有错的,静态库工程能编译成功主工程编译失败应该是主工程里哪里配置的问题。

    解决与结论

      后面分析到OTTPaySDK里集成了支付宝支付,uni-app里也集成了支付宝,两个SDK里有相同的库引用,会不会是这个原因导致OTTPaySDK不被引用到呢,我删掉了主工程里的Alipay.framework,这下编译正常了!!
      估计应该是住工程在链接静态库子工程时,由于静态库工程里的第三方库和本来自身引用的第三方库有冲突所以虽然链接了静态库子工程,但是却没有链接成功静态库子工程引用的这个第三方库,因为这个第三方库有冲突所以导致整个都没有被链接到,应该是这个原因。这个时候需要删除一个第三方库方可。

    uni-app 离线包版本不同导致问题

      这里还有个坑是,我这边用的是uni-app离线包2.9.3,同事用的2.9.8的版本,我这边编译运行都是正常的,同事那边(h5工程师,工程云打包)始终云打包后点击就直接闪退,后面重新下了2.9.8的离线包,运行确实直接就崩溃,说是方法执行在子线程里操作UI。将操作放在了主线程里就好了,看来不同版本间插件的插件调用逻辑有不同,2.9.3的插件调用是主线程里调用,2.9.8插件估计是在子线程操作。

    静态库分析

      趁此机会把静态库相关的查看命令整理下,

    一、查看.a静态库里的.o文件及函数接口信息

    查看.a静态库或者framework里的二进制文件都可以用下面这个命令

    nm -m x.a
    

    输出信息有类信息及很详尽的接口信息,如:


    image.png
    image.png

    二、静态库冲突,需拆分框架或者某些.o文件

    这里会用到lipo和ar两个命令
    1、查看库支持的框架类型:

    lipo -info .a //查看静态库的信息
    

    现在支持的框架类型有:i386、x86_64、armv7、arm64、arm64e。
    查看结果如下:


    image.png

    表明该静态库支持这4个架构。
    2、拆分静态库为指定架构
      将集成了几个架构的静态库查分,如:将刚才的静态库拆分成4个仅支持相应架构的库

    lipo lib.a -thin armv7 -output lib_armv7.a
    lipo lib.a -thin i386 -output lib_i386.a
    lipo lib.a -thin x86_64 -output lib_x86_64.a
    lipo lib.a -thin arm64 -output lib_arm64.a
    

    3、删除静态库里有冲突的类文件
      类文件在静态库二进制里是.o类型,编译的时候不同静态库里可能包含相同的类,此时我们需要将冲突的.o移除。注意:我们需要先将静态库拆分成单个架构的库然后才能使用ar来删除冲突的.o文件,几个框架的合并库是不能这样操作的。
    这里拿微博静态库做下测试:
    首先查看架构:

    lipo -info libWeiboSDK.a
    

    包含4个架构:


    image.png

    然后将其架构拆分:

    #!/bin/bash
    lipo libWeiboSDK.a -thin armv7 -output libWeiboSDK_armv7.a
    lipo libWeiboSDK.a -thin i386 -output libWeiboSDK_i386.a
    lipo libWeiboSDK.a -thin x86_64 -output libWeiboSDK_x86_64.a
    lipo libWeiboSDK.a -thin arm64 -output libWeiboSDK_arm64.a
    

    生成成功:


    image.png

    查看arm64的接口和类信息:

    nm -m libWeiboSDK_arm64.a 
    
    image.png

    移除命令ar -d,移除WBSDKUtil.o:

    ar -d libWeiboSDK_arm64.a WBSDKUtil.o
    

    执行过后如下图


    image.png
    image.png

    可以看到WBSDKUtil.o已经被成功移除。
    4、将这些处理完成后将这些静态库合并:

    lipo -create -output libWeiboSDK.a libWeiboSDK_i386.a libWeiboSDK_arm64.a libWeiboSDK_armv7.a libWeiboSDK_x86_64.a 
    
    

    三、查看framework是静态库还是动态库

      framework可能是静态库也可能是动态库,有时候需要分辨,通过命令:

    file xx
    

    这里查看framework里的二进制文件:


    image.png

      可以看到不同架构的库类型,有“current ar archive random library”字样的表示是静态库,如果是有“dynamically linked shared library”字样的表示是动态库。

    相关文章

      网友评论

          本文标题:ios静态库链接的问题

          本文链接:https://www.haomeiwen.com/subject/btinwktx.html