問題
升級Xcode12之后,單測的target (ReadInJoyTests) 出現(xiàn)了報錯:
error: Cycle inside ReadInJoyTests; building could produce unreliable results.
Cycle details:
→ Target 'ReadInJoyTests': CodeSign /Users/yoferzhang/Library/Developer/Xcode/DerivedData/QQMSFContact-gpvqexdcrtvrsdczqfqownxrezqo/Build/Products/Debug-iphonesimulator/QQ.app/EarlGrey.framework
○ That command depends on command in Target 'ReadInJoyTests': script phase “[CP] Copy Pods Resources”
○ Target 'ReadInJoyTests': CodeSign /Users/yoferzhang/Library/Developer/Xcode/DerivedData/QQMSFContact-gpvqexdcrtvrsdczqfqownxrezqo/Build/Products/Debug-iphonesimulator/QQ.app/EarlGrey.framework
解決方案,是要刪除 ReadInJoyTests target 中 build phase 的 [CP] Copy Pods Resources 的 Output file lists
手動刪除

image
手動清空后,pod install 后還是會生成。
腳本刪除
考慮是否可以通過腳本刪除。
刪除方法
腳本刪除可以分為以下幾步:
- 獲取主工程的
xcodeproj - 找到target
ReadInJoyTeststarget - 找到build phase
[CP] Copy Pods Resources - 保存project
刪除的代碼
require 'xcodeproj'
def delete_rij_tests_output_file_lists
puts "===================> Start delete ReadInJoyTests Target [CP] Copy Pods Resources output file lists"
project_path = './QQMSFContact.xcodeproj'
project = Xcodeproj::Project.open(project_path)
project.targets.each do |target|
if target.name == "ReadInJoyTests"
puts "===================> Find ReadInJoyTests Target"
build_phase = target.build_phases.find { |bp| bp.display_name == '[CP] Copy Pods Resources' }
puts "===================> Before delete, Output file lists:"
puts build_phase.output_file_list_paths
# 執(zhí)行刪除
while build_phase.output_file_list_paths.length > 0
build_phase.output_file_list_paths.pop()
end
end
end
# 保存工程文件
project.save
puts "===================> Finish delete ReadInJoyTests Target [CP] Copy Pods Resources output file lists"
end
刪除時機
首先來看一下cocoapods的hook執(zhí)行順序
- 終端執(zhí)行命令
pod install - 運行
podfile中的 ruby method - 執(zhí)行hook
pre_install - 執(zhí)行 pod install 的行為,但此時修改內(nèi)容還在內(nèi)存的 installer 中,還未寫入磁盤
- 執(zhí)行hook
post_install,同上還是未寫入磁盤 - 將installer修改部分寫入磁盤
如果在 post_install 中執(zhí)行 delete_rij_tests_output_file_lists ,那因為 post_install 內(nèi)pod的修改還沒寫入磁盤,delete_rij_tests_output_file_lists 的修改,會被 post_install 之后pod寫入磁盤而覆蓋掉。導(dǎo)致刪除失敗。
調(diào)試發(fā)現(xiàn),如果在第3步之前, output file paths 內(nèi)容存在,則在post_install 中執(zhí)行刪除,就不會發(fā)生覆蓋寫入時重新生成 output file paths 。
也就是說可以在第3步之前,先通過腳本寫入 path,欺騙cocoapods,path存在,這次 install 就不要生成path 做添加動作。然后在post_install 中執(zhí)行刪除邏輯,這樣就解決了問題。
寫入path的代碼為:
def add_rij_tests_temp_output_file_list
project_path = './QQMSFContact.xcodeproj'
project = Xcodeproj::Project.open(project_path)
project.targets.each do |target|
if target.name == "ReadInJoyTests"
puts "===================> Find ReadInJoyTests Target"
build_phase = target.build_phases.find { |bp| bp.display_name == '[CP] Copy Pods Resources' }
puts "===================> Before add, temp output file lists:"
puts build_phase.output_file_list_paths
list_path = '${PODS_ROOT}/Target Support Files/Pods-ReadInJoyTests/Pods-ReadInJoyTests-resources-${CONFIGURATION}-output-files.xcfilelist'
# 添加路徑
if build_phase.output_file_list_paths.include?(list_path) == false
build_phase.output_file_list_paths.push(list_path)
end
end
end
# 保存工程文件
project.save
end
最后修改完成的podfile 為
# 省略上述兩個method定義
post_install do |installer|
# 省略...
# 刪除 ReadInJoyTests Target [CP] Copy Pods Resources output file lists
delete_rij_tests_output_file_lists
end
# pod install之前添加一次,讓 pod 認為已經(jīng)有了path,pod install過程中就不會再新增了
add_rij_tests_temp_output_file_list
完整流程
最后來看完整的流程
- 臨時添加
output file path,讓cocoapods認為本次install無需做添加path的動作。 - install 生成工程修改(不會添加path)
-
post_install中再刪除output file path - pod將install 寫入磁盤。
See Also
最后提供一個不用 xcodeproj 工具的刪除方法
post_install do |installer|
installer.aggregate_targets.each do |target|
if target.name == "Pods-ReadInJoyTests"
puts "==========> Find Pods-ReadInJoyTests:"
project = target.user_project
puts project
project.targets.each do |sub_target|
if sub_target.name =="ReadInJoyTests"
puts "==========> Find ReadInJoyTests Target"
build_phase = sub_target.build_ phases. find { |bp| bp.display_name == '[CP] Copy Pods Resources' }
puts "==========> Before delete, Output file lists:"
puts build_phase.output_file_list_paths
#執(zhí)行刪除
build_phase.output_file_list_paths.pop( )
puts"==========> After delete, Output file lists:"
puts build_phase.output_file_list_paths
end
end
project. save
end
end
end