咱们平时在作开发的时候,多少会接触到组件化的思想。iOS的组件化通常是经过使用 cocoapods
制成pod库的形式完成的。pod库又分为公开库和私有库两种。好比咱们上传到 github
的就属于公开库,提供别人下载使用。而部署在公司内部的则属于私有库,别人访问不了,使用不到。html
本文主要是讲如何实现自动部署pod脚本的,所以关于pod库相关的概念只会作个简单的介绍,不会作过多的讲解。若是想要有更深刻的了解,能够查阅官方文档。git
一个 repo
就是至关于一个放置相关 pod
库的索引的仓库。怎么理解?好比咱们在github上制做的公开库,它的 repo
叫什么?叫 trunk,地址是 https://cdn.cocoapods.org/
。咱们能够直接在本机执行命令: pod repo
,将会看到图示。github
这个仓库就是存放咱们部署上去的 podspec
文件的。ruby
而一个 podspec
则是用于描述一个pod库,如库结构,版本,源代码地址等。markdown
了解了这两个,那么咱们就能够制做本身的pod库了。less
以制做公开库,提交到 github
为例。提交到trunk的官方文档点我ide
首先你须要现有一个源代码仓库,oop
pod spec create yourSpecName.podspec
复制代码
例如podspec文件内容以下,编辑里面的source、source_files等。组件化
Pod::Spec.new do |spec|
spec.name = 'Reachability'
spec.version = '3.1.0'
spec.license = { :type => 'BSD' }
spec.homepage = 'https://github.com/tonymillion/Reachability'
spec.authors = { 'Tony Million' => 'tonymillion@gmail.com' }
spec.summary = 'ARC and GCD Compatible Reachability Class for iOS and macOS.'
spec.source = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' }
spec.source_files = 'Reachability.h,m'
spec.framework = 'SystemConfiguration'
spec.requires_arc = true
end
复制代码
git commit -am 'submit'
git push origin
复制代码
注意到podspec是有版本号的概念的,它须要和你pod库,也就是源代码库的tag值是一致的。这样,咱们的cocoapods才能在解析podspec以后,下载到正确版本对应的源代码。ui
git tag 0.0.2
#推送指定tag到远端
git push origin 0.0.2
# 或者推送本地全部tag到远端
# git push origin --tags
复制代码
本地验证:
pod lib lint yourSpecName.podspec --allow-warnings
复制代码
远程验证:
pod spec line yourSpecName.podspec --allow-warnings
复制代码
pod trunk push yourSpecName.podspec --allow-warnings
复制代码
此时咱们的库中应该已经有一个podspec文件了的,咱们须要作的就是更新它的版本号,若是文件结构有变更,就须要改动 source_files
,有添加新的依赖库,那么须要修改 dependency
。
打开podspec文件,编辑更新version
字段就好,通常采用递增的方式。
# 须要先提交代码
git commit -am 'update'
git push origin
git tag 0.0.2
git push origin 0.0.2
# 或 git push origin --tags
复制代码
这一步在这里骑士能够跳过,通常第一次上传没问题,后面也不会出现问题。
pod lib lint *.podspec
复制代码
pod trunk push *.podspec
复制代码
脚本使用 ruby
实现的,源码在这。
实现的原理其实也是用了更新podspec的步骤,只不过是加了一些配置而已。
使用起来比较简单,将脚本放在在当前的pod根目录下,执行 ruby specpush.rb
便可一键发布。
这里直接贴代码:
#! /usr/bin/ruby
class Color
def self.natural
0
end
def self.black
30
end
def self.red
31
end
def self.green
32
end
def self.yellow
33
end
def self.blue
34
end
def self.magenta
35
end
def self.cyan
36
end
def self.white
37
end
end
def color_text(text, color = Color.natural)
if color == 0
return text
end
return "\033[#{color}m#{text}\033[0m"
end
def die_log(text)
puts color_text(text, Color.red)
end
# 拉取最新代码
# if system('git pull --rebase origin') == false
# system('git rebase --abort')
# puts color_text("There is a conflict, please handle it and retry", Color.red)
# return
# end
cur_path = Dir.pwd
push_path = cur_path
relate_dir_path = ''
user_custom_version = true
verify_podspec_format = true
pod_repo_name = 'trunk'
pod_repo_source =
is_static_lib = false
# 检查是否存在 SpecPushFile 文件,若是不存在,那么建立
if not File::exist?(cur_path + '/PodPushFile')
system('touch PodPushFile')
File.open(cur_path + '/PodPushFile', 'w+') do |f|
f.write("#写入*.podspec所在的相对目录,不写默认会在脚本执行的目录下查找 PUSH_DIR_PATH= #是否容许用户自定义版本号,不填或填true将容许用户设置自定义的版本号,而不是自增版本号 USER_CUSTOM_VERSION=true #默认开启验证,能够跳过验证阶段 VERIFY_PODSPEC_FORMAT=true #pod repo的名字,若是是私有库就填私有库的名字 POD_REPO_NAME=trunk #pod repo的源地址 POD_REPO_SOURCE=https://github.com/CocoaPods/Specs #若是这个库是静态库,那么须要设置为true POD_IS_STATIC_LIBRARY=false")
end
puts color_text('Create PodPushFile', Color.green)
puts color_text("First you should modify 'PodPushFile' file and run the script again", Color.white)
system('open PodPushFile')
return
end
puts color_text('Parse PodPushFile...', Color.white)
File.open(cur_path + '/PodPushFile') do |f|
f.each_line do |line|
key_value = line.split('=')
key = key_value.first.to_s.gsub("\n", '').gsub(' ','').gsub("\t",'')
value =
if key_value.count > 1
value = key_value.last.to_s.gsub("\n", '').gsub(' ','').gsub("\t",'')
end
# puts "key=#{key},value=#{value}"
if key.to_s == 'PUSH_DIR_PATH' and not value.nil?
relate_dir_path = value
push_path = cur_path + '/' + relate_dir_path
elsif key.to_s == 'USER_CUSTOM_VERSION' and not value.nil?
user_custom_version = value == 'true'
elsif key.to_s == 'VERIFY_PODSPEC_FORMAT' and not value.nil?
verify_podspec_format = value == 'true'
elsif key.to_s == 'POD_REPO_NAME' and not value.nil?
pod_repo_name = value.to_s
elsif key.to_s == 'POD_REPO_SOURCE' and not value.nil?
pod_repo_source = value
elsif key.to_s == 'POD_IS_STATIC_LIBRARY' and not value.nil?
is_static_lib = value == 'true'
end
end
end
# puts "Push path is: #{push_path}, relate dir path is: #{relate_dir_path}"
# 搜索podspec路径
podspec_path = ''
find_podspec_reg = (relate_dir_path.length == 0 ? '' : (relate_dir_path + '/')) + '*.podspec'
# puts "Find podspec reg = #{find_podspec_reg}"
Dir::glob(find_podspec_reg) do |f|
podspec_path = f
end
if podspec_path.length == 0
puts "Find podspec in current dir"
else
puts "Find podspec in releate path=#{podspec_path}"
end
if not File::exist?(podspec_path)
die_log("Can't find any podspec file in path: #{podspec_path}, please modify PodPushFile' PUSH_DIR_PATH(key)")
return
else
puts "Find podspec named" + color_text("#{podspec_path}", Color.white)
end
# 在当前podspec目录下新建一个临时 need_delete_temp.podspec 文件
podspec_dir = File.dirname podspec_path
podspec_absolute_path = cur_path + '/' + podspec_path
temp_podspec_path = podspec_dir + '/need_delete_temp.podspec'
temp_podspec_absolute_path = cur_path + '/' + temp_podspec_path
cur_version = ''
# 读取当前podspec文件的版本
File.open(podspec_absolute_path, 'r+') do |f|
f.each_line do |line|
# 查找.version
version_desc = /.*\.version[\s]*=.*/.match line
if not version_desc.nil?
cur_version = version_desc.to_s.split('=').last.to_s.gsub("'", '')
cur_version = cur_version.gsub(' ', '')
break
end
end
end
puts color_text("Current version = ", Color.white) + color_text("#{cur_version}", Color.green)
# 容许自定义版本号
if user_custom_version == true
puts color_text "Please input pod lib's new version, if there is no input or less than or equal old version, it will be incremented:", Color.white
input_version = gets.chomp
# 判断输入的version是否>当前的版本号
input_v_s = input_version.to_s.split('.')
cur_v_s = cur_version.split('.')
# 比较的位置,从最左边开始
v_index = 0
# 输入的version是否有效
input_valid = false
while v_index < cur_v_s.count && v_index < input_v_s.count do
if input_v_s[v_index].to_i > cur_v_s[v_index].to_i
# 说明用户输入的version比当前的大
input_valid = true
break
elsif input_v_s[v_index].to_i == cur_v_s[v_index].to_i
v_index += 1
else
break
end
end
if input_valid == false
puts color_text "Input invalid version = #{input_version},will auto +1 in last component", Color.natural
end
end
if not File.exist? temp_podspec_absolute_path
# system("cp -f #{podspec_path} #{temp_podspec_path}")
system("touch #{temp_podspec_path}")
end
new_version = ''
git_source = ''
File.open(temp_podspec_absolute_path, 'r+') do |t|
File.open(podspec_absolute_path) do |f|
f.each_line do |line|
# # 查找.version
# s.version = "0.0.2"
# 须要注意的是,版本号能够是'',也能够是""
write_line = line
version_desc = /.*\.version[\s]*=.*/.match line
if not version_desc.nil?
version_coms = version_desc.to_s.split('=')
if input_valid == true and user_custom_version == true
new_version = input_version.to_s
else
version_num = version_coms.last.to_s.gsub("'",'').gsub("\"",'').gsub(' ','')
v_s = version_num.split('.')
# 处理版本号 0.0.1
for i in 0...v_s.count do
if i == v_s.count - 1
new_version += (v_s[i].to_i + 1).to_s
else
new_version += (v_s[i].to_s + '.')
end
end
end
puts color_text("New version = ",Color.white) + color_text("#{new_version}", Color.green)
write_line = version_coms.first.to_s + '=' + " '#{new_version}'" + "\n"
end
source_desc = /.*\.source[\s]*=.*/.match line
if not source_desc.nil?
source_desc = /:git.*,/.match source_desc.to_s
source_desc = /'.*'/.match source_desc.to_s
git_source = source_desc.to_s.gsub("'",'')
puts "git source is #{git_source}"
end
t.write write_line
end
end
end
puts color_text("Update version from ",Color.white) + color_text("#{cur_version}",Color.green) + color_text(" to ",Color.white) + color_text("#{new_version}", Color.green)
# 将新数据反写回到原始podspec中
system("cp -f #{temp_podspec_path} #{podspec_path}")
system("rm -f #{temp_podspec_path}")
# 若是本地没有这个repo,那么添加
if system("pod repo | grep #{pod_repo_name}") == false
puts color_text("Add pod repo named '#{pod_repo_name}' with source: #{pod_repo_source}", Color.white)
system("pod repo add #{pod_repo_name} #{pod_repo_source}")
end
# 提交代码到远程仓库
puts color_text('Start upload code to remote', Color.white)
system("git commit -am 'update version to #{new_version}'")
if system('git push origin') == false
die_log('[!] git push code error')
end
system("git tag #{new_version}")
if system('git push origin --tags') == false
die_log('[!] git push tags error')
return
end
# 验证podspec格式是否正确
if verify_podspec_format == true
puts color_text("Start verify podspec '#{podspec_path}'...", Color.white)
if system("pod lib lint #{podspec_path} --allow-warnings") == false
die_log("[!] pod spec' format invalid")
return
end
end
# 提交pod spec到spec仓库
puts color_text("Start push pod '#{podspec_path}' to remote repo '#{pod_repo_name}'", Color.white)
if pod_repo_name == 'trunk'
if (is_static_lib == true ? system("pod trunk push #{podspec_path} --allow-warnings --use-libraries") : system("pod trunk push #{podspec_path} --allow-warnings")) == false
puts "If not timeout, you need to check your 'trunk' account like: 'pod trunk me', and register code is 'pod trunk register <your email> <your name>'"
return
end
else
if (is_static_lib == true ? system("pod repo push #{pod_repo_name} #{podspec_path} --allow-warnings --use-libraries") : system("pod repo push #{pod_repo_name} #{podspec_path} --allow-warnings")) == false
return
end
end
puts color_text("Update success ☕️! Current version = #{new_version}", Color.green)
复制代码
这里提一下 PodPushFile 文件,这个是配置文件,里面有这些配置项:
#写入*.podspec所在的相对目录,不写默认会在脚本执行的目录下查找,若是脚本执行的目录和podspec文件不在同一目录下,那么须要配置下
PUSH_DIR_PATH=
#是否容许用户自定义版本号,不填或填true将容许用户设置自定义的版本号,而不是自增版本号
USER_CUSTOM_VERSION=true
#默认开启验证,能够跳过验证阶段
VERIFY_PODSPEC_FORMAT=true
#pod repo的名字,若是是私有库就填私有库的名字
POD_REPO_NAME=trunk
#pod repo的源地址,若是是私有仓库,那么填写私有仓库的地址,注意是存放podspec的仓库的地址
POD_REPO_SOURCE=https://github.com/CocoaPods/Specs
#若是这个库是静态库,那么须要设置为true
POD_IS_STATIC_LIBRARY=false
复制代码
若是脚本有任何问题,请评论留言。rubyRepo
这是个人 ruby 仓库地址,里面会不时更新一些有用好玩的 ruby 脚本,喜欢的关注下。