iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)

前言:

iOS工程架构少不了cocoapods 对第三方库的管理,它有着很好的操作性和集中管理的特性。之前的写了不少Xcode 建静态库工程打包.a 和 .framework 的文章,但是我们要先建静态库工程、编译通用包、导入测试工程demo中、静态库工程有更新就需要从新来一遍。工作重复、低效、繁琐。今天讲一下cocoapods打包静态库的工程。这种方式可以很好的解决以上问题。

需求:持续向别人提供一套即时通讯SDK。

  1. SDK依赖的一些私有库会有频繁的更新,依赖的第三方库也是错综复杂。
  2. 使用开源库AFNetworking,别人项目已经有AFNetworking,就会产生开源库冲突。
  3. 假设你已经有一堆写好的源码,并且它们依赖一堆私有库和第三方库,也许,这些依赖并非都是源码,可能也包含了静态库(.a或者.framework)。

所以:我迫切需要找到一种更方便的打包静态库的方式,既能随时更新私有库,也能解决开源库的冲突问题,那就是使用Cocoapods。Cocoapods作为OS X和iOS开发平台的类库管理工具,已经非常完善和强大。通常我们用pod来管理第三方开源类库,也有可能会开发一个用pod管理依赖关系的静态类库给其他人使用。本文将以一个依赖于MBProgressHUD、Toast## 标题的静态类库,来演示如何使用CocoaPods创建静态类库以及打包的过程。

Cocoapods创建工程

终端cd 到你某个文件路径,输入pod lib create VideoPlayerLib 创建并初始化一个工程。(即配置podspec)
回答几个问题后就自动创建了一个工程。
iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)此时会自动打开一个名为 VideoPlayerLib 的工程以及目录如下:
iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)
首先认识一下*.podspec文件,*.podspec是关于pod库的描述文件,它详细说明了在这个pod library中源码应该从哪里取出、应用怎样的构建设置以及其他基本的信息,比如名称、版本、描述等

Pod::Spec.new do |s|
s.name          = 'YJDemoSDK' #项目名
s.version       = '0.1.0' #相应的版本号
s.summary       = 'A short description of YJDemoSDK.' #简述
s.description   = <<‐ DESC #详细描述
TODO: Add long description of the pod here.
DESC
s.homepage      = 'https://github.com/yangjie2/YJDemoSDK' #项目主页
s.license       = { :type => 'MIT', :file => 'LICENSE' } #开源协议
s.author        = { 'yangjie2' => '[email protected]' } #作者
s.requires_arc  = true #arc和mrc选项
s.libraries     = 'z', 'sqlite3' #表示依赖的系统类库,比如libz.dylib等
s.frameworks    = 'UIKit','AVFoundation' #表示依赖系统的框架
s.ios.vendored_frameworks = 'YJKit/YJKit.framework' # 依赖的第三方/自己的framework
s.vendored_libraries = 'Library/Classes/libWeChatSDK.a' #表示依赖第三方/自己的静态库(比如libWeChatSDK.a)
#依赖的第三方的或者自己的静态库文件必须以lib为前缀进行命名,否则会出现找不到的情况,这一点非常重要

#平台信息
s.platform      = :ios, '7.0'  #支持的平台
s.ios.deployment_target = '7.0'

#文件配置项
s.source        = { :git => 'https://github.com/yangjie2/YJDemoSDK.git', :tag => s.version.to_s }
 #配置项目的目标路径,如果不是本地开发,pod init/update会从这个路去拉去代码

s.source_files = 'YJDemoSDK/Classes/**/*.{h,m}' #你的源码位置
s.resources     = ['YJDemoSDK/Assets/*.png'] #资源,比如图片,音频文件等
s.public_header_files = 'YJDemoSDK/Classes/YJDemoSDK.h'   #需要对外开放的头文件

#依赖的项目内容 可以多个
s.dependency 'YYModel'
s.dependency 'AFNetworking' '2.3'

明白了.podspec文件是什么之后,继续往下看我们的工程目录,有个文件夹 Development Pods ,这里就是放置我们的源码和图片等资源文件的地方,要与YJDemoSDK.podspec文件中描述的一致。当你向VideoPlayerLib/Classes、VideoPlayerLib/Assets添加新的/已经存在的文件,或者更新你的.podspec时,需要运行pod install或者pod update。

  1. 打开VideoPlayerLib.podspec文件,修改自己的静态库配置,如下
#
# Be sure to run `pod lib lint VideoPlayerLib.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html
#

Pod::Spec.new do |s|
  s.name             = 'VideoPlayerLib'
  s.version          = '0.1.0'
  s.summary          = 'A short description of VideoPlayerLib.'

# This description is used to generate tags and improve search results.
#   * Think: What does it do? Why did you write it? What is the focus?
#   * Try to keep it short, snappy and to the point.
#   * Write the description between the DESC delimiters below.
#   * Finally, don't worry about the indent, CocoaPods strips it!

  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC

  s.homepage         = 'https://github.com/lzz/VideoPlayerLib'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'lzz' => '18116064' }
  
  # 修改s.source。根据你的实际路径修改。
  s.source           = { :git => '/Users/suning/Desktop/架构/cocoapods打包静态库/VideoPlayerLib/VideoPlayerLib', :tag => s.version.to_s }

  # s.source           = { :git => 'https://github.com/lzz/VideoPlayerLib.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'



