Cocoaのライブラリ管理ツール「CocoaPods」のセットアップ&操作方法

## 「CocoaPods」とは？

Cocoa(iOSやmacOSなど)のライブラリ管理ツールです。
Carthageが台頭するまではCocoaPods一択でしたが、今はプロジェクトによってCarthageのみを使ったり、両方を併用して使ったりすることが多いと思います。

Carthageとの主な違いについては[こちら](https://qiita.com/uhooi/items/ba20a604182ef25f6d7a#cocoapodsとの主な違い)に書いています。

## 環境

- OS：macOS Mojave 10.14
- Xcode：10.0 (10A255)
- Swift：4.2
- RubyGems：2.7.1
- CocoaPods：1.5.3

## CocoaPodsのセットアップ

### RubyGemsの更新

まずはRubyGemsを更新します。

```shell-session
$ sudo gem update --system
```

私の環境では以下のエラーが発生しました。

```shell-session
$ sudo gem update --system
Password:
Updating rubygems-update
Fetching: rubygems-update-3.0.0.gem (100%)
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /usr/bin directory.
```

RubyGemsが `/usr/bin` にインストールされていて、アクセス権限がないのが原因です。

```shell-session
$ which gem
/usr/bin/gem
```

`usr/local/bin` にインストールし直せば解決できると思いますが、手間がかかるので現状のバージョンのままとしました。

### CocoaPodsのインストール

RubyGemsからインストールします。

```shell-session
$ sudo gem install -n /usr/local/bin cocoapods
```

`sudo gem install cocoapods` でインストール先を指定せずにインストールすると、 `-bash: pod: command not found` となり `pod` コマンドが使えないので注意してください。

### CocoaPodsのセットアップ

`pod setup` コマンドでCocoaPodsの環境をセットアップします。

```shell-session
$ pod setup
```

セットアップが完了しない場合、以下を実行し、再度 `pod setup` を実行するとうまくいくことがあります。
`git clone` に時間がかかるので注意です。

```shell-session
$ cd ~/.cocoapods/repos/
$ rm -rf master/
$ git clone https://github.com/CocoaPods/Specs.git master
```

## ライブラリのセットアップ

### カレントフォルダの変更

まずはプロジェクトのルートフォルダに移動します。

```shell-session
$ cd {.xcodeprojファイルがあるフォルダ}
```

### Podfileの作成

`pod init` コマンドを実行すると、カレントフォルダに `Podfile` というファイルが作成されます。

```shell-session
$ pod init
```

### Podfileの編集

PodfileをVimなどのテキストエディタで開きます。

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

target '{製品ターゲット名}' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for {製品ターゲット名}

  target '{テストターゲット名}' do
    inherit! :search_paths
    # Pods for testing
  end

end
```

すでにテンプレートが記述されていることがわかるので、1つずつ編集していきます。

#### 対象プラットフォームの指定

コメントに記述されている通り、platformをコメントインして対象のプラットフォームを指定します。

例：
対象OS：iOS
対象バージョン：10.0以上

```diff
# Uncomment the next line to define a global platform for your project
- # platform :ios, '9.0'
+ platform :ios, '10.0'
```

プラットフォームを指定しない場合、 `pod update` 時などに以下の警告が出力されます。

```shell-session
[!] Automatically assigning platform `ios` with version `12.0` on target `{プロジェクト名}` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
```

簡単に訳すと「Podfileにプラットフォームが指定されていないから、勝手にiOSの12.0にしたよ」ということです。

#### ライブラリの指定

使いたいライブラリを `target '{製品ターゲット名}' do` の中に記述していきます。
フォーマットは  `pod '{ライブラリ名}' '{記号} {バージョン}'` です。

例：
バージョン6.0と互換性のあるGoogleTagManagerを指定

```diff
target '{製品ターゲット名}' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for {製品ターゲット名}
+ pod 'GoogleTagManager', '~> 6.0'
…
end
```

記号の意味は以下の通りです。

|記号|意味|
|:--|:--|
|> 1.0|1.0より大きい最新バージョン|
|>= 1.0|1.0以降の最新バージョン|
|< 1.0|1.0より小さいバージョン|
|<= 1.0|1.0以前のバージョン|
|~> 1.0|1.0と互換性がある最新バージョン|
|なし|最新バージョン|

### ライブラリをテストターゲットに追加

__TARGETSでテストターゲットを選択 > Build Settings - Framework Search Paths__

`$(inherited)` を全てのテストターゲットに記述します。
Carthageなどですでに記述している場合、半角スペース区切りで追加すればOKです。

<img width="1019" alt="スクリーンショット_2019-01-05_17_05_59.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/138245/ebc1ff6f-b6db-87d3-4adc-101d268d88f9.jpeg">

こちらを記述しないと単体テストの実行時に以下のビルドエラーが発生することがあります。

```
ld: framework not found {ライブラリ名}
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

ビルドエラー以外にも `pod update` 時などに以下の警告が出力されます。

```
[!] The `{プロジェクト名}Tests [Debug]` target overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-{プロジェクト名}Tests/Pods-{プロジェクト名}Tests.debug.xcconfig'. This can lead to problems with the CocoaPods installation
  - Use the `$(inherited)` flag, or
  - Remove the build settings from the target.
```

[Debug] or [Release]×Unit Tests or UITestsで計4つも似たような警告が出力されます。

### ユーザーデータの削除

`$(inherited)` の追加時に「No Scheme」となってビルドできなくなることがあります。
その場合、プロジェクトからユーザーデータを削除することでスキーマが復活します。

__{プロジェクト名}.xcodeprojを右クリック > パッケージの内容を表示__
<img width="510" alt="スクリーンショット_2019-01-05_17_21_21.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/138245/39b76d6e-1dfc-2eb7-5728-3d4bde95179d.jpeg">

__xcuserdata > {ユーザー名}.xcuserdatadをフォルダごと削除__
<img width="426" alt="スクリーンショット_2019-01-05_17_25_30.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/138245/12ec12b2-444f-c7a7-3afa-7553fdcb90c1.jpeg">

### ライブラリのインストール

Xcodeを終了し、以下のコマンドを実行します。

```bash
$ pod install
```

インストールが完了すると `{プロジェクト名}.xcworkspace` というファイルが作成されるので、`{プロジェクト名}.xcodeproj` ではなくこちらを開くようにします。
<img width="658" alt="スクリーンショット 2018-12-22 14.17.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/138245/3e1fe5be-420e-6ec1-555e-a556ec8dbdf9.png">

Podfile.lockというファイルも作成されます。
こちらのファイルには実際にインストールしたライブラリのバージョンが記述されています。

Podfile.lockが存在するときに `pod install` を実行すると、 __Podfileを見ずにPodfile.lockのみを見てライブラリをインストール__ します。
開発者同士でライブラリのバージョンを合わせるときに使います。

### ライブラリの更新

`pod update` コマンドを実行すると、Podfileに記述した全てのライブラリが更新されます。

```shell-session
$ pod update
```

Podfile.lockも更新されます。

特定のライブラリのみ更新したい場合、半角スペース区切りでライブラリを指定することで行えます。

```bash
$ pod update {ライブラリ名1} {ライブラリ名2} ...
```

### バージョン管理から無視する

インストールされたライブラリは `Pods` フォルダ内に格納されます。

サイズが大きいため、 `Pods` フォルダごとバージョン管理の対象外にすべきです。
Gitを使っている場合、以下を .gitignore に追加するのみでOKです。

```:.gitignore
Pods
```

## CocoaPodsのバージョンアップ

RubyGemsからバージョンアップします。

```shell-session
$ sudo gem update -n /usr/local/bin cocoapods
```

## おわりに

これでライブラリが使えるようになります！
GTMやCrashlyticsなど、公式がCocoaPodsからのインストールのみを紹介しているライブラリはまだ多いので、Carthageとうまく併用しつつ、素晴らしいライブラリライフを送りましょう:relaxed:

## 参考リンク

- [CocoaPods.org](https://cocoapods.org)
- [objective c - target overrides the FRAMEWORK_SEARCH_PATHS build settings - Stack Overflow](https://stackoverflow.com/questions/26445784/target-overrides-the-framework-search-paths-build-settings)
- [”No Scheme”になってしまった場合の対応](https://www.rizastar.com/blog_xcode/xcode-no-scheme/)
- [pod installとpod updateの違いについて - Qiita](https://qiita.com/shtnkgm/items/db45fd85c63696fd769b)