iOS uses scripting to automate target replication

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:

ruby doc

xcodeproj related API documentation

github example

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/#{name}"
srcroot = "TNTarget/#{srcname}"

# 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 = [
  "#{srcroot}/Resources",
  "#{srcroot}/NetWork",
  "#{srcroot}/TabbarSetDataSource",
  "#{srcroot}/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 + "#{item.build_settings}" +"_"*30
  item.build_settings["PRODUCT_BUNDLE_IDENTIFIER"] = "com.abc.aa.#{name}"
  item.build_settings["PRODUCT_NAME"] =displayname

  targetInfoPlist = item.build_settings["INFOPLIST_FILE"]
  item.build_settings["INFOPLIST_FILE"] = targetInfoPlist.sub(srcname, name)

  puts "-"*30 + "#{item.build_settings['PRODUCT_BUNDLE_IDENTIFIER']}" +"_"*30
  puts "-"*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)

#Copy Source target Referenced source and resource File Reference
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 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:  #{f.file_ref}, #{f.file_ref.hierarchy_path}...................\n"
        next
    end

    file_ref = proj.new(Xcodeproj::Project::Object::PBXFileReference)
    if f.settings
      puts ">>file.settings:  #{idx} > 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: #{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.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("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
# 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 = "#{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 hasAllListFiles
     files << "#{targetdir}/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>#{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>")
    else
      puts "*************************** 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>")
    end
    puts "*************************** updating InfoPlist"

    File.open(infoplistfile, "w") { |fw| fw.write(buffer) }

  end
proj.save

# modify Podfile
puts ">> prepare loading pods ..."
podTarget = "target '#{name}' 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'

Tags: iOS network Ruby xcode less

Posted on Wed, 01 Jul 2020 12:17:15 -0400 by phpjaco