有些项目成熟以后,就会有需求自动化配置生成一个全新的项目,不需要再让开发人员手动修改工程文件,将配置化工作直接移交给运维或者配置团队去做

其实按照普通的做法,无非就是在xcode里将目标target duplicate一下,然后修改相关的项目名称、target名称、bundleid等等,这些内容其实在xcodeproj文件中都有对应的配置信息,所以我们可以通过直接修改Xcodeproj直接文件的方式实现

首先感谢虾神 提供了详细的原理解说和工具介绍,在实现时少走了很多弯路,有兴趣的同学可以前往 虾神 的文章学习,这里我把最终实现贴出来供大家参考~~

希望进一步学习ios工程配置和脚本相关的同学建议去这里:

ruby doc

xcodeproj相关API文档

github示例

巧用脚本解决 Target 管理问题

#!/usr/bin/env ruby
require 'rubygems'
require 'xcodeproj'
require 'fileutils'#----------------------------------- 目标项目配置内容----------------------------#
name = "newyorktoon"
displayname = "纽约通"
target_toonType = 10001
target_pushType = "hello"
target_channel = "hello"
target_mapKey = "hello"
target_schemeType = "hello"
#----------------------------------- 目标项目配置内容----------------------------## 模板项目
# srcname = "tzhqtoon"
# srcdisplayname = "后勤通"                                                 #project
project_path = "Hello.xcodeproj"
# 复制资源文件,注意:
# 1. 复制资源文件时需要排除源资源文件
# 2. 在此文件的最后面将复制出来的资源文件添加到目标target
targetdir = "TNTarget/#{name}"
srcroot = "TNTarget/#{srcname}"# 复制资源文件夹,将源target下的图片资源文件夹复制到目标target目录
if !Dir.exists?(targetdir)Dir.mkdir(targetdir)
end
codeDirs = ["#{srcroot}/Resources","#{srcroot}/NetWork","#{srcroot}/TabbarSetDataSource","#{srcroot}/TNHQHome"
]
#复制源target目录下的定制化代码目录到目标target目录
hasAllListFiles = false
codeDirs.each do |d|hasAllListFiles = Dir.exists?(d)#-> 此处假设所有的code file为一个整体,一有具有if hasAllListFilesFileUtils.cp_r  d, targetdirend
end# 寻找模板target
proj = Xcodeproj::Project.open(project_path)
src_target = proj.targets.find { |item| item.to_s == srcname }
# 创建目标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|#设置target相关配置
  item.build_settings.update(src_target.build_settings(item.name))# puts "-"*30 + "#{item.build_settings}" +"_"*30item.build_settings["PRODUCT_BUNDLE_IDENTIFIER"] = "com.abc.aa.#{name}"item.build_settings["PRODUCT_NAME"] =displaynametargetInfoPlist = item.build_settings["INFOPLIST_FILE"]item.build_settings["INFOPLIST_FILE"] = targetInfoPlist.sub(srcname, name)puts "-"*30 + "#{item.build_settings['PRODUCT_BUNDLE_IDENTIFIER']}" +"_"*30puts "-"*30 + "#{item.build_settings['PRODUCT_NAME']}" +"_"*30
end# build_phases
phases = src_target.build_phases.reject { |x| x.instance_of? Xcodeproj::Project::Object::PBXShellScriptBuildPhase }.collect(&:class)#复制源target引用的source和resource文件引用
phases.each do |klass|
puts "||---------------------> copy phases #{klass}--------------------||"src = src_target.build_phases.find { |x| x.instance_of? klass }dst = target.build_phases.find { |x| x.instance_of? klass }unless dstdst ||= proj.new(klass)target.build_phases << dstenddst.files.map { |x| x.remove_from_project }idx = 1src.files.each do |f|
# 排除文件,将源target中的文件排除,不引用该文件if f.file_ref and f.file_ref.hierarchy_path.index(srcroot) != nilputs "\n................... ignore file:  #{f.file_ref}, #{f.file_ref.hierarchy_path}...................\n"nextendfile_ref = proj.new(Xcodeproj::Project::Object::PBXFileReference)if f.settingsputs ">>file.settings:  #{idx} > file: " + f.file_ref.to_s + " settings: " + f.settings.to_sendidx = idx+1if f.file_refif f.file_ref.nameputs ">> file_ref name: #{f.file_ref.name} path: #{f.file_ref.path} source_tree: #{f.file_ref.source_tree}"end# puts ">> file path: #{f.file_ref.hierarchy_path}-- #{f.file_ref.real_path}"
file_ref.name = f.file_ref.namefile_ref.path = f.file_ref.pathfile_ref.source_tree = f.file_ref.source_treefile_ref.last_known_file_type = f.file_ref.last_known_file_type# file_ref.fileEncoding = f.file_ref.fileEncoding
      beginfile_ref.move(f.file_ref.parent)rescueendendbuild_file = proj.new(Xcodeproj::Project::Object::PBXBuildFile)build_file.file_ref = f.file_ref
