Edited at
iOSDay 11

CocoaPods Private Specリポジトリの作成と利用方法

More than 3 years have passed since last update.

CocoaPodsでは公式なSpecリポジトリがGitHub上に公開されています。

https://github.com/CocoaPods/Specs

従来からこれとは別にPrivateなSpecリポジトリを用意する方法がありました。さらにCocoaPods 0.34から Podfile に宣言できるようになったことで明示的に参照するSpecリポジトリが指定できます。


Podfile

source 'https://github.com/makotokw/CocoaPodsSpecs.git'

source 'https://github.com/CocoaPods/Specs.git'

今回は自前のSpecリポジトリの作成と利用法について書きます。


自前のSpecリポジトリが必要なケース

CocoaPodsではPodfileに以下のように書くことで本家のリポジトリにない自前のPodを使うことができます。


Podfile

pod 'WZYFlatUIColor', :git => 'https://github.com/makotokw/CocoaWZYFlatUIColor.git'


これで済むならSpecリポジトリを用意する必要はありません。Specリポジトリが必要になる理由としては以下のようなものがあります。


  • Podの依存関係やバージョンを適切に管理したい

  • 柔軟にPodのバージョンを指定したい


Podの依存関係

長くライブラリを開発しているとさらに共通の処理を別の共有ライブラリに作成して逃したくなります。そうするとPodとPod間に依存関係が必要になります。CocoaPodsではPodごとのPodspecファイルに dependency シンタックスを使って依存関係を宣言することができます。


CommonLibrary.podspec

spec.dependency 'CommonLibrary2'


しかしdependency シンタックスでは :git オプションがサポートされておらずSpecリポジトリにあるPodでなければ依存関係に指定できません。Specリポジトリを用意しないで解決するにはdependency シンタックスを使わずにアプリケーション側で Podfile に以下のようにPodに依存するPodを全て指定する必要があります。


Podfile

pod 'CommonLibrary', :git => 'https://github.com/makotokw/CommonLibrary.git'

pod 'CommonLibrary2', :git => 'https://github.com/makotokw/CommonLibrary2.git'

しかし、この回避策ではアプリケーションの開発者がライブラリの依存関係を全て把握し、依存関係に変更があった場合にPodfileの内容を同期しなければなりません。


Podのバージョン管理

長く開発していると全てのアプリケーションが同じバージョンのライブラリを利用することは難しくなります。例えば、ある共有ライブラリでv2.0からiOS5を切るといった選択をした場合、iOS5対応のアプリではv1.*を使うということで以下のように書きたいものです。


Podfile

pod 'CommonLibrary', '~> 1.0'


これを gitオプションで参照するPodの場合は branchtag を使って管理することになります。


Podfile

pod 'CommonLibrary', :git => '...', :branch => 'develop'

pod 'CommonLibrary2', :git => '...', :tag => '1.0'

この場合 '~> 1.0' のようなバージョン比較の記述が利用できません。

またアプリケーションとライブラリの依存ならともかく、以下のようにライブラリ間でバージョンの依存関係ができてしまうとアプリケーション開発者がすべてのライブラリの依存関係を Podfile で管理するのは難しくなってきます。


  • CommonLibrary v1.0 が CommonLibrary2 v1.* に依存する

  • CommonLibrary v1.1 が CommonLibrary2 v2.* に依存する

CommonLibraryがどのライブラリのバージョンに依存しているかはカプセル化されているべき内容です。自前のSpecリポジトリを用意すれば :git オプションに頼ることなくライブラリを利用でき、バージョン利用の柔軟性や、Pod間の依存関係をライブラリの開発者に任せることができます。

それまではアプリケーションごとの Podfile で頑張ってはいましたが管理が限界に来ていたため sources の指定が義務付けられたCocoaPods 0.34のタイミングで自前のSpecリポジトリの利用に踏み切りました。


Specリポジトリを作成する

本家がそうであるようにSpecリポジトリはただのGitリポジトリとして存在します。Private Specリポジトリと呼ばれることもありますが、実際にPrivateかどうかはこのGitリポジトリの公開範囲できまります。GitリポジトリがPrivateであればそのSpecリポジトリはPrivateなものになりますし、GitHubなどでPublicなSpecリポジトリとして公開することも可能です。

Specリポジトリは以下のような構造でファイルを管理することで利用できます。

.

└── [SPEC_NAME]
└── [VERSION]
└── [SPEC_NAME].podspec

