1.修改配置.podspec文件。
2.删除淘宝镜像,增加gem sources -a https://gems.ruby-china.com/,升级cocoapods到1.5.0以上版本,安装cocoapods-packager。打包.framework类型的静态库或.a类型的静态库。
3.framework类型的静态库和.a类型的静态库的优缺点。
因为公司需要向友商提供一套蓝牙锁SDK,按照传统的方式打包静态库真是太痛苦,SDK依赖的一些私有库会有频繁的更新,依赖的第三方库也是错综复杂。我迫切需要找到一种更方便的打包静态库的方式,既能随时更新私有库,也能解决开源库的冲突问题(比如你的SDK包含了AFNetworking,别人项目中本身也含有AFNetworking,就会产生冲),那就是使用cocoapods。这个相对iOS使用动态库简单了很多,不用直接直接拷贝第三到工程,真正做到SDK和使用SDK的工程各用各的工程。
由cocoapods-packager插件通过对引用的三方库进行重命名很好的解决了类库命名冲突的问题。SDK的Demo。
既然创建制作SDK的静态库工程说了如何创建工程,制作SDK静态库已经说了SDK如何写。那么就是如何打包的问题。
1.修改配置.podspec文件。
TestSDK.podspec,*.podspec是关于pod库的描述文件,它详细说明了在这个pod library中源码应该从哪里取出、应用怎样的构建设置以及其他基本的信息,比如名称、版本、描述等。下面是关于.podspec文件的说明:
相信会完组件的对这个文件很了解,没有玩过组件了就要认真恶补以下了。
Pod::Spec.new do |s| s.name = 'TestSDK' s.version = '0.1.0' s.summary = 'A short description of TestSDK.' s.description = <<-DESC TODO: Add long description of the pod here. DESC s.homepage = 'https://github.com/jiaguoshang/TestSDK' # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'jiaguoshang' => 'jia12216@163.com' } s.source = { :git => 'https://github.com/jiaguoshang/TestSDK.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>' s.ios.deployment_target = '8.0' s.source_files = 'TestSDK/Classes/**/*' # s.resource_bundles = { # 'TestSDK' => ['TestSDK/Assets/*.png'] # } # s.public_header_files = 'Pod/Classes/**/*.h' # s.frameworks = 'UIKit', 'MapKit' s.dependency 'AFNetworking', '~> 3.1.0' s.dependency 'ReactiveObjC' s.dependency 'YYModel' s.dependency 'YYCategories' s.dependency 'FMDB' s.dependency 'MJExtension' s.dependency 'SDAutoLayout' s.dependency 'SAMKeychain' end
其中s.summary 是简述,填写下吧,s.homepage主页你随便写个地址,没有它pod spec lint和pod repo push时会给出告警。
s.name你的项目的名称,注意要和工程名同名,不然pod spec lint和pod repo push不通过。
s.version版本号这个是最核心的最常变的东东。每次发布版本需要对上传的最新版本打tag,修个这个版本号。注意:
1)这个版本只能比上一个版本号增加不能降低。若版本号相同也很容易出问题,所以一定要增加版本号。
2)添加标签时一定要勾选推送标签,并且选择origin。不然打包时你找不到最新版本号对应的版本。这个代表把标签打到master分支上。
图一:
s.license是执照,用默认创建的就可以了。
s.author是作者信息,使用默认创建的就可以。
s.source 代码仓库的源地址,这个不能乱写。不然无法pod repo push。
s.ios.deployment_target支持的最低操作系统版本号。
s.source_files包的源代码文件机制,'TestSDK/Classes/**/*'此种方式直接把Classes文件夹下文件及级联文件下的文件全部打包到SDK的TestSDK文件夹下。
注意:
1)这个源文件和它依赖的组件要能独立运行,一个组件就是一批可以独立运行的代码源文件,它最多只能使用它依赖的组件,不能使用直接其它的文件。
2)它能使用它依赖的组件的类和文件。
3)虽然组件不能访问非它依赖的组件的类和方法。但是可以通过注册block和组件依赖达到间接访问其它非依赖的组件的类和方法的效果。达到A,B组件互相依赖的解藕。
4)虽然在组件化下我们不提倡单例这种破坏模块化的方法。但是在特别情况下,我们有绕不过的硬伤,需要组件包含单例。如:由于组件只能使用组件的类,不能直接使用主工程的类和方法。那么如何实现组件和SDK同时关闭开启日志呢?有人说可以通过工程配置Prefix.pch的编译宏来重定义日志,达到关闭和开启日志。若只是你一个人开发的sdk你可以怎么玩。但是sdk是提供别的商家使用的,你不能要求商家做这做那,那是不科学的,并且你也不想用户看到你的日志。所以解决方案是,做一个单例组件来实现受编译宏控制的日志的重定义,日志级别。异步日志库CocoaLumberjack的ddLogLevel的声明和定义。
5)让组件的文件分多个文件夹存放见文章《创建并发布自己的公有库和如何把私有库的文件分多层目录存储》。
s.resource_bundles是sdk组件用到图片,文件等资源。
s.public_header_files是sdk组件对外开发的头文件,就是可以扩展包含头文件的方式。
s.frameworks 是sdk组件依赖的iOS系统基础库。
s.dependency是依赖的其它第三方库和你自己的私有组件。注意:你在Podfile导入的库,这里一定要添加依赖,不然你使用库时会报找不到库的错误。
配置完之后,上传代码,打Tag,见图一。打开终端,切换到TestSDK.podspec文件所在的目录,使用万能命令 pod spec lint TestSDK.podspec --sources='http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git,https://github.com/CocoaPods/Specs.git' --allow-warnings --use-libraries验证是否有效,必须没有错误,没有警告才可以通过验证。注意:就是验证通过,也不一定能保证你上次成功。你只能见招拆招了。我见到向服务器推送私有组件是网络错误出现了异常,让后检查配置文件没有问题,无论怎么推送都报错。我没有办法提高了版本号再推送就成功了,估计git的缓存问题。http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git代表私有Repo地址,一般都是公司的局域网,用gitLab搭建的服务器,https://github.com/CocoaPods/Specs.git'代表cocoapods官方的Repo。注意:你再GitLab服务器上创建Repo仓库时一定要勾选初始化 README.md 。若不小心忘记勾选了,可以用命令初始化 README.md。若不会命令,那么你需要用SourceTree把这个Repo仓库拉到本地上传一个文件。不然你将遇到文件验证有效,但是使用万能的推送命令pod repo push BTSpec TestSDK.podspec --sources='http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git,https://github.com/CocoaPods/Specs.git' --allow-warnings --use-libraries推送失败的问题。这个问题曾经困惑我一周。没有人指导,一个人摸索很苦啊!–use-libraries表示依赖了静态库,–allow-warnings忽略警告。它检查的是,master分支上的版本的代码。
创建本地私有仓库的命令是:pod repo add BTSpec http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git。在命令窗口下执行这个命令就可以。
若你使用了公用库和私有库,那么你的Podfile要增加私有源和公有源,不然报找不到私有库的错误。
use_frameworks! platform :ios, '8.0' source 'https://github.com/CocoaPods/Specs.git' //source 'http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git' target 'TestSDK_Example' do pod 'TestSDK', :path => '../' target 'TestSDK_Tests' do inherit! :search_paths #RAC响应式编程库 pod 'ReactiveObjC' ##################################第三方########################### #YYModel--数组转模型组件 pod 'YYModel' #YYCategories--给系统类添加的分类 pod 'YYCategories' pod 'FMDB' pod 'MJExtension' pod 'AFNetworking', '3.1.0' pod 'SDAutoLayout' pod 'SAMKeychain' end end
TestSDK_Example这个是和Podfile文件所并行存在的文件夹,注意:这个可不是外层的TestSDK问价夹名。
pod ‘TestSDK’, :path => '…/'这个代表是pod以TestSDK向下展开一层存放加载第三方库。
target ‘TestSDK_Tests’ do代表target为TestSDK_Tests的依赖库。
pod 'ReactiveObjC’代表加载ObjC版本的RAC响应式编程库。
下面是一个简化版本私有组件的Podfile文件,比这个SDK的Podfile简单多了:
然后执行pod install,再去检查就没有问题了
文件检查成功如下图:
图二
2.删除淘宝镜像,增加gem sources -a https://gems.ruby-china.com/,升级cocoapods到1.5.0以上版本,安装cocoapods-packager。打包.framework类型的静态库或.a类型的静态库。
前面的准备工作完成,最后一步就是打包静态库了。这里需要安装一个 CocoaPods 打包插件 cocoapods-packager。终端执行安装命令:sudo gem install cocoapods-packager,等待安装完成。
该插件通过对引用的三方库进行重命名很好的解决了类库命名冲突的问题。
下载cocoapods-packager我出现了一个问题。就是我用淘宝源不能下载最新的cocoapods,执行命令是报cocoapods版本太低无法下载cocoapods-packager。
使用终端查看当前的源
gem sources -l gem sources -r https://rubygems.org/ #删除源 gem sources -a https://gems.ruby-china.com/ #添加源
我这里有一个比较好的一个源
https://gems.ruby-china.com/
之后使用sudo gem install cocoapods 然后输入管理员密码 就可以了。
然后后查询cocoapods的版本号:
w1:Example jiaguoshang$ git --version git version 2.20.1 (Apple Git-117) w1:Example jiaguoshang$ pod --version 1.7.0.beta.2 w1:Example jiaguoshang$ gem sources -l *** CURRENT SOURCES *** https://ruby.taobao.org https://gems.ruby-china.com w1:Example jiaguoshang$
然后执行命令sudo gem install cocoapods-packager
,等待安装完成。
终端cd到TestSDK.podspec文件所在的目录下,执行以下命令即开始打包静态库:
pod package TestSDK.podspec --force --no-mangle --spec-sources=http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git,https://github.com/CocoaPods/Specs.git
打包成功的信息如下:
可以看到打包成的TestSDK-0.1.2文件夹,下面是展开的文件夹:
可以看到你直接可以得到TestSDK.framework,TestSDK.framework下Headers文件夹是一个超链接和TestSDK.framework下的Versions文件下的A文件夹下的Headers文件夹,TestSDK.framework下的Versions文件下的Current文件夹下的Headers文件夹下的文件是一份文件。TestSDK.framework下的TestSDK是一个超链接文件和TestSDK.framework下的Versions文件下的A文件夹下的TestSDK文件,TestSDK.framework下的Versions文件下的Current文件夹下的TestSDK文件是同一个文件。删除一个问价下的文件,其它逻辑目录下的文件都被删除。这个问题会在windows电脑打zip包时出现问题。后续会在另一篇文章介绍。
大家看到了没有,打包的TestSDK.framework文件把所有头文件都给包含进来了,这是不安全,使用SDK的可能通过引入你头文件调试出你的函数逻辑。所以我只能给用户提供指定的头文件,其它头文件要删除。所以我们只保留TestSDKSingleObject.h和TSBaseEntity.h头文件,其它文件都要删除。
若打包.a文件正好相反,只有一个 .a文件,没有头文件,需要拷贝TestSDKSingleObject.h和TSBaseEntity.h头文件给用户。下面是打包成.a格式包。
pod package TestSDK.podspec --library --force --no-mangle --spec-sources=http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git,https://github.com/CocoaPods/Specs.git
3.framework类型的静态库和.a类型的静态库的优缺点
1).a包需要你提供.a包和头文件,使用这需要同时导入.a包和头文件,就是使用者稍微麻烦些,不存在经过windows电脑采用zip压缩后发给别人解压不能使用问题。
2).framework包需要你手动删除不想让看到的头文件,使用者只需要导入.framework包就能看到头文件,正常使用。当然你忘记删除敏感的头文件就是严重的信息泄漏了。简言之就是发布包的做的事情多些,使用包的人只需要它拖入一个包就可以了。.framework因为存超链接,所以在windows用zip压缩再在其它电脑解压,这种超链接被破坏不能使用。当然你可以压缩无损的.rar包规避这个问题。
.a与.framework的区别:
一、库:
库是共享程序代码的方式,一般分为静态库和动态库
二、静态库与动态库的区别:
静态库:连接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
动态库:连接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。
三、iOS静态库形式和动态库形式:
静态库:.a和.framework
动态库:.dylib和.framework
四、framework静态库和动态库的区分:
系统的.framework是动态库,我们自己建立的.framework是静态库
五、.a和.framwork的区别:
.a是一个纯二进制文件,.framework中除了有二进制文件外还有资源文件。
.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。
.a + .h + sourceFile = .framework
你的SDK想生成那种类型的包,自己衡量利弊字节决定。福兮祸所伏,祸兮福所倚!
开发模式研究:
app四种开发模式的优缺点。移动五端合一说了如何让移动五端合一。
如何访问组件的bundle资源。
创建使用SDK静态库具体方案:
创建制作SDK的静态库工程说了如何创建工程,制作SDK静态库已经说了SDK如何写,打包SDK静态库说了如何打包iOS使用SDK静态库。
.framework类型的静态库和.a类型的静态库的优缺点及.framework类型的静态库zip压缩后解压后头文件丢失问题。
Mac电脑如何使用WinRAR。
下面是Demo:
iOS使用SDK静态库Demo.
SDK的Demo。