Xcode Gen を初めて使ってみる

チーム開発を行っているとき、プロジェクトファイルがよくコンフリクトします。

![confrict.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/ccad7ddc-b7ee-842f-dff2-d4f9f3939bd0.png)
その問題を解決する方法があります。

参考：

- [Xcodeプロジェクトの生成ツール「XcodeGen」のセットアップ&操作方法](https://qiita.com/uhooi/items/16a870eaae24b46103fb)
- [既存のプロジェクトを XcodeGen に移行する](https://qiita.com/gin0606/items/64855bb96570d875f231)


本記事は、他の記事を見ながら実際にやってみた、いわゆる備忘録となっています。
「まだ情報は集まってない…」
「とりあえず試したい…」
そんな方には役立てられるかと。

## 目次
Qiita なら必要ないかと思うけど一応

- [Xcode Gen とは](#Xcode-Gen-とは)
- [導入](#導入)
- [yml を作成](#yml-を作成)
- [yml を編集](#yml-を編集)
- [xcodeproj ファイル生成](#xcodeproj-ファイル生成)
- [バージョン管理から外しておく](#バージョン管理から外しておく)
- [ということでね](#ということでね)

## Xcode Gen とは
そもそもの話、なぜ **[Xcode Gen](https://github.com/yonaskolb/XcodeGen)** を使うのか。

それは、プロジェクトファイルである `*.xcodeproj` が毎度 conflict するので、それを未然に防ぎたいという考えです。

![yml1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/1a1391d4-e626-67b6-df01-aa6a1081205b.jpeg)

なぜ conflict するかというと、`*.xcodeproj`  内にあるファイルのアドレスが原因です。
あるブランチでは、ファイルを追加する。
別のブランチでも、ファイルを追加する。
このとき、`*.xcodeproj` ではコードとしても変更があるのですが…
…何と、同じところにファイルに関するコードが増えています。
これが原因です。

**じゃあどうすればいいのか。**
`*.xcodeproj` に変わる、プロジェクトの概要を管理するファイル…
`project.yml` （ヤムル）を使ってバージョン管理をすればいいのです。
![yml2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/fa7780b3-13e9-01c2-6649-b82f3d8f6507.jpeg)

`project.yml` は、ファイル・フォルダ構造を管理しません。
そのため当然、conflict地獄 は発生しない。


そして、**Xcode Gen** で `project.yml` を使えば、
いつでも`*.xcodeproj` を生成・更新することができます。

## 導入
![terminal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/eac34388-fc78-ce3b-6e9b-1ef863194ab2.png)
まずは Xcode gen を**ターミナル**でインストールする。
インストールする方法は、３種類ある模様。

- **Homebrew によるインストール方法**
- **Mint を使ったインストール方法**
- **手動でインストール**

### Homebrew によるインストール方法

~~~bash
brew install xcodegen
~~~

パッケージ管理の Homebrew をインストールしておく必要あり。
どのみち Homebrew は必要になるので、やってない方はこの際使ってみるといいでしょう。調べてみてね。

### [Mint](https://github.com/yonaskolb/mint) を使ったインストール方法

~~~bash
mint install yonaskolb/xcodegen
~~~
これに関しては記事冒頭の参考記事を見たほうがいいかと思います。
Mintについても調べてみてね。こっちのほうがいいかも。

### 手動でインストール

~~~
git clone https://github.com/yonaskolb/XcodeGen.git
cd XcodeGen
make install
~~~
手動による方法は、バージョン管理的にオススメはしない。

## yml を作成

まずは、**ターミナル**でプロジェクトのフォルダまで遷移して、このymlファイルを作る。

本記事では、使用するプロジェクト名は「Imager」とします。~~（作りかけ…？いえ、そんなことはないです。）~~

~~~bash
cd Imager
touch project.yml
~~~



![ymlfile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/35a1ac2f-ac7a-9951-64be-fcac80b36b5e.png)

なんかできてます。
これが ymlファイルですね。


## yml を編集
`*.xcodeproj`  を管理しない代わりに、必要な設定を`project.yml` で管理する必要があります。
ymlファイルに書き込むべき大まかな項目は、以下の通り。
本記事では **<font color="Red">必須</font>** 項目のみ説明します。
初期状態であれば、必須項目だけでもしっかりビルドできます。~~ﾃﾞｷﾅｶｯﾀﾗｺﾞﾒﾝﾈ~~



- [name](name) **<font color="Red">必須</font>**
- attributes
- [options](#options) **<font color="Red">必須</font>**
- configs
- schemes
- [settings](#settings) **<font color="Red">必須</font>**
- settingGroups
- packages
- [targets](#targets) **<font color="Red">必須</font>**



※本記事では、使用するプロジェクト名は「Imager」とします。



### name

~~~YAML:project.yml
name: Imager
~~~
**・`naem`** **<font color="Red">必須</font>**
プロジェクト名を書くだけです。
ここは簡単ですね。

### options
プロジェクトそのもののオプション。

~~~YAML:project.yml
options:
    bundleIdPrefix: com.imager
    deploymentTarget:
        iOS: 14.1
    developmentLanguage: ja
    postGenCommand: pod install
~~~
**・`bundleIdPrefix`** **<font color="Red">必須</font>**
各ターゲットに共通の **bundleId** を設定する。
ここに入力しておくと、下記にある **targets** で `PRODUCT_BUNDLE_IDENTIFIER` を記述する必要がなくなる模様。

**・`deploymentTarget`** **<font color="Red">必須</font>**
開発するプラットフォームのバージョンを指定する。
iOSアプリ開発であれば、iOSのバージョンだけ書けばおk。

**・`developmentLanguage`**
デフォルトの Language を設定できる。
この項目を記入しなかった場合は、`en` になる。

**・`postGenCommand`**
**CocoaPods** を使用している場合は、この項目に `pod install`  と記入しておくと便利。
これだけで、`$ xcodegen generate` した際に ``pod install``  までしてくれる。

### settings

各ターゲット共通で使う **Build Settings** 用のパラメータ設定。

~~~YAML:project.yml
settings:
    base:
        MARKETING_VERSION: 1.0.0
        CURRENT_PROJECT_VERSION: 1
        DEVELOPMENT_TEAM: XXXXXXXXXX
~~~
**・`MARKETING_VERSION`**
**General** にある、 **Version** 管理用パラメータ。
リリース時のバージョンを指定するアレですね。Ver1.0.0みたいな。
初期設定では紐付けされていないので、`Info.plist` にて紐付けしておきましょう。

`Bundle version string (short): $(MARKETING_VERSION)`

**・`CURRENT_PROJECT_VERSION`**
**General** にある、 **Build** 管理用パラメータ。
ビルド時のバージョン管理用。開発者側にしか見えない。
初期設定では紐付けされていないので、`Info.plist` にて紐付けしておきましょう。

`Bundle version : $(CURRENT_PROJECT_VERSION)`

**・`DEVELOPMENT_TEAM`** **<font color="Red">必須</font>**
**Signing & Capabilities** にある、開発チームのID。
元々使用されているパラメータですね。

Xcode内ではわからないかと思うので、`*.xcodeproj` を「パッケージの内容を表示」で開くと見える、 `project.pbxproj` の中身を見てみましょう。同名のパラメータがあります。

### targets
初期に存在する３ターゲットですね。
**ターゲット毎**に設定してあげる必要があります。

~~~YAML:project.yml
targets:
    Imager:
        type: application
        platform: iOS
        sources: Imager
        settings:
            base:
                INFOPLIST_FILE: Imager/Info.plist
    
    ImagerTests:
        type: bundle.unit-test
        platform: iOS
        sources: ImagerTests
        settings:
            base:
                INFOPLIST_FILE: ImagerTests/Info.plist
        dependencies:
            - target: Imager

    ImagerUITests:
        type: bundle.ui-testing
        platform: iOS
        sources: ImagerUITests
        settings:
            base:
                INFOPLIST_FILE: ImagerUITests/Info.plist
        dependencies:
            - target: Imager
~~~

**・`type`** **<font color="Red">必須</font>**
ターゲットのタイプ
上のコードを見た方が、早そうですね。

**・`platform`** **<font color="Red">必須</font>**
対応プラットフォーム
iOSアプリ開発なら、`iOS` とだけ。

**・`sources`** **<font color="Red">必須</font>**
ソースフォルダ名
これがないと、フォルダ内の構成が反映されません。

フォルダ構成は、どうやらここで参照したフォルダの中身を元に作られるみたいですね。
`*.xcodeproj` と違って、独自のファイルツリーが存在しない。
だからコンフリクトもしない。便利ですね。

**・`INFOPLIST_FILE`**
`Info.plist` のファイルパス。無くてもデフォルトの値が入る。

**・`target`**
**Testing** の **Host Application** を設定する、テスト用の項目。
テストを使うなら必須。

参考：

- [XcodeGen Example  //github](https://gist.github.com/d-date/44510c5b4b3baf820033453bfeb235c3)
- [Xcodegenのサンプル  //qiita](https://qiita.com/powerispower/items/c8ba8e3cb791d4c621c6)
- [XcodeGenで最低限のXcodeプロジェクトを生成する](https://blog.mothule.com/ios/xcodegen/ios-xcodegen-basic-usage)
- [公式ドキュメント](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md#general)

## xcodeproj ファイル生成
`project.yml` がある程度完成したら、
**ターミナル**で、ルートディレクトリまで遷移して以下のコマンドを打つ。

~~~bash
xcodegen generate
~~~
これで、`*.xcodeproj` が生成されます。
ちなみに、**CocoaPods** を使用している場合は、`project.yml` に以下の記入を忘れずに。
ジェネレート時にまとめて `pod install`  も行ってくれる。

~~~bash
options:
    postGenCommand: pod install
~~~

> $ xcodegen generate
> ⚙️ Generating plists...
> ⚙️ Generating project...
> ⚙️ Writing project...
> Created project at /Users/XXXXX/XXXXX/Imager/Imager.xcodeproj
> Analyzing dependencies
> Downloading dependencies
> ...

`Created project` の後は、全てpod側の処理ですね。
![yml2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/fa7780b3-13e9-01c2-6649-b82f3d8f6507.jpeg)
しっかり `*.xcodeproj` （pod 有りなら `*.xcworkspace` も含めて）が生成されていれば、大丈夫です。
ビルドも正常にできるかと。

## バージョン管理から外しておく
こうなってしまえば、`*.xcodeproj` と `*.xcworkspace` は使い捨てでいいので、管理する必要ありませんね。
`.gitignore` に登録して、git のバージョン管理から外しましょう。

ちなみに `.gitignore` ファイルの生成は、**ターミナル**で打つだけ。

~~~bash
cd Imager
touch .gitignore
~~~

![gitignone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139353/719416e8-74c3-196a-b3f1-bb36f319ef66.png)

`.gitignore` は隠しファイルです。
通常では見えません。
Finder では、**"command" + "shift" + "."** とコマンド入力すれば、見えるようになります。

終わったらもう一度コマンド入力して、元に戻しましょう。
後は適当に書いておきましょう。
Pods もぶちこめ。

~~~:.gitignore
Pods
*.xcodeproj
*.xcworkspace
~~~

## ということでね
必要に応じて、追加の設定を加えて行こうかなぁと考えています。
ライブラリに関しても、 **CocoaPods** しか仮定していないので…
リリース用ならもっと必要項目が…

とりあえず、入門編としての記事は以上ということでね。

細かい詳細に関する記事は、そのうちに…ね。
何か至らぬ点がありましたら、コメントをいただけると幸いです。