しかしPodのリリースの度にバージョンフォルダを作成してPodspecファイルを追加するのは面倒なので、これを行ってくれる pod repo push コマンドを利用します。


リポジトリの登録

pod repo push を使う準備作業として、まず push する先のSpecリポジトリを名前付きで登録します。Gitのリモートリポジトリのようなものだと考えると良いでしょう。

pod repo add REPO_NAME SOURCE_URL

たとえば以下のように書くことができます。

pod repo add makotokw git@github.com:makotokw/CocoaPodsSpecs.git


Podを登録する

SpecリポジトリにPodを登録するにはPodspecファイルを用意して、事前に登録しておいたREPO_NAMEに対して pod repo push を使うことで行えます。このコマンドでは指定したPodspecファイルの内容に準じて適切な階層にファイルを追加し、Gitのpushまでを行ってくれます。

この作業はPodの新しいバージョンをリリースする度に行い、既に登録済みのバージョンがあった場合は既存のものを差し替えることができます。

pod repo push makotokw CommonLibrary.podspec --allow-warnings

pod repo pushではPodspecファイルの内容を検証し、問題があれば登録できません。本家のSpecリポジトリに登録する際に使われることもあってか検証は厳し目になっています。

例えばLicense情報の指定がないと警告になり登録できないなど、PrivateなSpecリポジトリの場合には本質的ではない検証もあるため --allow-warnings で警告を許可するのも有効です。

なお pod spec lint NAME.podspec で登録する前に検証ができます。この際にdependencyで本家のSpecリポジトリに登録されていないPodに依存している場合は --sources にSpecリポジトリを指定する必要があり、以下のような形で実行します。警告を無視するのであれば--allow-warningsを指定できます。

pod spec lint NAME.podspec --sources=makotokw --allow-warnings

pod spec lintではPodspecファイルでsourceに指定したソースコードが検証されます。以下のように指定している場合はGit上のソースコードが検証の対象になります。


CommonLibrary.podspec

spec.source       = { :git => "https://github.com/makotokw/CommonLibrary.git", :tag => "v1.0.0" }


ローカルのソースコードで確認したい場合は pod lib lintコマンドを代わりに使うことができます。

pod lib lint NAME.podspec --sources=makotokw,master --allow-warnings


作成したSpecリポジトリを利用する

冒頭にも書きましたが作成したSpecリポジトリを利用するにはPodfilesourceで宣言します。

source 'https://github.com/makotokw/CocoaPodsSpecs.git'

source 'https://github.com/CocoaPods/Specs.git'

Specリポジトリは宣言した順番に検索されます。(以前は名前順でSpecsリポジトリが検索され、本家がmasterという名前のため自前のリポジトリ名がMより前か後ろかで挙動が変わる問題がありました)

従って自前のSpecリポジトリを先に宣言しておけば、本家のSpecリポジトリで公開されているPodをforkし、自前のSpecリポジトリに登録することでforkした方を優先して利用するといった使い方ができます。(ただしpod install時に同名のPodが複数のSpecリポジトリから検出されると警告はでます)


Specリポジトリを使う際の注意点

CocoaPodsのバージョンによって許可されていたシンタックスが非推奨になったり、挙動が変わることによってSpecリポジトリにあるPodspecファイルを書き直すなどメンテナンスが必要になることがあります。

実際問題、0.35の際に循環依存のチェックが入って修正を余儀なくされました。本家のSpecリポジトリでもみんなで修正している様が伺えます。#12783, #12819

これはSpecリポジトリに限った話ではありませんが、CocoaPodsを使う場合は更新情報をチェックして特にBreakingな修正には動作を確認しておく必要があります。時にはXcodeのバージョンにも左右されることもあります。

CocoaPodsは便利ですが深く付き合うにはそれなりの覚悟も必要です。


まとめ

Private Specリポジトリ自体は昔からありましたが、source の宣言がサポートされようやくライブラリ開発者にとってもアプリケーション開発者にとっても利用しやすくなったと思います。幾つものアプリケーションを開発している方はうまくライブラリを再利用することで生産性を高めていくとよいでしょう。

一方で本家のリポジトリに登録する、自前のSpecリポジトリを公開するなど自作のPodをオープンにしてくことも忘れないようにしたいと思います。

CocoaPodsはバージョン更新によって挙動が変わるのでチームで使うにはどのバージョンを使うか、いつアップデートするかなどSpecリポジトリの管理も含めてチームの中で誰が責任をもって運用するかが重要です。