独自URL Schemeの追加と、そのハンドラの実装
Table of Contents
URLには https://
Schemeを利用することが多いが、 mailto:
file:
のように他にもいろいろなScheme1がある。
また、macOS標準のScheme以外にも独自URL Schemeを追加するアプリケーションも存在する(e.g. org-protocol:
)2。
では、これらアプリケーションはどのように登録しているのだろうか?
独自URL Schemeの追加
独自URL Schemeは、Script Editorで作成したApplicationを適宜変更していくと楽に追加できる。 また、URLのハンドリング部分を全てAppleScriptで書いてもいいが、慣れていないので今後のメンテナンスを考えGoで実装したhandlerを呼び出すことにした。
ここでは例として、 go://journal/<date>
形式のリンクを踏むと該当する日記をEmacsで開くものを実装する。
まずはScriptEditorを起動して新規ファイルを作成し、ドキュメント3見つつCode 1のスクリプトを書いた。
on gohandler(input)
do shell script "/Applications/GoHandler.app/Contents/MacOS/bin/go-scheme-handler " & (quoted form of input)
end gohandler
on open location input
gohandler(input)
end open location
display dialog "GoHandler handles URL with the `go:` scheme :)"
これを Application
タイプで保存すると、Code 2のような構成のアプリケーションが生成された。
先ほど作成したスクリプトは Gohandler.app/Contents/Resources/Scripts/main.scpt
として格納されているので、
再度編集したい場合はこれをopenすればよい。
$ tree GoHandler.app/
GoHandler.app/
└── Contents
├── Info.plist
├── MacOS
│ └── applet
├── PkgInfo
└── Resources
├── Scripts
│ └── main.scpt
├── applet.icns
├── applet.rsrc
└── description.rtfd
└── TXT.rtf
5 directories, 7 files
先程のScriptには go:
をバインドする部分がなかったが、この設定は Info.plist
の方で定義できる。
定義方法は、Code 3の内容を最上位の <dict>
要素に追加するだけ。
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Go URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>go</string>
</array>
</dict>
</array>
TIPS Macアプリの簡単なアイコン変更方法
アイコンにしたい画像をクリップボードにコピーしておいた状態でアプリケーションを右クリック、メニューが表示されたらから Show Info
を選択。
ポップアップが表示されたら左上のアイコンをクリックしてペースト。
go-scheme-handlerの実装
URL Schemeとのバインド部分は完成したので、残りのハンドリング部分を実装する。
go-scheme-handler
は引数でURLを受け取るので、これをパースしてやりたい処理にハンドリングするだけ。
今後いろいろ追加していきたいので、Code 4のようにホスト部分で切り替えられるようにした。
コードの全体像はLadicle/go-scheme-handlerを参照。
func (h *Handler) handle() error {
switch h.url.Host {
// "journal/<name>"
case "journal":
return openJournalEditor(h.url.Path)
default:
return fmt.Errorf("%q is unknown hostname", h.url.Host)
}
}
最後に、ビルドした実行ファイルを GoHandler.app/Contents/MacOS/bin/
に配置すれば完成。
動作を確認するため、作成したアプリケーションを /Application
ディレクトリにコピーし、
Code 5のように go:
が正しく登録されたことを確認する。
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep -B6 "bindings:.*go:"
claim id: Go URL (0x15ae8)
localizedNames: "LSDefaultLocalizedValue" = "Go URL"
rank: Default
bundle: GoHandler (0x4914)
flags: apple-internal url-type (0000000000000042)
roles: Viewer (0000000000000002)
bindings: go:
q--
claim id: Go URL (0x15ae8)
localizedNames: "LSDefaultLocalizedValue" = "Go URL"
rank: Default
bundle: GoHandler (0x4914)
flags: apple-internal url-type (0000000000000042)
roles: Viewer (0000000000000002)
bindings: go:
独自Scheme利用した編集ボタンをつける
実際にこのハンドラを利用してみる。プライベートなメモ帳でもHugoを利用しているので、 そのページにCode 6のような編集ボタンを設定してみる。Hugoのファイル名は出力元(journal)のファイル名にアンダースコア(_)と日時を付与している。よって、編集するファイル名はこの前半部分を取得すれば良い。
また、Hugoのデフォルトで http:
/ https:
/ mailto:
以外のスキーマが禁止されている。
そのため、URLに safeURL
関数をパイプしてこれを回避している4。
{{ $editURL := (print "go://journal/" (index (split .File.BaseFileName "_") 0)) }}
<a class="edit-button" href="{{ $editURL | safeURL }}">Edit</a>
実際にこの挙動を確認してみる。最初の 1のように該当記事のJournalがEmacs上で開くことが確認できた。
TIPS Chromeの確認ダイアログを初回のみ表示させる
Chromeのv79+から外部アプリケーションを開こうとすると毎回確認ダイアログが表示されるようになった。 これを防ぐためには、Code 7のオプションの有効化が必要。これを有効にすると、「次回以降非表示にする」というチェックボックスがダイアログから選択できるようになる。(設定後にブラウザの再起動必須)
$ defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -bool true
.