NSDockTilePlugInを使って起動していないMac appのDockに任意のアイコン表示を行う
NSDockTilePlugInとは
NSDockTilePlugInとは、Mac appアプリケーションを起動していない間にもDock tile(Dockアイコンのこと)をカスタマイズできる方法です。例えばApple製のCalendar.appやClock.appのような動的なアイコン表示が可能です。3rdパーティではNovaやiA Presenterでも使われています。
Dock tile pluginの構造
アプリケーションバンドルの中に適切なプラグインバンドルを組み込むことで、Dockが別途ロードしてアプリケーション本体とは別のプロセスでDock tile pluginを走らせられます。例えばNova.appの中には.docktilepluginバンドルが組み込まれています。
プロジェクト設定
Dock tile pluginプロセスのTargetを用意
Xcodeで追加のTargetをBundleテンプレートで作ります。Bundle Extension(拡張子)には.docktileplugin
が使われますが、.plugin
でも機能するようです。
アプリケーション本体側のPlugInsにDock tile pluginを組み込む設定
アプリケーション本体のTargetのBuild Phasesペインで“+”ボタンを押して、New Copy Files Phase
でファイルコピーのフェーズを作ります。これを設定すると、プラグインをアプリケーションバンドル内のPlugIns
に組み込むことができます。
- Destinationを
PlugIns and Foundation Extensions
を選択 - 一覧にはDockTilePlugin.pluginを追加(この名前はBuild Settingsの設定次第)
アプリケーション本体側のInfo.plistにNSDockTilePlugInフィールドを追記
NSDockTilePlugIn
をキーとして、Dock tile pluginバンドルまでのパスを記述します。前回のCopy Files Phaseの設定ならば、ここはバンドル名のみで機能するはずです。
Dock tile pluginのPrincipalClassを設定
Dock tile plugin側のTargetのInfo.plistにNSPrincipalClass
を設定します。今回はDockTilePlugin
という名前のクラス名にしましたが、命名は任意です。
Dock tile pluginのPrincipalClassを実装
PrincipalClassと同じ名前のクラスを実装しましょう。DockTilePlugin.swiftファイルを用意して、クラス名もそれにします。
import Cocoa
class DockTilePlugin: NSObject, NSDockTilePlugIn {
func setDockTile(_ dockTile: NSDockTile?) {
guard let dockTile else { return }
let view = NSView()
view.frame = NSRect(origin: .zero, size: dockTile.size)
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.red.cgColor
dockTile.contentView = view
dockTile.display()
}
func dockMenu() -> NSMenu? {
return NSMenu()
}
}
setDockTile()
はNSDockTilePlugInプロトコルで必須のメソッドです。この中でDockTileを更新する処理を実装します。
オプショナルでDock Menuを提供するdockMenu()
も定義されています。
NSDockTileにはcontentView
があり、ここにカスタムビューを設定することで任意のイメージを描画することができます。再描画処理は自動で行われないので、都度display()
を実行する必要があります。
実装例はこのプロジェクトを参考にしてみてください。
Dock tileが更新されない場合はDockを再起動する
デバッグ最中などは古いDock tileがロードされたままになるので、都度killall Dock
しましょう。
Mac App Storeに載せられない
NSDockTilePlugInを使ったアプリケーションはMac App Storeには載せられないようです。Info.plistにNSDockTilePlugIn
の記述があるだけで弾かれてしまうようです。
- https://twitter.com/_karsten_/status/246963530421633024
- https://web.archive.org/web/20230307013643/https://twitter.com/stroughtonsmith/status/1328448423033442311
サンプルコード/関連コード
Discussion