iOS向けのライブラリをCocoaPodsで配布する

iOS向けのライブラリをオープンソースプロジェクトとして公開するということ、そして依存管理ツール`CocoaPods`で配布する方法について書きます。

先日、2011年から公開しているiOS向けのカラーピッカーのバージョンを2.0に上げました。
シンプルなカラーピッカーですが、使い勝手も組み込みやすさも、かなりいい感じに仕上がっているんじゃないかと思います。
http://hayashi311.github.io/Color-Picker-for-iOS/

2.0に上げるタイミングで、人にお願いしていたCocoaPodsへの登録を初めて自分で行ったので、忘れないためのメモでもあります。

git, GitHubについての説明はしません。

# オープンソースで公開する理由
### 自己顕示欲を満たせる
これを書かなきゃ嘘だと思うんですが、オープンソースプロジェクトを公開して使ってもらうことってかなり快感です。
他の開発者がコードを読んで、自分のアプリに組み込む、これってすごいことです。

### 他の開発者から学べる
勝手にforkされますし、自分の使っていない環境や技術に対応するよう、IssuesやPull Requestが届きます。想定していなかった使い方や、より良い実装、typoの指摘から、初心者の質問まで。

何よりも、他の人の目を意識してコードを書くのはいい経験になります。

### 結構、簡単
iOSの開発環境・エコシステムはこの数年ですごく良くなりました。GitHubも最高です。
`git push`で公開して、`pod try`で試してもらえるんです。

`pod try`を使ったことがない人は、以下のコマンドを試してみてください

    pod try Color-Picker-for-iOS

### オープンソースの適当さが分かる
オープンソースってすごいものだと思っていませんか。
公開してみると結構適当でもみんな使ってくれるんだなということが実感できますし、自分が他のプロジェクトを使う時もちゃんとコード読む癖が付きます。


# 何を公開するか

CocoaPodsを探してもなかったもの、自分が不便だと思って実装したら意外と上手く出来たものを実装するといいんじゃないでしょうか。

僕の場合は、

- ３本のUISliderを使って、RGBを選択させるようなことはしたくなかった
- 当時は微妙なカラーピッカーしかなかった（画像を使っていたり、デザインが微妙だったり

という理由で自前で実装したものを勢いで公開しました。

その後、使われ方や、流行っているプロジェクトを見て、

