When some projects are mature, there will be a need to automate configuration to generate a completely new project, no need for developers to manually modify the project files, and transfer the configuration work directly to operations and maintenance or the configuration team
In fact, it is common practice to just change the target duplicate in xcode, then modify the related project name, target name, bundleid and so on. These contents actually have corresponding configuration information in the xcodeproj file, so we can achieve this by directly modifying the direct file of Xcodeproj.
First thanks Shrimp God Provides detailed explanation of the principle and introduction of the tools, takes a lot less detours in the implementation, and interested students can go there. Shrimp God Articles study, here I will post the final implementation for your reference~~
Students who wish to learn more about ios project configuration and scripting suggest going here:
xcodeproj related API documentation
Skillfully Solve Target Management Problems with Scripts
#!/usr/bin/env ruby require 'rubygems' require 'xcodeproj' require 'fileutils' #----------------------------------- Target project configuration content----------------------------# name = "newyorktoon" displayname = "New York Tong" target_toonType = 10001 target_pushType = "hello" target_channel = "hello" target_mapKey = "hello" target_schemeType = "hello" #----------------------------------- Target project configuration content----------------------------# # Template Project # srcname = "tzhqtoon" # srcdisplayname = "Logistics" #project project_path = "Hello.xcodeproj" # Copy the resource file, note: # 1. Exclude source resource files when copying resource files # 2. Add the copied resource file to the destination at the end of this file target targetdir = "TNTarget/#" srcroot = "TNTarget/#" # Copy Resource Folder,Will Source target Copy the following picture resource folder to the destination target Catalog if !Dir.exists?(targetdir) Dir.mkdir(targetdir) end codeDirs = [ "#/Resources", "#/NetWork", "#/TabbarSetDataSource", "#/TNHQHome" ] #Copy Source target Directory of customized code to target target Catalog hasAllListFiles = false codeDirs.each do |d| hasAllListFiles = Dir.exists?(d)#-> This assumes that all code file As a whole, one has if hasAllListFiles FileUtils.cp_r d, targetdir end end # Find Templates target proj = Xcodeproj::Project.open(project_path) src_target = proj.targets.find { |item| item.to_s == srcname } # Create goals target target = proj.new_target(src_target.symbol_type, name, src_target.platform_name, src_target.deployment_target) target.product_name = name # create scheme scheme = Xcodeproj::XCScheme.new scheme.add_build_target(target) scheme.set_launch_target(target) scheme.save_as(project_path, name) # build_configurations target.build_configurations.map do |item| #Set up target Related Configuration item.build_settings.update(src_target.build_settings(item.name)) # puts "-"*30 + "#" +"_"*30 item.build_settings["PRODUCT_BUNDLE_IDENTIFIER"] = "com.abc.aa.#" item.build_settings["PRODUCT_NAME"] =displayname targetInfoPlist = item.build_settings["INFOPLIST_FILE"] item.build_settings["INFOPLIST_FILE"] = targetInfoPlist.sub(srcname, name) puts "-"*30 + "#" +"_"*30 puts "-"*30 + "#" +"_"*30 end # build_phases phases = src_target.build_phases.reject { |x| x.instance_of? Xcodeproj::Project::Object::PBXShellScriptBuildPhase }.collect(&:class) #Copy Source target Referenced source and resource File Reference phases.each do |klass| puts "||---------------------> copy phases #--------------------||" src = src_target.build_phases.find { |x| x.instance_of? klass } dst = target.build_phases.find { |x| x.instance_of? klass } unless dst dst ||= proj.new(klass) target.build_phases << dst end dst.files.map { |x| x.remove_from_project } idx = 1 src.files.each do |f| # Exclude files, source target Exclude files from, do not reference them if f.file_ref and f.file_ref.hierarchy_path.index(srcroot) != nil puts "\n................... ignore file: #, #...................\n" next end file_ref = proj.new(Xcodeproj::Project::Object::PBXFileReference) if f.settings puts ">>file.settings: # > file: " + f.file_ref.to_s + " settings: " + f.settings.to_s end idx = idx+1 if f.file_ref if f.file_ref.name puts ">> file_ref name: # path: # source_tree: #" end # puts ">> file path: #-- #" file_ref.name = f.file_ref.name file_ref.path = f.file_ref.path file_ref.source_tree = f.file_ref.source_tree file_ref.last_known_file_type = f.file_ref.last_known_file_type # file_ref.fileEncoding = f.file_ref.fileEncoding begin file_ref.move(f.file_ref.parent) rescue end end build_file = proj.new(Xcodeproj::Project::Object::PBXBuildFile) build_file.file_ref = f.file_ref # File property configuration, such as no-arc if f.settings build_file.settings = f.settings end dst.files << build_file end end #Set goals target File Groups projTargetGroup = proj.main_group.groups.find { |x| x.path == 'TNTarget' } targetGroup = projTargetGroup.new_group(name, name) # resource resourceGroup = targetGroup.new_group("Resources", "./Resources") supportingGroup=resourceGroup.new_group("Supporting Files") # Add resource file references, note that they differ from code file references target.add_resources( [ resourceGroup.new_reference("areaCode.plist"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("[email protected]"), resourceGroup.new_reference("toon_serviceProtocol.html"), resourceGroup.new_reference("user_protocol.html"), resourceGroup.new_reference("NewFunction.html"), supportingGroup.new_reference("Supporting Files/configuration.plist"), supportingGroup.new_reference("Supporting Files/Info.plist"), supportingGroup.new_reference("Supporting Files/Images.xcassets"), supportingGroup.new_reference("Supporting Files/InfoPlist.strings"), supportingGroup.new_reference("Supporting Files/Localizable.strings") ]) if hasAllListFiles # Add Code File Group code1 = targetGroup.new_group("NetWork", "./NetWork") code2 = targetGroup.new_group("TabbarSetDataSource", "./TabbarSetDataSource") code3 = targetGroup.new_group("TNHQHome", "./TNHQHome") # Add Code File Reference target.add_file_references( [ code1.new_reference("NetworkRequestURL.h"), code1.new_reference("NetworkRequestURL.m"), code2.new_reference("TNTabSettingDataSource.h"), code2.new_reference("TNTabSettingDataSource.m"), code3.new_reference("TNHomeViewController.m") ]) end # Modify File Common Content infoplistfile = "#/Resources/Supporting Files/Info.plist" files = [ "#/Resources/areaCode.plist", "#/Resources/toon_serviceProtocol.html", "#/Resources/user_protocol.html", "#/Resources/NewFunction.html", infoplistfile, "#/Resources/Supporting Files/InfoPlist.strings", "#/Resources/Supporting Files/Localizable.strings" ] if hasAllListFiles files << "#/TabbarSetDataSource/TNTabSettingDataSource.m" end files.each do |f1| File.open(f1) do |fr| buffer = fr.read.gsub(srcdisplayname, displayname) buffer= buffer.gsub("Project Name", displayname) buffer= buffer.gsub("Da Tong", displayname) File.open(f1, "w") { |fw| fw.write(buffer) } end end # modify info.plist File.open(infoplistfile) do |fr| if hasAllListFiles puts "*************************** 1" buffer = fr.read.gsub("<string>10024</string>", "<string>#</string>") buffer= buffer.gsub("<integer>124</integer>", "<integer>#</integer>") buffer= buffer.gsub("<string>1241002</string>", "<string>#</string>") buffer= buffer.gsub("<string>8058bda8c0ad5a7cfb8742cfbac4ecb8</string>", "<string>#</string>") buffer= buffer.gsub("<string>toon124</string>", "<string>#</string>") else puts "*************************** 2" buffer = fr.read.gsub("<string>10016</string>", "<string>#</string>") buffer= buffer.gsub("<integer>116</integer>", "<integer>#</integer>") buffer= buffer.gsub("<string>10035</string>", "<string>#</string>") buffer= buffer.gsub("<string>e851d7df83d59f143bff1ad5a3a8e554</string>", "<string>#</string>") buffer= buffer.gsub("<string>toon116</string>", "<string>#</string>") end puts "*************************** updating InfoPlist" File.open(infoplistfile, "w") { |fw| fw.write(buffer) } end proj.save # modify Podfile puts ">> prepare loading pods ..." podTarget = "target '#' do shared_pods end" File.open("Podfile") do |file| if file.read().index(podTarget) ==nil File.open(infoplistfile, "w") { |fw| fw.puts podTarget } puts ">> add pod item" else puts ">> pod has been added" end end # file.close # To update pod rely on exec 'pod install'