# 文件属性配置,如no-arc   if f.settingsbuild_file.settings = f.settingsenddst.files << build_fileend
end#设置目标target文件组
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")# 添加资源文件引用,注意和代码文件引用方式不同
target.add_resources([resourceGroup.new_reference("areaCode.plist"),resourceGroup.new_reference("login_toon_bg@2x.png"),resourceGroup.new_reference("login_toon_bg@3x.png"),resourceGroup.new_reference("tab_item_home_highlight@2x.png"),resourceGroup.new_reference("tab_item_home_highlight@3x.png"),resourceGroup.new_reference("tab_item_home_normal@2x.png"),resourceGroup.new_reference("tab_item_home_normal@3x.png"),resourceGroup.new_reference("Toon_logo@2x.png"),resourceGroup.new_reference("Toon_logo@3x.png"),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
# 添加代码文件组
code1 = targetGroup.new_group("NetWork", "./NetWork")
code2 = targetGroup.new_group("TabbarSetDataSource", "./TabbarSetDataSource")
code3 = targetGroup.new_group("TNHQHome", "./TNHQHome")# 添加代码文件引用
    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# 修改文件通用内容infoplistfile = "#{targetdir}/Resources/Supporting Files/Info.plist"files = ["#{targetdir}/Resources/areaCode.plist","#{targetdir}/Resources/toon_serviceProtocol.html","#{targetdir}/Resources/user_protocol.html","#{targetdir}/Resources/NewFunction.html",infoplistfile,"#{targetdir}/Resources/Supporting Files/InfoPlist.strings","#{targetdir}/Resources/Supporting Files/Localizable.strings"]if hasAllListFilesfiles << "#{targetdir}/TabbarSetDataSource/TNTabSettingDataSource.m"end
files.each do |f1|File.open(f1) do |fr|buffer = fr.read.gsub(srcdisplayname, displayname)buffer= buffer.gsub("项目名", displayname)buffer= buffer.gsub("大同", displayname)File.open(f1, "w") { |fw| fw.write(buffer) }end
end# 修改info.plistFile.open(infoplistfile) do |fr|if hasAllListFilesputs "*************************** 1"buffer = fr.read.gsub("<string>10024</string>", "<string>#{target_pushType}</string>")buffer= buffer.gsub("<integer>124</integer>", "<integer>#{target_toonType}</integer>")buffer= buffer.gsub("<string>1241002</string>", "<string>#{target_channel}</string>")buffer= buffer.gsub("<string>8058bda8c0ad5a7cfb8742cfbac4ecb8</string>", "<string>#{target_mapKey}</string>")buffer= buffer.gsub("<string>toon124</string>", "<string>#{target_schemeType}</string>")elseputs "*************************** 2"buffer = fr.read.gsub("<string>10016</string>", "<string>#{target_pushType}</string>")buffer= buffer.gsub("<integer>116</integer>", "<integer>#{target_toonType}</integer>")buffer= buffer.gsub("<string>10035</string>", "<string>#{target_channel}</string>")buffer= buffer.gsub("<string>e851d7df83d59f143bff1ad5a3a8e554</string>", "<string>#{target_mapKey}</string>")buffer= buffer.gsub("<string>toon116</string>", "<string>#{target_schemeType}</string>")endputs "*************************** updating InfoPlist"File.open(infoplistfile, "w") { |fw| fw.write(buffer) }end
proj.save# 修改Podfile
puts ">> prepare loading pods ..."
podTarget = "target '#{name}' do shared_pods  end"
File.open("Podfile") do |file|if file.read().index(podTarget) ==nilFile.open(infoplistfile, "w") { |fw| fw.puts podTarget }puts ">> add pod item"elseputs ">> pod has been added"endend# file.close# 更新pod依赖
exec 'pod install'

转载于:https://www.cnblogs.com/v-jing/p/8004695.html

iOS 使用脚本自动化复制target相关推荐

  1. iOS逆向之自动化重签名

    iOS逆向之自动化重签名 准备工作 非越狱的iPhone手机 用PP助手下载: 微信6.6.5(越狱应用) 步骤 新建工程"自动化签名",在工程目录下新建APP文件夹放置需要重签名 ...

  2. shell脚本自动化部署服务

    shell脚本自动化部署 !/bin/bash#export PATH=$PATH:/export/maven/binrun_flag_dir="/data0/shell/deploy_wo ...

  3. docker脚本自动化安装

    docker脚本自动化安装 1.安装docker和docker-compose installdocker.sh shell脚本安装docker和docker-compose install-dock ...

  4. linux 运维高级脚本生成器,Linux运维系列,Shell高级脚本自动化编程实战

    课程文件目录: Linux自动化运维系列 Shell高级脚本自动化编程实战 [6.1G] ┣━━01.Shell基础概述 [315.1M] ┃ ┣━━1-1 Shell脚本体系概述.mp4 [154. ...

  5. python脚本自动化盲注_三、基于报错型注入和sql盲注的自动化实现

    通过前面payload的构造,不难发现,对于报错型注入和布尔注入(sql盲注)纯手工注入的效率是非常慢的.这些payload语句虽然复杂,但大部分内容都是相同的,因此,一言不合就写了个脚本自动化注入, ...

  6. PowerDesigner运行自定义VBS脚本,复制Name到Comment

    1.说明 PowerDesigner支持自定义一些命令与操作, 通过编写VBS(Visual Basic Script)脚本, 可以扩展出更多的功能. 下面开发一个自定义的VBS脚本, 实现复制Nam ...

  7. Linux一键脚本自动化安装项目环境

    当你面对一个全新的Linux系统时,是如何部署搭建项目环境呢?是否是一个一个软件安装呢?小编在往期文章中介绍了相关软件的安装方法,但是你是否发现不同的软件安装下来是否会出现问题呢?今天就教大家如何使用 ...

  8. Windows系统共享文件夹或打印机等设备的dos脚本自动化

    目录 目录 Windows系统共享文件夹或打印机等设备的dos脚本自动化 一.概述 步骤: 执行的结果: 二.脚本实作 2.1.激活Windows的Administrator账户: 2.2.设置Win ...

  9. IOS在Windows自动化测试之tidevice

    前提安装了一下工具: 1.Windows上配置了Python环境:Python 3.6+ 2.Windows上安装了iTunes IOS在Windows自动化测试之tidevice tidevice地 ...

  10. 通过shell脚本自动化量产SD启动卡

    通过shell脚本自动化量产SD启动卡 首先感谢米联客提供的高质量的脚本文件,我这里根据他的脚本文件稍作修改,使用更加便捷,量产SD卡,使用脚本操作,方便快捷.是针对大批量定制SD卡的一种自动化操作. ...

最新文章

  1. 怎么用deveco studio升级鸿蒙,华为鸿蒙DevEco studio2.0的安装和hello world运行教程
  2. java 整数变负数_年年有余之java求余的小技巧
  3. https://gogs.io/
  4. CentOS 8下 MySQL 8.0 安装部署(亲测)
  5. ThreadPool执行异步操作
  6. UltraEdit 21 for Mac(超好用的高级文本编辑器)
  7. 2018关于认证第三方IATF 16949:2016审核完成不符合事项分析
  8. Mac苹果电脑桌面上的文件突然没了怎么办
  9. ssl证书 嵌入式设备_ngx_http_ssl_module
  10. 京东科技风格 NutUI 发布了
  11. SCI-HUB的前世今生以及其他下载论文文献的方法
  12. English Learning NetSource
  13. 可由线性表示且表达式唯一_一个向量能由另一个向量组线性表示,且表示式唯一的等价条件是什么?...
  14. JUC编程java多线程并发详细总结
  15. JAVA练习174-递归乘法
  16. 科研快报 | 三代测序技术-海水微生物态,助力海水微生态及微生物基因组研究
  17. Andriod Studio 下载安装详细教程
  18. 恶搞谷歌翻译,伤不起!
  19. iOS-使用UIControl封装@上下文控件
  20. RIME中州韵输入法如何实现中英文翻译功能

热门文章

  1. 计算机网络工程税率多少,弱电工程增值税6%、9%、13%税率怎样选择?
  2. 移动端ajax,移动端ajax请求问题?
  3. 力扣题目系列:1313. 解压缩编码列表
  4. python中的递归函数如何表示_Python递归函数如何写?正确的Python递归函数用法!...
  5. React Native vs. Cordova.
  6. spring boot入门之——2.0新特性以及模块化构建
  7. 【DataBase】【sqlite3】【第一天】
  8. ogre 1.9SDK阅读笔记
  9. CentOS 6.5下安装MySQL后重置root密码方法
  10. HDU 3996 Gold Mine【最大闭合权图】