# 下面配置依赖的资源、库、配置等

  # 工程依赖系统版本
  s.ios.deployment_target = '8.0'
  # 是否是静态库 这个地方很重要 假如不写这句打出来的包 就是动态库 不能使用 一运行会报错 image not found
  s.static_framework  =  true
  # arc和mrc选项
  s.requires_arc = true
  # 链接设置 重要
  # s.xcconfig = {'OTHER_LDFLAGS' => '-ObjC'}


  # 你的源码位置,源文件 包含 h,m
  s.source_files = 'VideoPlayerLib/Classes/**/*.{h,m}'
  # s.source_files = 'VideoPlayerLib/Classes/head/VideoPlayerLib.h'

  # 需要对外开放的头文件   打包只公开特定的头文件
  s.public_header_files = 'VideoPlayerLib/Classes/**/VideoPlayerLib.h'
  # 调试公开所有的头文件 这个地方下面的头文件 如果是在Example中调试 就公开全部,需要打包就只公开特定的h文件
  # s.public_header_files = 'VideoPlayerLib/Classes/**/*.h'


  # 资源,比如图片,音频文件等
  s.resource_bundles = {
     # 这是个数组,可以添加其他bundle
     'VideoPlayerLib' => ['VideoPlayerLib/Assets/*.png']
  }

  # 表示依赖系统的框架(多个)
  # s.frameworks = 'UIKit', 'MapKit'

  # 表示依赖的系统类库(多个) 注意:系统类库不需要写全名 去掉开头的lib
  # s.libraries = 'stdc++','sqlite3'


  # 依赖的第三方/自己的framework
  # s.ios.vendored_frameworks = 'VideoPlayerLib/MySDK.framework'


  # 表示依赖第三方/自己的静态库(比如libWeChatSDK.a)
  # 依赖的第三方的或者自己的静态库文件必须以lib为前缀进行命名,否则会出现找不到的情况,这一点非常重要
  # s.vendored_libraries = 'VideoPlayerLib/Classes/libWeChatSDK.a'
  # s.vendored_libraries = 'VideoPlayerLib/Classes/openssl/include/*.{a}'

  # 载入第三方.a头文件
  # s.xcconfig = {
  #      'USER_HEADER_SEARCH_PATHS' => 'VideoPlayerLib/Classes/openssl/include/openssl/*.{h}'
  #}


  # l依赖第三方开源框架(多个)
  # s.dependency 'AFNetworking', '~> 2.3'
  s.dependency 'MBProgressHUD'
  s.dependency 'Toast','3.0'

end

3.进入Example文件夹,执行pod install,让demo项目安装依赖项并更新配置。如果有错误,会有提示根据提示修改执行pod install,直到成功。
iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)
运行pod install,让demo程序加载新建的类。也许你已经发现了,只要新增加类/资源文件或依赖的三方库都需要重新运行pod install来应用更新。

demo项目中调用测试。
iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)
成功打印,调用成功!

编译静态库

  1. 验证类库
    开发完成静态类库之后,需要运行pod lib lint验证一下类库是否符合pod的要求。可以通过添加–only-errors忽略一些警告。

cd 到含有VideoPlayerLib.podspec 文件下,然后执行

lzz-Mac-mini:~ suning$ 
lzz-Mac-mini:~ suning$ cd /Users/suning/Desktop/架构/cocoapods打包静态库/VideoPlayerLib/VideoPlayerLib 
lzz-Mac-mini:VideoPlayerLib suning$ pod lib lint VideoPlayerLib.podspec

可能会报错,根据错误提示修改即可!

pod lib lint VideoPlayerLib.podspec --allow-warnings

–use-libraries表示依赖了静态库,–allow-warnings忽略警告
使用 pod spec lint VideoPlayerLib.pods --verbose 去查看详细错误
iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)打包类库:需要使用一个cocoapods的插件cocoapods-packager来完成类库的打包。
安装打包插件命令

lzz-Mac-mini:~ suning$ sudo gem install cocoapods-packager
Password:
Fetching: cocoapods-packager-1.5.0.gem (100%)
Successfully installed cocoapods-packager-1.5.0

Parsing documentation for cocoapods-packager-1.5.0
Installing ri documentation for cocoapods-packager-1.5.0
Done installing documentation for cocoapods-packager after 0 seconds
1 gem installed
lzz-Mac-mini:~ suning$ 
  1. 提交源码,并打tag。
    git add .
    git commit -a -m 'v0.1.0'
    git tag -a 0.1.0 -m 'v0.1.0'

git commit -a -m’v请换成版本号’
git tag -a 版本号 -m’v版本号’
记住,tag必须和.podspec文件中的 版本号一致! 同时,一旦修改了.podspec, 必须进入Example文件, 进行 pod install操作,然后退出到上级目录中 提交git

  1. 打包静态库
    // 打包静态.a 用这个
pod package VideoPlayerLib.podspec --library --force

iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)
//打包静态framework 用这个,如果不修改版本号,它会把上面打包的.a 清除掉

pod package VideoPlayerLib.podspec --force

iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)为了保留两种静态库.a 和.framework ,编译一个版本号v0.2.0的库
第一步:修改版本号

  s.version          = '0.2.0'

第二步:提交源码,并打tag。

    git add .
    git commit -a -m 'v0.2.0'
    git tag -a 0.2.0 -m 'v0.2.0'

第三步:打包静态库

pod package VideoPlayerLib.podspec --force

iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)
最终得到两个版本的.a 和.framework 库
iOS架构-cocoapods打包静态库(依赖私有库、开源库、私有库又包含静态库)(14)
这样就完成静态库的打包了,并且打出来的包是支持 armv7 armv7s i386 x86_64 arm64 平台的,如果修改静态库代码,只需要修改版本号,执行pod install ,git add 步骤就能轻松打包了。比脚本还要简单。cocoapods不愧为打包神器!

遗留:在配置中为了不打断静态库的编译。暂时没有依赖私有库、私有库又包含静态库。依赖了开源库Toast 没有使用。

感谢:

Cocoapods 打包framework或者.a静态库
使用cocoapods打包静态库(依赖私有库,开源库,私有库又包含静态库)