fragon
fragon

Reputation: 3471

Duplicate iOS application target, rename it, add new icon and build app from command line (without using Xcode GUI)

I would like to automate the process of adding a new target to my iOS application and write a script which would speed up the whole process. Is there any way to duplicate Xcode iOS application target, then rename it, add new icon specific for this target, change bundle id, app name etc. and finally build the app? I've tried using AppleScript to achieve this, but with no luck.

The workaround I am using now is to create one additional target (using Xcode GUI) and customize it during the build time (every time I want to build the app). The biggest downside of this approach is that targets' configurations are not saved anywhere and the parameters of the target have to be specified for every build of the app. This can lead to unrepeatable builds and other undebuggable issues. That's why I am looking for a method or a tool which would allow me to duplicate and configure new target from command line script

Upvotes: 3

Views: 1816

Answers (1)

Michael Maher
Michael Maher

Reputation: 240

You can use this ruby script to duplicate any target, but you need to install github.com/CocoaPods/Xcodeproj first :

#!/usr/bin/env ruby

require 'rubygems'
require 'xcodeproj'

puts "Project path:"
proj_path = gets
puts "New target name:"
name = gets
puts "New target bundle identifer"
bundleIdentifier = gets
puts "Witch target to clone?"
srcTargetName =  gets

name = name.chomp
bundleIdentifier = bundleIdentifier.chomp
proj_path = proj_path.chomp
srcTargetName = srcTargetName.chomp

proj = Xcodeproj::Project.open(proj_path)
src_target = proj.targets.find { |item| item.to_s == srcTargetName }
#proj_path = "/testingTest.xcodeproj"

# create 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(proj_path, name, shared = true)

# copy build_configurations
target.build_configurations.map do |item|
  item.build_settings.update(src_target.build_settings(item.name))
end

target.build_configurations.each do |config|
  config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = bundleIdentifier
  config.build_settings['PRODUCT_NAME'] = "$(TARGET_NAME)"
end

# copy build_phases
phases = src_target.build_phases.reject { |x| x.instance_of? Xcodeproj::Project::Object::PBXShellScriptBuildPhase }.collect(&:class)

phases.each do |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 }

  src.files.each do |f|
    file_ref = proj.new(Xcodeproj::Project::Object::PBXFileReference)
    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

    build_file = proj.new(Xcodeproj::Project::Object::PBXBuildFile)
    build_file.file_ref = f.file_ref
    dst.files << build_file
  end
end

# add files
#classes = proj.main_group.groups.find { |x| x.to_s == 'Group' }.groups.find { |x| x.name == 'Classes' }
#sources = target.build_phases.find { |x| x.instance_of? Xcodeproj::Project::Object::PBXSourcesBuildPhase }
#file_ref = classes.new_file('test.m')
#build_file = proj.new(Xcodeproj::Project::Object::PBXBuildFile)
#build_file.file_ref = file_ref
#sources.files << build_file

proj.save

Upvotes: 5

Related Questions