Sketchプラグインの開発環境をXcodeで構築する

# Xcode用テンプレートのインストール

SketchプラグインのためのXcodeテンプレートが存在するので、それを利用します。

```shell
$ git clone https://github.com/MagicSketch/XcodeTemplate-SketchPlugin.git ~/Library/Developer/Xcode/Templates/Sketch\ Plugin
```

# 新規プロジェクト作成

テンプレートには3種類あります。

- **Sketch Panel UI Framework**
    - インスペクターのUIを提供するにはこのテンプレからフレームワーク作成します
- **Sketch Plugin Framework**
    - 独自のフレームワークを作成する場合にはこのテンプレからフレームワークを作成します
- **Sketch Plugin Bundle**
    - Sketchプラグインバンドルのテンプレです。今回はこれを利用します

![](https://qiita-image-store.s3.amazonaws.com/0/3603/f63e649e-1a62-ce73-0932-fcc0805d4d20.png)

# manifest.json

manifest.json はプラグインの情報を記述するためのJSONファイルです。

新規プロジェクトからすでにプラグインの雛形は出来上がっているので、manifest.jsonに必要な情報を記述しておきます。

|項目|内容|
|:--|:--|
|name|プラグインの表示名|
|description|プラグインの説明文（プラグインマネージャ画面に表示されます）|
|author|作者名|
|authorEmail|作者メール|
|homepage|プラグインホームページ|
|identifier|プラグインID（逆ドメイン記法が望ましい）|
|compatibleVersion|Sketch互換バージョン(44など／現在は利用されていない模様)|
|build|プラグインビルド番号|
|version|プラグインバージョン|
|appcast|アップデート配信対応用|
|menu|プラグインメニューの定義|
|commands|プラグインメニューコマンドの定義|

## menu定義

Pluginsメニューに挿入するメニュー項目を定義できます。
サブメニューにまとめるなら `isRoot` を `false` にします。そのとき、`title` がメニュー名になります。
`items` には commands で定義するコマンドの identifier を記述します。

```json:menu例
"menu": {
	"isRoot" : false,
	"shortcut" : "",
	"title": "LoveCocoa",
	"items": [
		"menu-1"
	]
}
```

## commands定義

命令を定義します。コマンドの identifier とスクリプトのメソッド名を対応付けます。
`name` で表示名を設定します。
`script` でスクリプトのファイル名を指定します。
`handler` `handlers` で実行するメソッド名を指定します。

```json:commands例
"commands": [
	{
		"name" : "Run",
		"identifier" : "menu-1",
		"shortcut" : "",
		"script" : "script.cocoascript",
		"handler" : "onRun"
	},
	{
		"script" : "script.cocoscript",
		"handlers" : {
			"actions" : {
				"Startup" : "onStartup",
				"OpenDocument":"onOpenDocument",
				"SelectionChanged.finish" : "onSelectionChanged"
			}
		}
	}
]
```

# CocoaScript

JavaScriptでCocoa/Objective-Cをブリッジできます。
直接Objective-Cメッセージを記述してCocoa APIを呼び出すことができます。

※テンプレで自動生成されるスクリプトファイルは `.cocoscript` となっており、これはタイポだと思われます。プルリクが出ていますが今のところマージされていません。
https://github.com/MagicSketch/XcodeTemplate-SketchPlugin/pull/7


# Xcodeワークスペース

例として二つのプロジェクトを同時に扱う場合を想定します。

- **Sketchプラグイン**: Sketchプラグインのプロジェクト
- **Cocoa Bundle**: プラグインに動的にロードさせるバンドルのプロジェクト

まずは空のワークスペースを用意しましょう。

![](https://qiita-image-store.s3.amazonaws.com/0/3603/80de481b-bf56-9c9c-0144-d90fbbe96ca9.png)


## Sketchプラグイン

テンプレからSketchプラグインのプロジェクトを新規作成します。
これを先ほどのワークスペースに追加します。

## Cocoa Bundleでプロジェクトを作成

macOSのCocoa Bundleでプロジェクトを作成します。
これを先ほどのワークスペースに追加します。

# Sketchプラグイン: ビルドフェーズ

Sketchプラグイン側のターゲットからBuild Phasesを開き、次の手順を踏みます。

## サブプロジェクトの紐付け

"Link Binaries with Libraries" にCocoa Bundleプロジェクトファイル（xcodeproj）を追加します。

![](https://qiita-image-store.s3.amazonaws.com/0/3603/f198b7b2-0b87-e1d3-dabd-3e2dd5d00dee.png)

## Target Dependencies の紐付け

＋ボタンから成果物（.bundle）を指定します。
![](https://qiita-image-store.s3.amazonaws.com/0/3603/52383c7a-e7c7-63be-0927-9cc87f2ef198.png)

## .bundle のコピー設定

Copy Files に .bundle を追加します。
![](https://qiita-image-store.s3.amazonaws.com/0/3603/8c209c0c-3047-7f9e-2abc-0e5879191182.png)

# Sketchプラグイン: プラグインの自動インストール (Run Script)

ビルド済みプラグインをPluginsディレクトリーにコピーするためのスクリプトがテンプレに実装されているため、我々はただXcodeでビルドして実行するだけで良いです。

# Sketchプラグイン: Sketch.appの起動設定

ビルド&実行と同時にSketch.appを立ち上げてプラグインをロードさせることができます。
Sketchプラグイン側のスキーム設定を開き、ExecutableにSketch.appを指定します。

コンソールもXcodeのものが使えるので便利です。

![](https://qiita-image-store.s3.amazonaws.com/0/3603/25919468-2bde-a5b1-0bac-7e488e1e69b5.png)

# Cocoa Bundle: プリンシパルクラスの用意

プリンシパルクラスを用意します。名前を `Principal` としたとき、これを Info.plist に記述しておきます。（名前はなんでも良いです。）

![](https://qiita-image-store.s3.amazonaws.com/0/3603/e9ffb89c-dae4-a628-3c28-5976de7e4252.png)


```objc:Principal.h
#import <Cocoa/Cocoa.h>

@interface Principal : NSObject

+ (NSString*)hello;
- (NSString*)goodbye;
- (NSString*)show;

@end
```

```objc:Principal.m
#import "Principal.h"
#import "BundleTest-Swift.h"

@implementation Principal

+ (NSString*)hello {
	return @"hello";
}

- (NSString*)goodbye {
	return @"byebye";
}

- (NSString*)show {
	return @"show";
}

@end
```

# 注意

## Swift コードを含んでいる場合に `Library not loaded: @rpath/libswiftAppKit.dylib` が出てしまう

Build Settingsから `Runpath Search Paths` に `${DT_TOOLCHAIN_DIR}/usr/lib/swift/macosx/` を追加するとこれは直ります。

https://stackoverflow.com/questions/41721938/xcode-issue-library-not-loaded-rpath-libswiftappkit-dylib

## Cocoa Bundleやフレームワークは一度ロードされると解放されないので注意

適宜XcodeのビルドキャッシュをクリアしてSketch.appも再起動しましょう。
# 参考資料

https://blog.magicsketch.io/beginning-sketch-plugins-development-in-xcode-2ee562352798
https://blog.magicsketch.io/sketch-plugin-xcode-template-c8236a6f7fff