Cocoapods创建私有库问题汇总

Swift、OC混编Framework

正常的Swift项目可以通过创建bridge桥接文件的方式来导入OC库或文件,但是Framework不行,它会提示以下错误:

1
using bridging headers with framework targets is unsupported

如何解决这个问题,主要分以下几种情况:

同一个Framework的混编

解决方式

新建Framework时,会自动创建一个和库同名的.h文件(umbrella header/master header)。我们将需要使用的.h文件import到umbrella header,然后在Build Settings里将Defines Module设置为YES

如果编译时提示Include of non-modular header inside framework module错误。

你可以在Build Setting找到Allow Non-modular Includes In Framework Modules并设置为YES来忽略掉这个问题。

看起来一切OK,但是当你打包库文件给其他项目使用时,问题依旧存在。

正确的做法是将对应的.h文件加入到Build Phases -> Headers -> public里。

错误原因

出现这个错误是因为我们创建的一般都是project header files,而umbrella header是public的。

打包Framework时,Xcode会自动生成一个和库同名的module文件和一个umbrella文件(如果没有的话),默认的module文件在工程中是不可见的,是在编译时生成的。它包含了所有当前库里public header,因此我们可以直接通过import {module name}的方式来完成库的引用,而不需要去将每个.h都import一遍,看起来并不优雅。

因此当你在umbrella header中引入一个非public的文件时,就会出现上述non-modular header的错误。当然,同样的,你在其他public header文件中引入非public文件,也会有同样的问题。

优缺点

这样做的好处是,你的OC文件通过umbrella header暴露给了swift使用,解决了swift和OC混编的问题。但是同样的,也暴露给了外部,而你可能并不想这么做。

官方文档:Importing Objective-C into Swift

不同Framework的混编

虽然swift已经普及,但是对于老项目而言,考虑到成本等各种因素,还是有很大一部分是由OC编写完成的,而我们又不可避免的要使用到它。

很多第三方的静态库Framework并没有使用module,这也是我们不能在Swift中直接引用该静态库的原因,需要在bridge里挨个import我们需要的头文件,但是在Framework里,并不支持bridge。

通过同样的方法,在umbrella header中引用三方库文件时,也会报Include of non-modular header inside framework module错误,因为默认的module里只允许包含当前库下的public header,而你也不能修改对方的Framework。

一种做法是,我们在搞一个OC的Framework,我们暂且叫做BridgeFramework,对引用的三方库进行二次封装,然后通过import BridgeFramework的方式来完成swift的引用,因为我们自己创建的库是可以生成module的。

当然,这样做比较繁琐,维护起来也很麻烦。

在这里,我们可能需要使用自定义module的方式,来解决这个问题。

Module介绍

Module是一种集成库的方式,在Module出现之前,开发者需要在引入库文件的同时引入需要使用的头文件,以保证编译的正常进行。但是每次引入库的时候都要导入一堆文件,看起来并不优雅。Module和Framework的出现让开发者极大程度上告别了这些不优雅的工作。从Xcode5开始,Apple对系统内置的动态库添加了Module的支持。Xcode6开始将Module开放给开发者,开发者可以让自己的库支持Module。

Module本质上是一个描述文件,用来描述Module中包涵的内容,每个Module中必须包涵一个umbrella头文件,这个文件用来import所有这个Module下的文件。

大致关系为:import module -> import umbrella header -> other header

使用Module库的调用方式:

项目类型 OC库(MeeviiAds) Swift库(MeeviiAds)
OC项目 #import <MeeviiAds/MeeviiAds.h> #import <MeeviiAds-Swift.h>
Swift项目 import MeeviiAds import MeeviiAds

MeeviiAds.h其实就是umbrella header/master header

自定义Module创建流程

我们以桥接GDTMobSDK为例。

在项目中新建一个module.modulemap和一个OCBridgeHeader.h,最好将它们放在同一个文件夹下,否则在module.modulemap里配置映射文件路径时,你需要写上完整的OCBridgeHeader.h文件路径。

module.modulemap内容:

1
2
3
4
module ADSDKHeaderBridge {
header "OCBridgeHeader.h" // 这是文件路径!!!
export *
}

OCBridgeHeader.h内容:

1
2
3
4
5
6
7
8
9
10
11
#ifndef OCBridgeHeader_h
#define OCBridgeHeader_h

#import <GDTMobSDK/GDTMobBannerView.h>
#import <GDTMobSDK/GDTRewardVideoAd.h>
#import <GDTMobSDK/GDTNativeExpressAd.h>
#import <GDTMobSDK/GDTNativeExpressAdView.h>
#import <GDTMobSDK/GDTMobInterstitial.h>
#import <GDTMobSDK/GDTSplashAd.h>

#endif /* OCBridgeHeader_h */

配置module路径:

然后在需要使用的地方直接import ADSDKHeaderBridge就可以愉快的使用GDTMobSDK了,同样的,该方法也适用于同Framework下的混编。

如果想要上传pod,你还需要修改podspec文件:

1
2
3
4
5
6
spec.preserve_paths = ["Sources/Module/module.modulemap", "Sources/Module/*.h"]
spec.pod_target_xcconfig = {
"SWIFT_INCLUDE_PATHS" => "$(SRCROOT)/MeeviiAds/Sources/Module"
}
spec.header_mappings_dir = "Sources/Module"
spec.header_dir = "Sources/Module"

注意事项

1、如果已经在preserve_paths添加了modulemapumbrella header,可以不用在source_files里再加一遍,如果要在source_files里加也可以,记得指定public_header_files。如果没有指定,你自己创建的modulemap也会当做public处理。这样lint的时候会报Include of non-modular header inside framework module

2、lint时遇到Include of non-modular header inside framework module错误,可以在后面添加--use-libraries。虽然能验证和上传通过,但是其他项目引用的时候还是会有问题。

3、虽然我们在Build Settings里指定了Import Paths,但是在上传pod时,这些设置是不生效的。所以还是需要你通过pod_target_xcconfig再指定一遍,该路径和Import Paths里稍有不同。

原路径:$(SRCROOT)/Sources/Module
pod_target_xcconfig路径:$(SRCROOT)/MeeviiAds/Sources/Module

MeeviiAds为你的spec.name

4、user_target_xcconfig是针对所有pod的,可能和其他pod存在冲突。pod_target_xcconfig是针对当前pod的。

删除已发布的版本

1
pod trunk delete 框架名称 版本号

私有repo内的pod库之间相互依赖导致lint和push不通过的问题

lint在对引用库验证时,默认只验证官网的仓库,我们需要手动添加验证源才能通过.

解决办法:

指定repo地址:--sources=******.git

示例:

1
2
3
pod spec lint --sources=git@bitbucket.org:sealcn/sealrepo.git,https://github.com/CocoaPods/Specs --allow-warnings --verbose

pod repo push SealRepo MeeviiAds.podspec --sources=git@bitbucket.org:sealcn/sealrepo.git,https://github.com/CocoaPods/Specs --allow-warnings --verbose

Pod subspec默认无法移除

podspec为库的描述文件,包括应该从何处获取资源,使用什么文件,构建什么版本等。

相关字段介绍可以见:Podspec文件说明

default_subspecs:一个subspec的数组,是用来指定默认subspec依赖的,如果没有指定,则会指定全部subspec作为依赖项。

所以指定好你的default_subspecs就可以了。

[!] Authentication token is invalid or unverified. Either verify it with the email that was sent or register a new session.

1
pod trunk register 邮箱地址 名字

会给你发一封邮件,点击链接就可以了。

相关文档