因为公司需要持续性向别人提供一套蓝牙锁SDK,按照传统的方式打包静态库真是太痛苦,SDK依赖的一些私有库会有频繁的更新,依赖的第三方库也是错综复杂。我迫切需要找到一种更方便的打包静态库的方式,既能随时更新私有库,也能解决开源库的冲突问题(比如你的SDK包含了AFNetworking,别人项目中本身也含有AFNetworking,就会产生冲),那就是使用cocoapods。
什么是库 ?
库就是程序代码的集合,将N个文件组织起来,是共享程序代码的一种方式。库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。咱们自定义的私有组件和公有组件也是一种库。
库的分类
开源库:源代码是公开的,可以看到每个实现文件(.m文件)的实现,例如GitHub上的常用的开源库:AFNetworking、SDWebImage等;
闭源库:不公开源代码,是经过编译后的二进制文件,看不到具体的实现。闭源库又分为:静态库 和 动态库
静态库与动态库的区别
静态库:链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝。
动态库:链接时不复制,程序运行时由系统动态加载到内存,系统只加载一次,多个程序共用(如系统的UIKit.framework等),节省内存。
静态库和动态库是相对编译期和运行期的:静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在。
可以看到你想SDK用自己版本的第三方库,而使用你的SDK库的人使用相同的不同版本的第三方库。那么使用静态库可能实现他们的冲突,具体的由cocoapods-packager插件通过对引用的三方库进行重命名很好的解决了类库命名冲突的问题。
由于以前都是使用Souce Tree创建git工程,这样速度很快并且也很简单。但是制作通用静态库工程需要使用命令创建。看来萧何败也萧何。
- 创建你的 project
打开终端,cd 到你的文件路径cd /Users/jiaguoshang/Desktop/TestSDK;
,输入pod lib create TestSDK
创建并初始化一个工程。
Last login: Mon May 6 08:26:35 on console cd /Users/jiaguoshang/Desktop/TestSDK; clear; pwd w1:~ jiaguoshang$ cd /Users/jiaguoshang/Desktop/TestSDK; clear; pwd /Users/jiaguoshang/Desktop/TestSDK w1:TestSDK jiaguoshang$ pod lib create TestSDK Cloning `https://github.com/CocoaPods/pod-template.git` into `TestSDK`. Configuring TestSDK template. ------------------------------ To get you started we need to ask a few questions, this should only take a minute. 2019-05-06 16:55:32.146 defaults[5778:415315] The domain/default pair of (org.cocoapods.pod-template, HasRunbefore) does not exist If this is your first time we recommend running through with the guide: - https://guides.cocoapods.org/making/using-pod-lib-create.html ( hold cmd and click links to open in a browser. ) Press return to continue.
然后回答几个问题,就自动创建出一个project:
我们新建的工程以及目录如下:
其中重要文件夹我都已经展开,可以看到里面包含的内容,其他没有展开的文件夹不用管它。
Example for TestSDK文件夹是存放测试文件的地方,Development Pods下的TestSDK是存放SDK自定义库的代码地方。这两个是最核心的文件夹。Podfile是配置SDK依赖的第三方库的配置文件。
2. 最重要的一个文件就是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。不然打包时你找不到最新版本号对应的版本。
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导入的库,这里一定要添加依赖,不然你使用库时会报找不到库的错误。
3. 很重要的Podfile文件。这个是你的工程和sdk依赖的第三方库配置文件。
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简单多了:
# Uncomment this line to define a global platform for your project source 'https://github.com/CocoaPods/Specs.git' source 'http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git' platform :ios, "8.0" target 'BITCache' do # Uncomment this line if you're using Swift or would like to use dynamic frameworks # use_frameworks! # Pods for BITCache pod 'BITNSObject' end
source 'https://github.com/CocoaPods/Specs.git’代表依赖共有源
source 'http://192.168.1.12:2388/bitinfo_tech_ios/BTSpec.git’代表依赖私有源。若你的组件或项目依赖私有源一定要把依赖私有源加上,不然你无法下载你的私有组件。
4. 再来看看我改进的代码结构吧!我很不喜欢storyboard,文件大笨,打开要很久,难以多个人开发一个页面后合并代码。才用storyboard或xib做的页面的app要比纯用代码写的页面的app要大一倍。所以我去掉了主页面的storyboard,改用代码实现页面。
注意:
1)Development Pods下的TestSDK才是我们SDK代码存放的地方,这个才是我们的菜。
2)Example for TestSDK文件夹下是我们的测试工程的测试页面和代码存放的家。
5. 下面是对应的电脑上的物理路径:
TestSDK下的Classes文件夹对应的是工程中Development Pods下的TestSDK夹,是我们SDK代码存放的地方,这个才是我们的菜。
Example下的TestSDK文件夹对应工程中Example for TestSDK文件夹,是我们的测试工程的测试页面和代码存放的地方。
6.打开终端,切换到Example下的TestSDK文件夹,运行pod update。更新完毕,运行TestSDK.xcworkspace,工程正常启动。创建制作SDK的静态库工程完成。接下来我们介绍如何使用这个通用静态库工程做SDK,如何发布!
由于测试代码和SDK的代码在一个工程中,一边开发可以一边测试。当然不把这个测试工程直接开源出去,那么不泄漏你的SDK源代码了吗?由于该工程直接集成了测试用例,那么在打包SDK后,重新创建代码,把测试部分代码拷贝过去,直接使用SDK进行测试就可以。这样也方便,开发速度快。
开发模式研究:
app四种开发模式的优缺点。移动五端合一说了如何让移动五端合一。
如何访问组件的bundle资源。
创建使用SDK静态库具体方案:
创建制作SDK的静态库工程说了如何创建工程,制作SDK静态库已经说了SDK如何写,打包SDK静态库说了如何打包iOS使用SDK静态库。
.framework类型的静态库和.a类型的静态库的优缺点及.framework类型的静态库zip压缩后解压后头文件丢失问题。
Mac电脑如何使用WinRAR。
下面是Demo:
iOS使用SDK静态库Demo.
SDK的Demo。