CocoaPods を試す

2016年12月19日 0 開発 , , ,

これまで akabekobeko/Examples-iOS というリポジトリで iOS に関するサンプルを公開していたのだが、以下のルールで新リポジトリ移行することにした。

  • サンプルごとにリポジトリを分割
    • Examples-iOS/VideoPlayer は examples-ios-video-player のように分割
    • 更新管理しやすくなる
  • 外部ライブラリは CocoaPods.org で管理する
    • 静的に組み込むのではなく、パッケージ管理に委ねる
    • ついでに FMDB サンプルを書き直して examples に追加したい
  • 可能なら Objective-C と Swift のサンプルを同時公開したい
    • iOS 以外でも Swift の利用が進みそうなので、触れておきたい
    • 慣れ親しんだ Objective-C で作成したものと同じサンプルを Swift 移植することで、学びやすくなるのではないか?
    • ひとつのサンプルに objc/swift というサブ ディレクトリがあり、そこが Xcode プロジェクトになる感じ

iOS アプリ開発から 2 年ぐらい遠ざかっておりサンプルも古びている。いまでは動かないものもあるだろう。これは、それらの棚卸しも兼ねた試みでもある。

もう Examples-iOS を更新することはないけれど、これはそのまま残しておく。かつてはこう書いていたという記録にはなるだろう。ただし更新されないサンプルは検索ノイズになってしまうから開発が中止されたことや代替サンプルについてだけ README で言及する予定。

CocoaPods

FMDB の解説記事は 2011 年に書かれたものだが現在も結構なアクセスがある。しかし ARC すら使われていない時代のもので、しかも組み込まれている FMDB が古すぎることから、いつか更新しなければと考えていた。

また、現在の iOS ライブラリ管理には CocoaPods を使用するのが一般的だろう。パッケージ管理にしておけば、ライブラリの依存やバージョン更新も楽になる。というわけで CocoaPods に入門する。

まずは CocoaPods をインストール。と、ここでいきなりつまづいた。

$ sudo gem install cocoapods
...
ERROR:  While executing gem ... (Errno::EPERM)
    Operation not permitted - /usr/bin/xcodeproj

私の環境は macOS Sierra なので、rootless により /usr への書き込みが制限されている。これは sudo でもはねられる。CocoaPods 公式の Getting Started を読むと --user-install でユーザー単位にインストールして shell の .profile にパスを通す方法を紹介していたので、試しにこれを採用してみた。

しかしこの方法でインストールした CocoaPods で生成した Podfile を Git リポジトリに入れて複数マシンで開発していたところ、新規に clone したプロジェクトに対して pod install した後にビルドしたら Podfile.lock No such file or directory というエラーが出るようになった。この問題は

などに解説されている方法で直るそうだが、私の環境ではダメだった。そもそも pod install の内容をみると Abort trap: 6 と出ている。これについて調べたら

にて CocoaPods の再インストールが勧められている。どうやら環境が壊れているらしい。そこでまずはアンインストール。

$ sudo gem uninstall cocoapods
Password:

Select gem to uninstall:
 1. cocoapods-0.34.2
 2. cocoapods-0.39.0
 3. All versions
> 3
Successfully uninstalled cocoapods-0.34.2
Remove executables:
    pod, sandbox-pod

in addition to the gem? [Yn]  Y
Removing pod
Removing sandbox-pod
Successfully uninstalled cocoapods-0.39.0

gem が複数バージョンあるようなので All versions を選び、すべて消した。その後に

$ sudo gem install -n /usr/local/bin cocoapods
...中略...
11 gems installed

でインストール。再び --user-install で入れるか迷ったが permission の通る場所ならばよいわけだし、いちいち .bash_profile を編集するのは面倒なのでこれでゆく。ちゃんとインストールできたか確認。

$ pod --version
1.1.1
$ gem list
...中略...
cocoapods (1.1.1)
cocoapods-core (1.1.1, 0.39.0, 0.34.2)
cocoapods-deintegrate (1.0.1)
cocoapods-downloader (1.1.3, 1.1.2, 0.9.3, 0.7.2)
cocoapods-plugins (1.0.0, 0.4.2, 0.3.1)
cocoapods-search (1.0.0, 0.1.0)
cocoapods-stats (1.0.0, 0.6.2)
cocoapods-trunk (1.1.2, 1.1.1, 0.6.4, 0.3.0)
cocoapods-try (1.1.0, 0.5.1, 0.4.1)

最新版が入ってる。CocoaPods 系 gem も単一バージョンだけのようだ。最後に CocoaPods を初期化する。

$ pod setup
Setting up CocoaPods master repo

