更新記錄
- 2020年3月28日,初稿
源碼地址
- CocoaPods/CocoaPods
- Pod是由Ruby實現的,所以想要讀懂源碼,還需要先了解一下Ruby的源碼
源碼運行過程(含注釋),即輸入Pod install(或update)的執行過程
前置環節-生成對應的Command子類對象(例如Install類和Update類)
- Pod::Command的run類方法
def self.run(argv)
help! 'You cannot run CocoaPods as root.' if Process.uid == 0 && !Gem.win_platform?
verify_minimum_git_version!
verify_xcode_license_approved!
super(argv)
ensure
UI.print_warnings
end
- CLAide::Command類的run方法
def self.run(argv = [])
plugin_prefixes.each do |plugin_prefix|
PluginManager.load_plugins(plugin_prefix)
end
argv = ARGV.coerce(argv)
#通過參數生成一個Command類的子類對象
command = parse(argv)
ANSI.disabled = !command.ansi_output?
unless command.handle_root_options(argv)
command.validate!
# 調用comman類子類對象的run方法
command.run
end
rescue Object => exception
handle_exception(command, exception)
end
- CLAide::Command類的parse方法
# @param [Array, ARGV] argv
# A list of (remaining) parameters.
#
# @return [Command] An instance of the command class that was matched by
# going through the arguments in the parameters and drilling down
# command classes.
#
def self.parse(argv)self.run
argv = ARGV.coerce(argv)
# 得到第一個參數
cmd = argv.arguments.first
if cmd && subcommand = find_subcommand(cmd)
argv.shift_argument
subcommand.parse(argv)
elsif abstract_command? && default_subcommand
load_default_subcommand(argv)
else
new(argv)
end
end
3.1 CLAide::Command類的argument方法
# @return [Array<Argument>]
# A list of arguments the command handles. This is shown
# in the usage section of the command’s help banner.
# Each Argument in the array represents an argument by its name
# (or list of alternatives) and whether it's required or optional
#
def arguments
# 如果@arguments不為空,則返回@arguments,否則返回空數組
@arguments ||= []
end
3.2 CLAide::Command類的find_subcommand方法
# Searches the list of subcommands that should not be ignored for command
# lookup for a subcommand with the given `name`.
#
# @param [String] name
# The name of the subcommand to be found.
#
# @return [CLAide::Command, nil] The subcommand, if found.
#
def self.find_subcommand(name)
subcommands_for_command_lookup.find { |sc| sc.command == name }
end
3.3 通過 find_subcommand 找到對應的子類對象,然后調用子類對象的parse方法(subcommand.parse(argv))
def self.parse(argv)
entries = []
#對argv數組的每個值進行to_s的表達式操作,生成一個新的數組,存儲到copy變量中
copy = argv.map(&:to_s)
double_dash = false
#shift返回數組的第一個元素,並且移除該元素。類比stack的pop函數
while argument = copy.shift
# if為真,直接進入下次循環
next if !double_dash && double_dash = (argument == '--')
type = double_dash ? :arg : argument_type(argument)
parsed_argument = parse_argument(type, argument)
entries << [type, parsed_argument]
end
entries
end
實際pod主流程的核心環節(調用Installer類的install函數)
- 看到 CocoaPods/lib/cocoapods/command/install.rb中Install類的run方法
def run
verify_podfile_exists!
installer = installer_for_config
installer.repo_update = repo_update?(:default => false)
installer.update = false
installer.deployment = @deployment
installer.clean_install = @clean_install
installer.install!
end
- 我們對比一下 CocoaPods/lib/cocoapods/command/update.rb中Update類的run方法
def run
verify_podfile_exists!
installer = installer_for_config
installer.repo_update = repo_update?(:default => true)
installer.clean_install = @clean_install
if @pods.any? || @excluded_pods.any? || @source_pods.any?
verify_lockfile_exists!
verify_pods_are_installed!
verify_excluded_pods_are_installed!
@pods += @source_pods.select { |pod| config.lockfile.pod_names.include?(pod) }
@pods = config.lockfile.pod_names.dup if @pods.empty?
@pods -= @excluded_pods
installer.update = { :pods => @pods }
else
UI.puts 'Update all pods'.yellow
installer.update = true
end
installer.install!
end
- 對比Install類和Update類的run方法,我們發現
- 相同點
- 最后都會調用Installer類的
install!函數
- 最后都會調用Installer類的
- 明顯的不同點
- Install命令類的
repo_update屬性為false,Update命令類的repo_update函數為true - Install命令類的
update屬性為false,Update命令類的update函數為true
- Install命令類的
- 相同點
- 參考Podfile.lock背后的那點事,我們可以提前知道
update變量的值,區分了Installer調用install函數下,使用pod install和pod update的場景。
本篇結論
- 本篇分析執行Pod install或者update的前幾個步驟,主要是通過命令行參數(install或者update)的解析,實例化不同的
Command子類對象。 - install和update參數的命令執行,最后都會進入Installer類的install函數,執行核心的依賴庫安裝過程。
- Installer類的install函數,是通過update的值,來判斷兩種不同的場景(即update和install)來進行不同的操作
- 另附上簡單版(真的是簡單版,別見怪)類圖,流程圖


寫在后面的話
- 鑒於篇幅已較長,為了有較好的閱讀體驗(避免文章分析過長,很多讀者其實都沒有耐心看下去),而且自己也不能一下子完全捋清楚,所以第一篇到此為止。
- 后續會從該篇的節點繼續往下分析
- 后續還需要分析的點
- Installer類中的update屬性如何使用?如何具體地區別install和update兩種場景?
- PodFile.lock文件有何作用?
- Pod如何解析PodFile文件的?
- Pod.spec文件有何作用?
- Pod是如何集成Xcode工程的?
