iOS 使用脚本自动化复制target
有些项目成熟以后,就会有需求自动化配置生成一个全新的项目,不需要再让开发人员手动修改工程文件,将配置化工作直接移交给运维或者配置团队去做
其实按照普通的做法,无非就是在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相关推荐
- iOS逆向之自动化重签名
iOS逆向之自动化重签名 准备工作 非越狱的iPhone手机 用PP助手下载: 微信6.6.5(越狱应用) 步骤 新建工程"自动化签名",在工程目录下新建APP文件夹放置需要重签名 ...
- shell脚本自动化部署服务
shell脚本自动化部署 !/bin/bash#export PATH=$PATH:/export/maven/binrun_flag_dir="/data0/shell/deploy_wo ...
- docker脚本自动化安装
docker脚本自动化安装 1.安装docker和docker-compose installdocker.sh shell脚本安装docker和docker-compose install-dock ...
- linux 运维高级脚本生成器,Linux运维系列,Shell高级脚本自动化编程实战
课程文件目录: Linux自动化运维系列 Shell高级脚本自动化编程实战 [6.1G] ┣━━01.Shell基础概述 [315.1M] ┃ ┣━━1-1 Shell脚本体系概述.mp4 [154. ...
- python脚本自动化盲注_三、基于报错型注入和sql盲注的自动化实现
通过前面payload的构造,不难发现,对于报错型注入和布尔注入(sql盲注)纯手工注入的效率是非常慢的.这些payload语句虽然复杂,但大部分内容都是相同的,因此,一言不合就写了个脚本自动化注入, ...
- PowerDesigner运行自定义VBS脚本,复制Name到Comment
1.说明 PowerDesigner支持自定义一些命令与操作, 通过编写VBS(Visual Basic Script)脚本, 可以扩展出更多的功能. 下面开发一个自定义的VBS脚本, 实现复制Nam ...
- Linux一键脚本自动化安装项目环境
当你面对一个全新的Linux系统时,是如何部署搭建项目环境呢?是否是一个一个软件安装呢?小编在往期文章中介绍了相关软件的安装方法,但是你是否发现不同的软件安装下来是否会出现问题呢?今天就教大家如何使用 ...
- Windows系统共享文件夹或打印机等设备的dos脚本自动化
目录 目录 Windows系统共享文件夹或打印机等设备的dos脚本自动化 一.概述 步骤: 执行的结果: 二.脚本实作 2.1.激活Windows的Administrator账户: 2.2.设置Win ...
- IOS在Windows自动化测试之tidevice
前提安装了一下工具: 1.Windows上配置了Python环境:Python 3.6+ 2.Windows上安装了iTunes IOS在Windows自动化测试之tidevice tidevice地 ...
- 通过shell脚本自动化量产SD启动卡
通过shell脚本自动化量产SD启动卡 首先感谢米联客提供的高质量的脚本文件,我这里根据他的脚本文件稍作修改,使用更加便捷,量产SD卡,使用脚本操作,方便快捷.是针对大批量定制SD卡的一种自动化操作. ...
最新文章
- 怎么用deveco studio升级鸿蒙,华为鸿蒙DevEco studio2.0的安装和hello world运行教程
- java 整数变负数_年年有余之java求余的小技巧
- https://gogs.io/
- CentOS 8下 MySQL 8.0 安装部署(亲测)
- ThreadPool执行异步操作
- UltraEdit 21 for Mac(超好用的高级文本编辑器)
- 2018关于认证第三方IATF 16949:2016审核完成不符合事项分析
- Mac苹果电脑桌面上的文件突然没了怎么办
- ssl证书 嵌入式设备_ngx_http_ssl_module
- 京东科技风格 NutUI 发布了
- SCI-HUB的前世今生以及其他下载论文文献的方法
- English Learning NetSource
- 可由线性表示且表达式唯一_一个向量能由另一个向量组线性表示,且表示式唯一的等价条件是什么?...
- JUC编程java多线程并发详细总结
- JAVA练习174-递归乘法
- 科研快报 | 三代测序技术-海水微生物态,助力海水微生态及微生物基因组研究
- Andriod Studio 下载安装详细教程
- 恶搞谷歌翻译,伤不起!
- iOS-使用UIControl封装@上下文控件
- RIME中州韵输入法如何实现中英文翻译功能
热门文章
- 计算机网络工程税率多少,弱电工程增值税6%、9%、13%税率怎样选择?
- 移动端ajax,移动端ajax请求问题?
- 力扣题目系列:1313. 解压缩编码列表
- python中的递归函数如何表示_Python递归函数如何写?正确的Python递归函数用法!...
- React Native vs. Cordova.
- spring boot入门之——2.0新特性以及模块化构建
- 【DataBase】【sqlite3】【第一天】
- ogre 1.9SDK阅读笔记
- CentOS 6.5下安装MySQL后重置root密码方法
- HDU 3996 Gold Mine【最大闭合权图】