写点什么

cocoapods 的主模块如何判断子模块有没有被加载?

用户头像
fuyoufang
关注
发布于: 4 小时前
cocoapods 的主模块如何判断子模块有没有被加载?

当我们在制作 cocoapods 库时,有时候需要分成主模块子模块,主模块负责提供主要的功能,使用者可以按需引用子模块。


比如 ShareSDK,我们在使用时,首先需要引用主模块 mob_sharesdk,然后根据产品需求添加分享渠道的子模块。


# 主模块(必须)pod 'mob_sharesdk'
# 用户按需添加子模块pod 'mob_sharesdk/ShareSDKPlatforms/QQ'pod 'mob_sharesdk/ShareSDKPlatforms/SinaWeibo'
复制代码


那主模块是如何知道子模块有没有被用户引用呢?

根据 framework 来判断

在 ShareSDK 和 podspec 文件当中,有这样一行注释:


各个平台:每个平台都必须要有 ShareSDK.bundle 和对应的 Connector


下面是 podspec 文件 QQ 和 SinaWeibo 模块的部分设置:


# QQsp.subspec 'QQ' do |ssp|    ssp.vendored_frameworks = 'ShareSDK/Support/PlatformSDK/QQSDK/TencentOpenAPI.framework','ShareSDK/Support/PlatformConnector/QQConnector.framework'end
# SinaWeibo 精简版sp.subspec 'SinaWeibo_Lite' do |ssp| ssp.vendored_frameworks = 'ShareSDK/Support/PlatformConnector/SinaWeiboConnector.framework'end
复制代码


通过观察发现,各个子模块都会依赖一个对应的 **Connector.framework。所以我猜想 ShareSDK 是根据是否能够加载对应的 framework,来判断是否加载了子模块。


如何判断能否加载到指定的 framework 呢?


在 Objective-C 中,可以通过 __has_include 来判断:


#if __has_include(<MyFramework/SomeFeature.h>)SomeFeature *h = [SomeFeature new]#endif
复制代码


在 Swift 中,可以通过 canImport 来判断:


#if canImport(MyFramework)import MyFramework#endif
复制代码

根据子模块的宏来判断

在 podspec 文件中,可以通过 pod_target_xcconfig 修改的编译选项,给模块添加条件编译的定义。


在 Objective-C 文件中,条件编译所用到的宏定义,是通过:GCC_PREPROCESSOR_DEFINITIONSPreprocessor Macros 来定义的。



在 Xcode 8 之后,在 Swift 文件中使用到的宏,是通过 SWIFT_ACTIVE_COMPILATION_CONDITIONSActive Compilation Conditions 去定义的,直接定义添加宏名称即可。



我们可以通过在子模块中添加特定的宏,然后在主模块中判断是否有对应的宏定义,来判断是否加载了子模块。


假如,我们要自己实现一个 iShareSDK 的框架,核心模块是 Core,有 Platforms/QQPlatforms/WeChat 两个子模块,分别给子模块添加一个特殊的宏定义:iShareSDK_Platforms_QQiShareSDK_Platforms_WeChat


podspec 文件的配置如下:


# 核心模块s.subspec 'Core' do |sp|    sp.source_files = 'iShareSDK/Classes/Core/**/*'end
# 可选的子模块s.subspec 'Platforms' do |sp|
# QQ sp.subspec 'QQ' do |ssp| ssp.source_files = 'iShareSDK/Classes/QQ/**/*' ssp.dependency 'iShareSDK/Core' ext.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => 'iShareSDK_Platforms_QQ', 'GCC_PREPROCESSOR_DEFINITIONS' => 'iShareSDK_Platforms_QQ=1' } end
# WeChat sp.subspec 'WeChat' do |ssp| ssp.source_files = 'iShareSDK/Classes/WeChat/**/*' ssp.dependency 'iShareSDK/Core' ext.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => 'iShareSDK_Platforms_WeChat', 'GCC_PREPROCESSOR_DEFINITIONS' => 'iShareSDK_Platforms_WeChat=1' } endend
复制代码


在主模块中,我们就可以根据是否有子模块中的宏定义,来判断是否加载了子模块了。


public class iShareSDK {        /// 处理所有平台的分享事件    /// - Parameter platform: 分享渠道    public func share(platform: Platform) {        switch platform {        case .QQ:            #if iShareSDK_Platforms_QQ            QQ.handleShare()            #else            debugPrint("未加载 QQ 模块")            #endif        case .WeChat:            #if iShareSDK_Platforms_WeChat            WeChat.handleShare()            #else            debugPrint("未加载 WeChat 模块")            #endif        }    }}
复制代码

总结

在制作 cocoapods 库时,有时需要分成多个子模块,而且子模块是用户按需进行加载的,我们可以通过两种方式来判断用户是否加载了特定的子模块:


  1. 通过否能够加载到指定模块的 framework 来确定;

  2. 在各个模块中添加一个唯一的编译条件宏定义,在其他模块中判断是否包含对应的宏定义来判断。

参考

  1. Cocoapods 修改Pod 编译选项

  2. iOS(Swift) 条件编译, Active Compilation Conditions和Preprocessor Macros的区别

用户头像

fuyoufang

关注

iOS 开发者 2017.10.17 加入

iOS 开发者,微信号:devfang

评论

发布
暂无评论
cocoapods 的主模块如何判断子模块有没有被加载?