咱們平時在作開發的時候,多少會接觸到組件化的思想。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 腳本,喜歡的關注下。