xcodeprojとは?
xcodeprojはRubyのgemであり、xcodeないの設定などをrubyでいじるために使われる物である。
例をあげるとschemeなどの作成やターゲットの作成、buildsettingやgroupの作成などxcodeに関係する様々な設定を操作可能にします。
使用例
※以下コードはアプリケーションのマスク替えを効率化する事を目的に記述されています。
require 'rubygems'
require 'xcodeproj'
name = 'test_copy'
proj = Xcodeproj::Project.open('test.xcodeproj')
src_target = proj.targets.find { |item| item.to_s == 'test' }
# create target
target = proj.new_target(src_target.symbol_type, name, src_target.platform_name, src_target.deployment_target)
# create scheme
scheme = Xcodeproj::XCScheme.new
scheme.add_build_target(target)
scheme.set_launch_target(target)
scheme.save_as(proj_path, name)
# copy build_configurations
target.build_configurations.map do |item|
item.build_settings.update(src_target.build_settings(item.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
それではまず下記のコードの解説をしていきます。
まずインストールしたgemを使用するために、requireで必要gemの使用を可能にします。
そしてnameにアプリケーション名を代入し、projに各当プロジェクトの名称を代入します。
次にsrc_targetにコピー元のターゲットを代入します。
require 'rubygems'
require 'xcodeproj'
name = 'test_copy'
proj = Xcodeproj::Project.open('test.xcodeproj')
src_target = proj.targets.find { |item| item.to_s == 'test' }
次にターゲットの作成を行います。
まず先ほど定義したsrc_target(コピー元ファイル)のsymbol_type(例 :application,:frameworkなど)を設定し、名前の設定し、platform_nameは:iosか:osxを設定します。devekopment_targetは調べてもよくわからなかったので、nilを指定してあげるとターゲットがbuildされました。
説明が不十分な点ご了承ください。
下記にこのメソッドの公式リファレンスを貼っておきます。
https://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj%2FProject%2FProjectHelper.new_target
# create target
target = proj.new_target(src_target.symbol_type, name, src_target.platform_name, src_target.deployment_target)
次にスチーマのbuildを行います。
設置は下記の通りで、スチーマにadd_build_targetで各当のターゲットを設定します。
set_launch_targetに関しては必要性がわからなかったのですが、なくても問題なくターゲットも設定されたスチーマがbuildされていました。気になる方は検証してみてください。
最後にsave_asメソッドでプロジェクトのパスとスチーマ名を設定し保存で完了です。
# create scheme
scheme = Xcodeproj::XCScheme.new
scheme.add_build_target(target)
scheme.set_launch_target(target)
scheme.save_as(proj_path, name)
次にbuild_phasesのコピーを行います。
まずphasesにsrc_targetのbuild_phases内のrun_script(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)をrejectメソッドで取り除き必要な項目だけを残して代入します。
次にsrcにコピー元のbuild_phasesを見つけ代入します。そしてdstに先ほどbuildしたターゲットのbuild_phasesを見つけ代入します。そしてunless文でdstにない項目を特定し、ないものを加えます。
次に加えられた項目をremove_from_projectで前のプロジェクト情報を取り除きます。
そして次に、各ファイルに新しいプロジェクト情報や名前、パスなどをsrc(元ターゲット)のファイルに設定していきます。
そしてbuild_fileに新しく空のfile_refを作り、そこに先ほど再設定した元ファイルのfile_refを代入します。
最後にこれを新ターゲットのファイルに加えることで、ターゲット情報が変わった新ファイルを生成することができます。
# 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
次は新しいファイルを加えるための処理を行なっていきます。
まず最初にclassesにファイルを作成するグループを代入します。
次に各当ターゲットのbuild_phasesをsourcesに代入します。
そしてfile_refにclassesに新しくファイルを生成し代入し、build.fileにfile_refに代入し、sourcesのファイルの方にも加えて完了です。
# 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
最後に
私自身まだまだ理解が足りていないので、説明が曖昧な箇所多々あると思いますがご了承ください。
さらに理解を深めたい方は下記に参考リンクを載せておくので、ご利用ください。
参考文献
Github
https://github.com/CocoaPods/Xcodeproj
公式リファレンス
https://www.rubydoc.info/gems/xcodeproj/Xcodeproj/Project