PostProcessBuildでRubyを使う〜iOS用〜


[Xcodeproj](https://github.com/CocoaPods/Xcodeproj)を使用します。
特にUnity限定というわけでもないので、Unity以外でも使用できます。

もちろん`UnityEditor.iOS.Xcode`でも同様のことはできるかと思います。

## 環境
* Unity 5.5.1f1
* Mac (10.12.5)
* xcodeproj (1.4.2)

# QuickStartのUnityでの読み替え+α
[PostProcessBuildでRubyを使う](http://qiita.com/rinsyan0518/items/61bb100af20c44d76d8f)で実行されている想定で、Rubyのソースの先頭で以下が定義されている前提です。
適宜読み替えていただければと思います。

``` ruby
require 'xcodeproj'

output_path = ARGV[0]
target = ARGV[1].downcase
is_development = ARGV[2].downcase == 'true'
product_name = ARGV[3]
```

* ここでは特に記述しないですが、Unityでビルド時にreplaceしない限り同じ内容（Build Phaseの追加など）を追記してしまう可能性があるため、追加する前にチェックする必要があります。

## プロジェクトの読み込みから保存
以下で定義された変数`projcect`は以降でも使用されます。

### *.xcodeprojファイル

``` ruby
# 読み込み
project_path = '#{output_path}/Unity-iPhone.xcodeproj'
project = Xcodeproj::Project.open(project_path)

# 保存（この場合上書きされます）
project.save(project_path)
```

### *.plist
``` ruby
# 読み込み
info_plist_path = "#{output_path}/Info.plist"
info_plist = Xcodeproj::Plist.read_from_path(info_plist_path)

# 保存（この場合上書きされます）
Xcodeproj::Plist.write_to_path(info_plist, info_plist_path)
```

## 各ターゲットの読み込み
``` ruby
project.targets.each do |target|
  puts target.name
end
```

以下が出力されるかと思います。

```
Unity-iPhone
Unity-iPhone Test
```

#### 参考
* [AbstractTargetのReference](http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj/Project/Object/AbstractTarget)
* [PBXNativeTargetのReference](http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj/Project/Object/PBXNativeTarget)


## BuildPhaseの追加

### Shell Script Build Phaseの追加

``` ruby
project.targets.each do |target|
  # BuildPhaseの作成
  phase = project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
  phase.name = 'phaseの名前'
  phase.shell_script = 'echo シェルスクリプトを書く'

  # 末尾に追加
  target.build_phases << phase
end
```

### Copy Files Build Phaseの追加

以下の例はframeworkファイルの参照をコピーします
`symbol_dst_subfolder_spec`には`Constants::COPY_FILES_BUILD_PHASE_DESTINATIONS`に含まれているものであれば指定することができます。

``` ruby
project.targets.each do |target|
  # BuildPhaseの作成
  phase = project.new(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase)
  phase.name = 'phaseの名前'
  phase.symbol_dst_subfolder_spec = :frameworks

  # ファイルのリファレンス情報を作成
  framework_ref = project.new(Xcodeproj::Project::Object::PBXFileReference)
  framework_ref.name = 'hogehoge.framework'
  # 例：Frameworks/Plugins/iOS/hogehoge.framework
  framework_ref.path = '/path/to/hogehoge.framework'

  build_file = phase.add_file_reference(framework_ref, true)

  # Code Sign On Copyにチェックを入れたい場合
  # build_file.settings = {
  #   'ATTRIBUTES' => [
  #     'CodeSignOnCopy',
  #     'RemoveHeaderOnCopy'
  #   ]
  # }

  # 末尾に追加
  target.build_phases << phase
end
```

### その他
`target.build_phases`はArrayを継承した[ObjectList](http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj/Project/ObjectList)を返却するため、新しいBuild Phaseの存在チェックや指定の箇所への挿入ができます。

#### CopyFilesの名前を持ったBuildPhaseが存在するか
``` ruby
target.build_phases.any? do |phase|
  phase.name == 'CopyFiles'
end
```

`name`を持っていない場合があるためチェックがあったほうが良い。

``` ruby
target.build_phases.any? do |phase|
 phase.respond_to?(:name) && phase.name == 'CopyFiles'
end
```

#### CopyFilesの名前を持ったBuildPhase後に挿入

``` ruby
index = target.build_phases.rindex {|p|
 p.display_name == 'CopyFiles'
}
if index.nil?
 target.build_phases << phase
else
 target.build_phases.insert(index + 1, phase)
end
```

#### 参考
* [PBXCopyFilesBuildPhaseのReference](http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj/Project/Object/PBXCopyFilesBuildPhase)
* [Constants::COPY_FILES_BUILD_PHASE_DESTINATIONSのソース](https://github.com/CocoaPods/Xcodeproj/blob/master/lib/xcodeproj/constants.rb#L363)


# おわり
Xcodeprojの使い方がわからなくて、リファレンス、spec、コードを読みつつ書いています。
あまりRubyが得意というわけでもないので、Rubyっぽくないなどで他に良い書き方があればご教授いただけるとうれしいです。