XcodeGenでフォルダ参照した時の罠

XcodeGenでは指定しなければ基本、ディレクトリはすべて自動でグループとして扱われる。
そのためフォルダ参照したい場合は、フォルダ参照するパスのタイプを指定する必要がある。
ここまでは公式仕様にも書かれているのでわかる。
が、さらに罠があったので共有したい。

わかりやすいように以下にサンプルプロジェクトを配置したので、これを使って説明していきたい。
https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen

* Xcode13.1
* XcodeGen2.25.0


# グループとして参照
`targets:` `sources:` で指定した `path`以下のディレクトリ群はグループとして扱われるため

```yml
targets:
  FolderReferencesWithXcodeGen:
    type: application
    platform: iOS
    sources:
      - path: FolderReferencesWithXcodeGen
        excludes:
          - Info.plist
```

こうなるのがデフォルト仕様。

![1_base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/69c75f9c-c85b-734e-8fa9-03b5c96707a6.png)

しかし、最終的には.appのリソースの中でImagesフォルダを持ちたいとすると、このままだとNG。

# フォルダ参照
`targets:` `sources:` で指定したパスの `type:` を `folder` で指定する必要がある。
[公式仕様](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md#sources)にも明記されている。

```yml
targets:
  FolderReferencesWithXcodeGen:
    type: application
    platform: iOS
    sources:
      - path: FolderReferencesWithXcodeGen
        excludes:
          - Info.plist
      - path: FolderReferencesWithXcodeGen/Images # <-New
        type: folder # <-New
```

これで一見よさそうだが、何故か**グループとしても**扱われてしまい、ProjectでもBuild Phase のCopy Bundle Resourcesでもフォルダ参照とグループ参照としての内部ファイル群の両方が追加される形となってしまう。。なんでやねん

|Project|Build Phase のCopy Bundle Resources|
|:---:|:---:|
|![2_folderref_only_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/a240efe6-cada-4ab0-b595-46e2c73b9abe.png)|![2_folderref_only_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/3dda1a5d-6cd4-263b-ef61-642d040ac4c4.png)|

# フォルダ参照 ＋ グループ参照を省く

`targets:` `sources:` で指定した `path`で Images以下がグループ参照されてしまわないようにしたいので `excludes` の指定にImagesを追加する。

[https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen/blob/23f9c1a7a4145f156040661bbde9df08f0308e4d/project.yml#L18-L28](https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen/blob/23f9c1a7a4145f156040661bbde9df08f0308e4d/project.yml#L18-L28)

```yml
targets:
  FolderReferencesWithXcodeGen:
    type: application
    platform: iOS
    sources:
      - path: FolderReferencesWithXcodeGen
        excludes:
          - Info.plist
          - Images # <-New
      - path: FolderReferencesWithXcodeGen/Images
        type: folder
```

|Project|Build Phase のCopy Bundle Resources|
|:---:|:---:|
|![3_folderref_with_excludes_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/9da36823-ffe5-6cdd-faaa-68cbbe5fb695.png)|![3_folderref_with_excludes_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156085/5a2a4fcc-a35b-d446-4266-c42e66a3a51e.png)|

これでグループ参照の重複が解消され、最終的に.appのリソースにはImagesフォルダ以下が入ることになる。

# 確認

アプリ起動時に.appのリソース内/Images/tree.jpgがあるか確かめる。

[https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen/blob/23f9c1a7a4145f156040661bbde9df08f0308e4d/FolderReferencesWithXcodeGen/AppDelegate.swift#L15-L17](https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen/blob/23f9c1a7a4145f156040661bbde9df08f0308e4d/FolderReferencesWithXcodeGen/AppDelegate.swift#L15-L17)

```Swift
        if let fileURL = Bundle.main.resourceURL?.appendingPathComponent("Images").appendingPathComponent("tree.jpg") {
            print("filePath exists: \(FileManager.default.fileExists(atPath: fileURL.path))")
        }
```
.appのリソース内/tree.jpgが無いか確かめる。
[https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen/blob/23f9c1a7a4145f156040661bbde9df08f0308e4d/FolderReferencesWithXcodeGen/AppDelegate.swift#L19-L21](https://github.com/yumemi-ajike/FolderReferencesWithXcodeGen/blob/23f9c1a7a4145f156040661bbde9df08f0308e4d/FolderReferencesWithXcodeGen/AppDelegate.swift#L19-L21)

```Swift
        if let fileURL = Bundle.main.resourceURL?.appendingPathComponent("tree.jpg") {
            print("filePath exists: \(FileManager.default.fileExists(atPath: fileURL.path))")
        }
```