CocoaPods 1.2.0.beta.1 is available.
To update use: `sudo gem install cocoapods --pre`
[!] This is a test version we'd love you to try.

For more information, see https://blog.cocoapods.org and the CHANGELOG for this version at https://github.com/CocoaPods/CocoaPods/releases/tag/1.2.0.beta.1

Setup completed

これで準備完了。

CocoaPods でライブラリをインストールする

ある Xcode プロジェクトに CocoaPods 経由でライブラリをインストールするための手順。CocoaPods が導入済みで pod setup まで完了していることを前提とする。

はじめに Terminal で Xcode プロジェクトのルートへ移動。これは 名.xcodeproj ファイルの置かれた場所になる。

次に Terminal から pod init を実行。これで Podfile が生成される。このファイルは YAML 形式となっており、Xcode プロジェクト単位で設定が階層化されている。Xcode プロジェクトを作成する際、テストを有効にした場合は Tests や UITests といったプロジェクトも生成されるので、以下のようになるはず。

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

target 'UsingFMDB-Objective-C' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for UsingFMDB-Objective-C
  pod 'FMDB/FTS'

  target 'UsingFMDB-Objective-CTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'UsingFMDB-Objective-CUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

メインとなるプロジェクトでライブラリを使用したいならルートに追加する。この例では FMDB/FTS を追加している。

Swift プロジェクトの Podfile では use_frameworks! のコメント アウトを解除すること。こうしないと Swift 用のライブラリがインストールされないので注意する。

設定を済ませた後に pod instal を実行すると

$ pod install
Analyzing dependencies
Downloading dependencies
Installing FMDB (2.6.2)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

こんな感じでライブラリがインストールされる。このとき .xcodeproj と同じ階層に以下のファイルとフォルダが追加される。

File/Folder 内容
.xcworkspace プロジェクト間の参照関係を管理するファイル。
Podfile.lock ライブラリのバージョンや依存情報を管理するためのファイル。
Pods/ インストールされたライブラリの実体を格納するフォルダ。

以降の開発で Xcode から開くファイルは .xcworkspace になる。間違って xcodeproj を対象にするとライブラリを参照できずビルドが通らないので気をつけること。

プロジェクトを Git リポジトリで管理しているなら gitignore/Objective-C.gitignore を使用していることだろう。CocoaPods を使用する場合、この .gitignorePods/ がコメントアウトされているので以下のように解除しておく。

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
Pods/

このフォルダは動的に取得したライブラリを格納するのでリポジトリに含める必要はない。それ以外はコミットしておく。他の環境でプロジェクトと共に CocoaPods 関連を取得して pod install すれば同じ環境が整う。

CocoaPods でインストールしたライブラリの参照方法について。Objective-C の場合、

#import <FMDatabase.h>

のようにする。.xcworkspace を開いていれば、ライブラリの参照が通っているので Xcode エディタから補完されるはず。Swift の場合は

import FMDB

となる。なお、補完に出てこない場合は Xcode を開き直すとか、Product – Clean してから Product – Build すると直ることがある。

というか Swift はバックグラウンドで走る構文チェックが不安定で、エラーの原因を修正してもなかなか警告が消えないとか地味にストレスたまる。Swift 3 で言語の破壊的な変更は落ち着くそうだから、Xcode 9 あたりで Objective-C なみにサクサク開発できるようになるのかな、と期待している。

あとこれは愚痴なのだけど、Xcode や CocoaPods 関連は環境的な問題にしばしば遭遇する。CocoaPods は Xcode に後付でパッケージ管理を加えているので仕方のないことではあるが、プログラミングと異なり環境系の問題は操作基盤そのものなので原因を特定するのが難しい。

Stack Overflow などで対策を見つけても、それが起きる原理まで掘り下げていることは滅多にない。そのため指定された手順をなぞっても直らないとか、仕方ないから環境をクリーンにしてから再試行で直ったとかで釈然としない。こういうのを繰り返してるとだんだん堪忍袋が温まってくる。

あのプロプライエタリで有名だった Visual Studio ですら方針転換して NuGet を導入したのだから、Xcode もそろそろ公式に CocoaPods なりそれに類するパッケージ管理をサポートしてほしいものだ。

今後の予定

現在、FMDB サンプルを作成中。

Objective-C 版は完了したのでそれをベースに Swift 版へ処理を移植中。Swift 学習も兼ねているため小さなサンプルなのに苦戦している。

他の examples-ios-XXXX への移行は断続的におこなう。ひとつプロジェクトを作成するたびにそこで起きたことなどをブログに記録してゆく予定。