- 組み込みやすさ
- カスタマイズのしやすさ
- パフォーマンス
- IBフレンドリー&AutoLayout対応 (2.0
- iOS7以降のフラットデザインに変更 (2.0

というような改善を行っています。
公開していなければ考えなかったようなことなので、公開して良かったなーと思っています。

# 公開の準備
今、公開しようとしているコードが、まだアプリから完全に分離できていないという状態だとします。

## 名前を決める
これ大事です。CocoaPodsはGitHubに依存し、GitHubはリポジトリのURLにプロジェクト名が入っている関係で、名前を変えることができません。

僕は3年前に`Color-Picker-for-iOS`という糞みたいな名前を付けてから変えることができていません。

- 検索しやすくて分かりやすい名前
- プレフィックスを付ける (最近は3文字推奨だそうです。インターネットで読みました

こんな感じ

## プロジェクトの準備
いつからか分からないんですが、オープンソースのプロジェクトはこんな構成にすべしという指針をCocoaPodsが公開しています。

https://github.com/CocoaPods/pod-template

`pod try`コマンドは最近実装されたばかりで、ディレクトリ構成によっては上手く動作しないこともあるみたいです。今から公開するのであれば、この指針に従って、

    pod lib create [pod name]

とやるだけで、いい感じのテンプレートが生成されるそうです（やってない

## ライブラリをアプリから分離する

`Classes`の中に、配布するコードを入れて、`Example`の中にサンプルを書きます。
`Example`に書いたものが、`pod try`で実行されます。

公開すると変えられないことも多いので、ここでリファクタリングもやってしまうと良いと思います。

クリーンで、疎結合で、可能な限り理解しやすいように。
流行っているプロジェクトは3行くらいで呼び出せて、カスタマイズすることができます。

参考になるプロジェクトを二つ紹介します。

`AFNetworking2`は互いに依存しない小さな機能を組み合わせて、強力な機能を実現するお手本のようなプロジェクトです。ライブラリは2層になっていて、疎で個別に差し替え可能な機能群と、それを簡単に呼び出せるラッパーに分かれています。
https://github.com/AFNetworking/AFNetworking

`SVProgressHUD`は良いデザインとシンプルなAPIの組み合わせが、どれだけ効果的かを示すよい例です。
`SVProgressHUD`を使う時は何も考える必要がないように設計されていて、アプリ内のどこからでも高品質なHUDを1行で呼び出せます。
https://github.com/samvermette/SVProgressHUD

ライブラリを公開すると思って読むと、また違った発見があると思います。

## READMEを書く
ドキュメントを書きます。
人気のライブラリのREADMEはmarkdownを駆使して読みやすいように装飾されていて、もはやREADME文学というべき何かに昇華されています。

コンセプト、スクリーンショット、サンプルコード、公開後有名アプリに採用されたら、採用実績なんかも書くといいんじゃないでしょうか。

スクリーンショットはスクリーンショット用のブランチに置くか(そして、`raw.githubusercontent.com/~`をREADMEで読み込む)、GitHub Pages用のブランチにでも置いておくと、リポジトリがすっきりします。

## ライセンス
ライセンスを決めます。適当に調べてみてください。
iOSのライブラリではMITライセンスが多いように思います。

## テスト
UIコンポーネントを公開する場合は、なかなか書きづらいんですが、公開するものがUIを伴わないライブラリなら元のアプリのプロジェクトからテストを持ってくるとよいと思います。

---
さて、これで公開するライブラリの準備が整いました。

# CocoaPodsでの配布
## podspecを作る
`pod lib create`で出来たpodspecを編集します。

    pod spec lint

で正しく編集できたか確認できるのですが、Githubにtagをpushするまで通らないようです。

まず、ローカルできちんと動作するか確認する方法です。

### 適当なプロジェクトを作る

    pod init

でPodfileを作ります。これから公開するライブラリを使う側のプロジェクトファイルというイメージです。
Podfileに以下を記述します。

    platform :ios, '7.0'
    pod 'ライブラリ名', :path => 'ライブラリのPath'

CocoaPodsはローカルのプロジェクトも指定することができるんです。

あとはいつも通り、

    pod install

で、上手く動作して、適当なプロジェクト内からライブラリを期待通り呼び出せるまでpodspecを編集します。

## GitHubで公開

GitHubで公開します。ライブラリ名と同じリポジトリ名にしてください。そうしないと、あらゆる面でCocoaPodsが上手く動作しない可能性があります。僕は3年前に(ry

先ほどのPodfileを以下のように書き換えます。

    platform :ios, '7.0'
    pod 'ライブラリ名', :git => 'https://github.com/GitHubアカウント/リポジトリ名.git'

もう一度、適当なプロジェクトで`pod install`を実行して、動作していることを確認します。

Pull Requestを投げづらいので、最低限`master`の他に`develop`ブランチは用意します。

## タグを付ける
CocoaPodsで指定できるバージョンはtagで管理されています。

    git tag 1.0.0

途中で足りなくなって困るので、バージョニングにネコ科の動物の名前を使うようなことはしないように。

バージョニングの作法については以下参照。
http://semver.org/

CocoaPodsには、

    pod 'Hoge', '~> 1.0.7'

と書くと、Hoge 1.0.xまで、

    pod 'Hoge', '~> 1.0'

と書くと、Hoge 1.xまで最新版を取得するというルールがあります。
詳しくは以下参照。
http://guides.cocoapods.org/using/the-podfile.html

tagのバージョンとpodspecに記述するバージョンは揃えます。
問題なければ

    git push 1.0.0 
    // or git push --tags

## pod try

この段階で`pod try`が動きます。

    pod try 'https://github.com/GitHubアカウント/リポジトリ名.git'

## pod lib lint

podspecが正しく書けているか確認します。ここまでくると、podspecをすべて正しく埋めることができるはずです。

    cd ~/code/Pods/NAME
    pod lib lint

いろいろ怒られると思うので、修正してpushします。
tagの方も更新しておきます。(この段階では`force push`してもよいと思います

## CocoaPods trunk
配布用の仕組みで`pod trunk`というのが最近できました。これを使って公開していきます。

まず、アカウント登録

    pod trunk register 自分のメール '自分の名前' --description='macbook@home'

こんな感じ。メールが飛んでくるので、リンクをクリックして確認しておきます。

    pod trunk me

で名前が表示されればOKです。

いよいよ、CocoaPodsで公開します。

    pod trunk push ライブラリ名.podspec

lintが通っていれば問題なくpushできるんじゃないでしょうか。
http://cocoapods.org/ で自分のライブラリを検索してみましょう。
    
    pod try ライブラリ名

でサンプルを実行できます。
適当なプロジェクトの`Podfile`を

    platform :ios, '7.0'
    pod "Color-Picker-for-iOS", "~> 2.0"

に書き換えて`pod install`が通ることを確認します。

# DogFooding

公開が終わったところで、このライブラリを最初に作ったアプリのプロジェクトに戻ります。
プロジェクトの`Podfile`に作ったライブラリを加えて、アプリ内にあったコードを削除します。

これで、普段の開発の中で改善を続けることができます。

# 公開後

ライブラリを公開すると、コードの品質の低さに恥ずかしくなったり、直したいところが出てきたり、GitHub Pagesを作りたくなったり、IssuesやPull Requestを貰ったりしますが、そろそろWWDC 2014が始まる時間なので記事をアップします。

俺たちの戦いはこれからだ！（適当