我报名参加金石计划1期应战——瓜分10万奖池,这是我的第1篇文章,点击检查活动详情

前语 项目布景

项目里边有这么一个需求,在一个App项目中创立多个Static Library,各司其职进行模块与责任划分。

别问为啥没有使用私有库Cocopods进行,横竖现在便是为了便利后续各个Static Library,能够随便拖动到其他项目中进行复用。

然后,问题来了。

问题:在Static Library无法引证友盟的framework

为了便于阐明与演示,我特别创立了一个Demo,经过截图进行讲解。

我有个项目叫做TestUM,里边包括一个SomeSDK,我期望在SomeSDK里边,包括高德地图和友盟统计的功能。

Swift:巧用module.modulemap,告别Bridging-Header.h

于是乎,我在Podfile文件中进行了装备:

target 'SomeSDK' do
 # Comment the next line if you don't want to use dynamic frameworks
 use_frameworks!
 pod 'AMapSearch', '= 8.1.0'
 pod 'AMapLocation', '= 2.8.0'
 pod 'UMCommon', '~> 1.3.4.P'
 pod 'UMSPM'
 pod 'UMCCommonLog'
end
target 'TestUM' do
 # Comment the next line if you don't want to use dynamic frameworks
 use_frameworks!
 # Pods for TestUM
end

注意,进行Pod的target是SomeSDK而非TestUM可是实际上TestUM也是能引证高德与友盟的库。

最后,依据友盟集成的文件,需求增加桥接文件进行处理:

Swift:巧用module.modulemap,告别Bridging-Header.h

在TestUM下,我经过import AMapFoundationKit,咱们能够顺畅的调用高德的相关API,由于桥接了友盟,我也能够顺畅的调用友盟的相关API:

Swift:巧用module.modulemap,告别Bridging-Header.h

然而,在SomeSDK下,由于能够import AMapFoundationKit,我依旧能够调用高德,可是友盟却怎么也点不出来了:

Swift:巧用module.modulemap,告别Bridging-Header.h

我测验在SomeSDK也创立一个相似主工程中Bridging-Header.h的文件,对友盟进行桥接,然而得到的却是编译错误using bridging headers with framework targets is unsupported

不支持,这条路被堵死了。

假如桥接行不通,SomeSDK就无法使用友盟统计的功能,只能将其相关业务移植到主工程去,这显着不符合公司要求。

Swift:巧用module.modulemap,告别Bridging-Header.h

领导就一句话:高德能够,友盟为什么不行?

Swift:巧用module.modulemap,告别Bridging-Header.h

现在回头看看,为何高德地图的既能够在TestUM又能够在SomeSDK中进行引证——由于它能在工程中的*.swift文件中进行import

而友盟在经过TestUM-Bridging-Header.h文件进行桥接后,在TestUM主工程的.swift文件中,无需import,直接调用即可,可是在SomeSDK的子工程中无法调用。

高德与友盟的架包到底有何差异?

AMapFoundationKit.framework与UMCommon.framework比照

其实高德与友盟的Pod引证还是非常相似的,由于都是封装的静态库,Pod集成的都是非开源的.framework架包。

这里咱们将AMapFoundationKit.framework与UMCommon.framework做一下比照:

高德 友盟
Swift:巧用module.modulemap,告别Bridging-Header.h
Swift:巧用module.modulemap,告别Bridging-Header.h
Swift:巧用module.modulemap,告别Bridging-Header.h
Swift:巧用module.modulemap,告别Bridging-Header.h
Swift:巧用module.modulemap,告别Bridging-Header.h
Swift:巧用module.modulemap,告别Bridging-Header.h
  1. 经过Xcode展开工程看,Pod中,AMapFoundationKit.framework不仅展现了Frameworks文件夹,一起露出的.h文件也显现了,而UMCommon.framework没有显现.h文件。
  2. 经过AMapFoundationKit.podspec.jsonUMCommon.podspec.json,咱们会发现尽管两者都是.framework的pod集成方法,可是在装备参数的差异方法决定了显现不同。
  3. 看.framework的文件结构,很显着的发现AMapFoundationKit.frameworkUMCommon.framework多一个Module文件夹!

就让咱们看看,这个Module文件夹下面吧。

里边就只有一个module.modulemap文件,里边长这样:

Swift:巧用module.modulemap,告别Bridging-Header.h

关于umbrella header我们能够看看参考文档What is an umbrella header?,它的功能便是将AMapFoundationKit.h里边露出的.h文件,经过循环都露出出来。

AMapFoundationKit.h里边长这样:

Swift:巧用module.modulemap,告别Bridging-Header.h

回想一下,咱们能够在*.swift文件中能够import AMapFoundationKit是不是由于有module.modulemap中的装备原因?

带着这个问题,我去搜索了一下module.modulemap的相关资料。

在一篇文章中我找到相关的信息与灵感:

Swift:巧用module.modulemap,告别Bridging-Header.h

AsBridging-Headercan help us inApp TargetandApp Test Target,not in static library or dynamic librariesto use the Objective C / C APIs into Swift classes,modulemapcan help us here.

经过理解,Pod这种.framework的静态库,在主工程的使用能够经过桥接处理,而在主工程的的static library则需求经过modulemap来进行处理。

为UMCommon.framework手搓一个module.modulemap

本着死马当活马医的想法,我想为UMCommon.framework手搓一个module.modulemap

首先我特别看了一下UMCommon.framework中Headers里边的文件:

Swift:巧用module.modulemap,告别Bridging-Header.h

抱着试一试的态度,我新建了Modules一个文件夹,并写了这样一个文件,注意我并没增加所有的.h文件,仅仅为了便利测验。

framework module UMCommon {
 header "MobClick.h"
 header "UMConfigure.h"
 header "UMCommon.h"
   export *
}

然后将其放到对应的UMCommon.framework。

Swift:巧用module.modulemap,告别Bridging-Header.h

见证结果的时刻来了,编译,试着import,成功了!

Swift:巧用module.modulemap,告别Bridging-Header.h

咱们乃至能够,点击看看这个import UMCommon

Swift:巧用module.modulemap,告别Bridging-Header.h

MobClick类现已完美经过Swift表示了。

而且此时,咱们能够把主工程里边的Bridging-Header.h里边桥接文件注释掉(乃至将这个.h文件删除),在*.swiftimport对应的类,即可成功引入与调用!

总结

  • 将Pod中的某些需求桥接的库,经过手搓一个module.modulemap,咱们彻底有能力抹去桥接操作,可是一起这样有一个问题,一旦Pod的库,晋级或许文件进行了改变,自行写的module.modulemap或许也需求更改。

    而且更改Pod下的库的文件,也不太符合操作规矩。

    另外,我们能够测验把AlipaySDK.framework经过这种方法去除桥接试试,原理都是一样的,就当练手。

  • 还有一种方法便是自己创立一个私有的Spec,自己增加module.modulemap后,进行pod库办理,可是这样还是避免不了上游更新,私有库也要同步更新的问题。

最好的Pod集成方法,就像高德的库,官方将podspec装备好,使用者直接傻瓜pod install就好了。

参考文档

What is an umbrella header?

Swift Objective C interoperability, Static Libraries, Modulemap etc…

自己写的项目,欢迎我们star⭐️

RxStudy:RxSwift/RxCocoa框架,MVVM形式编写wanandroid客户端。

GetXStudy:使用GetX,重构了Flutter wanandroid客户端。