XcodeGenの導入+Carthage+CocoaPods

# はじめに
多くのアプリ開発者はプロジェクトにファイルの追加、ファイルのリネーム、ファイルの移動などをよくすると思います。さらにそのプロジェクトをチームでGitを用いて開発すると思います。ただしXcodeの仕組み上、ファイルのリネームや移動等で`*.xcodeproj`の内容が変更されるのでGit管理でコンフリクトが頻繁に起きてしまう問題を抱えています。 
コンフリクト解決に時間を取られてしまうので、チーム全体の開発スピードを鈍足にしてしまいます。 
 本記事では、上記の問題を解決するXcodeGenの導入方法とCarthage・CocoaPodsとの連携について説明します。

# ファイル構造
説明にあたり以下のようなファイル構造となっています。

```txt
.
├── .git
├── .gitignore
├── .swiftformat
├── .swiftlint.yml
├── Cartfile
├── Cartfile.resolved
├── Carthage
├── Extensions.framework
├── Modules
├── Podfile
├── Podfile.lock
├── Pods
├── SampleApp
├── SampleAppUITests
├── SampleProject.xcodeproj
├── SampleProject.xcworkspace
└── project.yml
```

# XcodeGenとは
https://github.com/yonaskolb/XcodeGen
XcodeGenはXcodeのプロジェクトの設定を`*.yaml`で定義して`*.xcodeproj`を生成するツールです。
なのでGitで*.xcodeproj`を管理せずに*.yaml`を使うことでXcode原因のコンフリクトを回避することができます。  

YAMLの定義例

```yaml:project.yml
name: SampleProject
options:
  bundleIdPrefix: com.messyu.sampleproject
targets:
  SampleApp:
    type: application
    platform: iOS
    deploymentTarget: "12.0"
    sources: 
      - path: SampleApp
    settings:
      configs:
        debug:
          CUSTOM_BUILD_SETTING: my_debug_value
        release:
          CUSTOM_BUILD_SETTING: my_release_value
      SWIFT_VERSION: 5.0
    dependencies:
      - target: TodoList
      - target: TodoDetail
      - carthage: RxSwift　# carthageで生成したフレームワークを利用
      - framework: Extensions.framework # 自作したフレームワーク

  TodoList:
    type: framework
    platform: iOS
    deploymentTarget: 12.0
    sources:
      - path: Modules/TodoList
        buildPhase: none
    settings:
      PRODUCT_BUNDLE_IDENTIFIER: com.messyu.todolist
      INFOPLIST_FILE: Modules/TodoList/Info.plist
      SWIFT_VERSION: 5.0
    dependencies:
      - carthage: RxSwift

  TodoDetail:
    type: framework
    platform: iOS
    deploymentTarget: 12.0
    sources:
      - path: Modules/TodoDetail
        buildPhase: none
    settings:
      PRODUCT_BUNDLE_IDENTIFIER: com.messyu.tododetail
      INFOPLIST_FILE: Modules/TodoDetail/Info.plist
      SWIFT_VERSION: 5.0
    dependencies:
      - carthage: RxSwift
  
```
# Carthageとの連携
XcodeGenはCarthageで生成したフレームワークを利用できるように設定することができます。

Carthageで生成したいフレームワークを記述します。

```txt:Cartfile
github "ReactiveX/RxSwift" ~> 5.0
```

Cartfileをもとにcarthageコマンドでフレームワークを生成します。
フレームワークは`Carthage -> Build -> iOS`ディレクトリに生成されるので、確認することができます。

```bash
$ carthage update --platform iOS --no-use-binaries
```

では実際にXcodeGenコマンドで`*.xcodeproj`を生成しましょう。

```bash
$  xcodegen
```


# CocoaPodsとの連携
 XcodeGenで`*.xcodeproj`生成できたら、CocoaPodsと連携させましょう。

Podfileの定義例

```:Podfile
# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'

def install_swiftformat
  pod 'SwiftFormat/CLI'
  # ビルドするたびにSwiftFormatを実行させる
  script_phase :name => 'Run SwiftFormat',
               :script => 'if which "${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat" >/dev/null; then
  "${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat" . --self insert
else
  echo "warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat"
fi'
end

def install_swiftlint
  pod 'SwiftLint'
　# ビルドするたびにSwiftLintを実行させる
  script_phase :name => 'Run SwiftLint',
              :script => 'if which "${PODS_ROOT}/SwiftLint/swiftlint" >/dev/null; then
  "${PODS_ROOT}/SwiftLint/swiftlint" autocorrect
  "${PODS_ROOT}/SwiftLint/swiftlint"
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi'
end

target 'SampleApp' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  
  # Pods for SampleApp
  install_swiftformat
  install_swiftlint
end

target 'TodoList' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  
  # Pods for SampleApp
  install_swiftformat
  install_swiftlint
end

target 'TodoDetail' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  
  # Pods for SampleApp
  install_swiftformat
  install_swiftlint
end
```

#gitignoreの設定
　`*.xcodeproj`が管理されないように`.gitignore `に設定を記述します。
また、Carthageで作成したフレームワークとCocoaPodsの`Podfile.lock`は不必要なので管理対象から除外します。

```:.gitignore
### Carthage ###
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
Carthage/
Cartfile.resolved

# CocoaPods - Only use to conserve bandwidth / Save time on Pushing
#           - Also handy if you have a large number of dependant pods
#           - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
Pods/
Podfile.lock

### Xcode ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Xcode Patch
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcworkspace/contents.xcworkspacedata
/*.gcno
### Xcode Patch ###
**/xcshareddata/WorkspaceSettings.xcsettings

### macOS ###
# General
.DS_Store
```

# 参考資料
- https://github.com/yonaskolb/XcodeGen
- https://qiita.com/yutat93/items/97fe9bc2bf2e97da7ec1
- https://github.com/Carthage/Carthage
- https://qiita.com/gin0606/items/64855bb96570d875f231
- https://tech-blog.sgr-ksmt.org/2016/03/24/carthage_xcode_7_3/
- http://gitignore.io/