知識ゼロからXcodeのプラグインを開発してみた

iOSアプリの開発経験はありますが、OS XアプリやXcodeプラグインに関する知識はゼロから始めたので開発の仕方をまとめてみました。
長々と書いていますがやってみると意外と簡単です。
※とりあえず動く簡単なプラグインを開発しただけです。
#はじめに
いろいろ調べているとXcodeのプラグインはAppleが公式でサポートしている機能ではないそうで公式のドキュメントやAPIは公開されていないそうです。
なのでネットに転がっている記事や公開されているプラグインのソースコードを参考に開発してみました。
####参考にしたページ
[Xcode Plugin を試しに作ってみた](http://tochiba.hatenablog.com/entry/2014/03/09/130738)
[Xcode Plugin が盛り上がっているらしい](http://qiita.com/griffin_stewie/items/ffb53d0a5d03fe2d91a4)
[VVDocumenter-Xcode](https://github.com/onevcat/VVDocumenter-Xcode)
#Xcode-Plugin-Templateの導入
Xcodeプラグインの作り方を調べているとInfo.plistの設定やBuild Settingの設定が色々と出てくるのですがその辺りのめんどうな設定をまとめて設定してくれているTemplateです。
###1.Xcode-Plugin-Templateの取得
こちら↓から`git clone https://github.com/kattrali/Xcode-Plugin-Template.git`するかZIPファイルをダウンロードします。
[Xcode-Plugin-Template](https://github.com/kattrali/Xcode-Plugin-Template)
###2.TemplateファイルをXcodeで使用できるようにする
取得したファイルの中から`XcodePlugin.xctemplate`ディレクトリ
(`Xcode-Plugin-Template/Project Templates/Application Plug-in/Xcode Plugin.xctemplate`)
を
`~/Library/Developer/Xcode/Templates/File Templates/`
ディレクトリ以下に移動します。
`Templates`, `File Templates`ディレクトリが存在しない場合は自分で作成してください。
###3.XcodePluginテンプレートファイルを使用してプロジェクトを作成
Xcodeの新規プロジェクト作成で`OS X`->`File Templates`->`Xcode Plugin`を選択してプロジェクトを作成します。（File Templatesがない場合は1,2のTemplatesの追加がうまく行えていないと思います）
![スクリーンショット 2015-08-08 4.30.52.png](https://qiita-image-store.s3.amazonaws.com/0/88056/8605faa2-ad1f-b93b-e8ab-8a723f4941a1.png)

今回はObjective-Cで作成しましたが、Swiftも使用できるようです。
![スクリーンショット 2015-08-08 4.39.46.png](https://qiita-image-store.s3.amazonaws.com/0/88056/41b9befd-20b7-0ac7-453c-9a737995f339.png)
#プロジェクトをビルド〜プラグインを実行
###1.プロジェクトをビルド
作成したプロジェクトをビルド(Command+B)します。
特になにも変更しなくともそのままビルドが通りました。
ビルドが成功すると`~/Library/Application Support/Developer/Shared/Xcode/Plug-ins`ディレクトリに`{プロジェクト名}.xcplugin`というディレクトリが作成されていれば成功のようです。
###2.Xcodeを再起動してプラグインを実行する
ビルドが成功したらXcodeを再起動し、メニューの`Edit->Do Action`をクリックします。
![スクリーンショット 2015-08-09 4.05.20.png](https://qiita-image-store.s3.amazonaws.com/0/88056/32f71751-d5b5-3e4f-26b2-38b1abd2e28a.png)

すると「Hello, World」というアラートが表示されました。
![スクリーンショット 2015-08-09 4.03.46.png](https://qiita-image-store.s3.amazonaws.com/0/88056/f0bb7c86-4a09-fae7-5084-09840009cd02.png)
これでひとまずプラグインが正常に実行されるようになりました。
###3.正常に動作しなかったら
再起動時にこんなアラートが表示された場合は「Load Bundle」を選択すればOKです。
![スクリーンショット 2015-08-09 3.49.33.png](https://qiita-image-store.s3.amazonaws.com/0/88056/8c1bb8f3-f250-fce6-9064-a3c63a98d04b.png)

メニューに「Do Action」が追加されていなかったり正常に動作しない場合は、
`/var/log/system.log`のログの中から「Xcode」を含むログを確認すれば原因が書かれていたりします。
#プラグインの削除
プラグインの削除は削除したいプラグインのプロジェクトをXcodeで開いてプロジェクトをクリーンするか作成されたファイルを直接削除し、Xcodeを再起動すれば削除されるようです。プラグインの影響でXcodeに問題が発生したらこの方法でプラグインを削除してみてください。

プロジェクトのクリーンはメニューの「Product->Clean」を選択（Command+Shift+K）するとクリーンされます。
ファイルの直接削除はプラグインが作成された`~/Library/Application Support/Developer/Shared/Xcode/Plug-ins`ディレクトリから削除したいプラグインのディレクトリを削除でOKです。

#コードを解読してみる
プロジェクト名.m（今回はXcodePluginText.m）をみてみると、`didApplicationFinishLaunchingNotification`でメニューを追加しているのがわかります。そしてメニューが選択されたらアラートを表示するというすごく簡単なコードです。

```objc

- (void)didApplicationFinishLaunchingNotification:(NSNotification*)noti
{
    //removeObserver
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:nil];
    
    // Create menu items, initialize UI, etc.
    // Sample Menu Item:
    // メインメニューのEditメニューを取得
    NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
    if (menuItem) {
        // メニューに区切りを追加
        [[menuItem submenu] addItem:[NSMenuItem separatorItem]];
        // 新しく「Do Action」というメニューを作成
        NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"Do Action" action:@selector(doMenuAction) keyEquivalent:@""];
        //[actionMenuItem setKeyEquivalentModifierMask:NSAlphaShiftKeyMask | NSControlKeyMask];
        [actionMenuItem setTarget:self];
        // 「Edit」のサブメニューとして「Do Action」を追加
        [[menuItem submenu] addItem:actionMenuItem];
    }
    
}

// 追加した「Do Action」メニューが選択されたら呼ばれる
- (void)doMenuAction
{
    // アラートで「Hello, World」を表示
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:@"Hello, World"];
    [alert runModal];
}

```

#コードを変更してみる
今回は16進数のカラーコードからUIColorのコードを生成するプラグインを開発してみました。
###主な変更箇所
####1.メニューのタイトルを変更
「Do Action」を「ConvertUIColor」に変更しただけです。

```objc
NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"ConvertUIColor" action:@selector(doMenuAction) keyEquivalent:@""];
```
####2.WindowControllerクラスとxibファイルを作成
![スクリーンショット 2015-08-11 2.00.45.png](https://qiita-image-store.s3.amazonaws.com/0/88056/06a5b086-2364-5b5e-7ad0-af86036fdfcc.png)


####3.メニュー選択時のアクションをアラートから2.で作成したWindowControllerを表示に変更

```objc
- (void)doMenuAction
{
    // 色変換用のWindowを表示
    self.windowController = [[ConvertColorWindowController alloc] initWithWindowNibName:@"ConvertColorWindowController"];
    [self.windowController showWindow:self.windowController];

}
```
####4.WindowControllerのボタン押下時の処理を記述
UITextFieldではなくNSTextFieldなのでiOSとは若干の違いがあります。

```objc
// 変換ボタン押下時
- (IBAction)convert:(id)sender {
    // 入力された文字列を取得
    NSString* hexString = self.hexTextField.stringValue;
    // 文字列を変換
    NSString* uiColorString = [self stringUIColorFromColorCode:hexString];
    // 出力用のTextFieldに出力
    self.uicolorTextField.stringValue = uiColorString;
}
// クリアボタン押下時
- (IBAction)clear:(id)sender {
    // TextFieldの値をリセット
    self.hexTextField.stringValue = @"";
    self.uicolorTextField.stringValue = @"";
}

/**
 *  16進数の文字列をUIColorに変換
 *
 *  @param colorCode 16進数のカラーコード
 *
 *  @return UIColorの文字列
 */
- (NSString*)stringUIColorFromColorCode:(NSString*)colorCode
{
    // 「#」を取り除く
    NSString* hexString = [colorCode stringByReplacingOccurrencesOfString:@"#" withString:@""];
    // 長さが6未満の場合は空文字を返す
    if (hexString.length < 6) {
        return @"";
    }
    
    // 16進数をintに変換
    unsigned int color[3];
    for (int i = 0; i < 3; i++) {
        NSString *param = [hexString substringWithRange:NSMakeRange(i * 2, 2)];
        NSScanner *scanner = [NSScanner scannerWithString:param];
        [scanner scanHexInt:&color[i]];
    }
    
    // UIColorの文字列に変換
    NSString* uiColorString = [NSString stringWithFormat:@"[UIColor colorWithRed:%f green:%f blue:%f alpha:1.0f]; // #%@",
                               color[0] / 255.0f,
                               color[1] / 255.0f,
                               color[2] / 255.0f,
                               hexString];
    return uiColorString;
}
```
#できたもの
メニューの「Edit->ConvertUIColor」を選択するとこんな感じでWindowが表示されます。
![スクリーンショット 2015-08-11 2.11.30.png](https://qiita-image-store.s3.amazonaws.com/0/88056/ce0e05fd-9f25-4dbd-94a6-6835a715da10.png)
ここに16進数のカラーコードを入力して変換を押すとUIColorの文字列を生成するというものです。（とりあえず作ってみただけなのでダサくて利便性も低いですが・・・）
![スクリーンショット 2015-08-11 2.13.35.png](https://qiita-image-store.s3.amazonaws.com/0/88056/d8aed132-5c28-f6c0-a6a2-8a1c10ddc5cf.png)

16進数のカラーコードをUIColorのソースコードに変換してくれるWEBサービスもありますが、いちいちブラウザに切り替えるのも面倒ですし、かといってソース内で変換する処理を記述するのは無駄な処理をしている感じがして嫌だったのでプラグインで書いてみました。
[ソースコード](https://github.com/gmaesak/ConvertUIColor)

#まとめ
今回はメニューに追加して実行するタイプでしたが、いろいろとイベントを受け取って処理をしたりすることもできるのでそのうち受け取れるイベントのまとめやそのイベントを使ったプラグインも作れればいいなと思っています。

Xcodeのプラグイン作成は敷居が高いイメージでしたが、簡単なものであれば意外とすぐに作成できるのでこんな機能がほしい！というのがあれば自分で作ってみてはいかがでしょう？