MeetingBar はカレンダーの次の予定をメニューバーに出してくれるアプリです。 起動しっぱなしでよいのですが、たまに落ちていて予定を見落とすことがあったので、毎時28分と58分に起動し直す仕組みを組みました。 やりたいのは、次のコマンドを定期実行することです。
open -g -j -a "MeetingBar"
-a はアプリ名で起動、-j はウィンドウを隠した状態(hidden)で起動、-g はアプリをフォアグラウンドに持ってこないオプションです。
すでに起動済みなら二重には立ち上がらず、既存プロセスがそのまま使われます。
-g をつけないと実行されるたびに作業中のウィンドウからフォーカスが奪われてしまうので、-g も忘れずに付けてください。
なぜcronではなくlaunchdか
定期実行というと crontab が手軽ですが、今回はGUIアプリの起動が絡みます。
open -a はユーザーのGUI(Aqua)セッションの中で動く必要があり、cron経由だとこのセッションに結び付かず、アプリの起動やフルディスクアクセスの許可周りで詰まることがあります。
macOSではユーザー単位のバックグラウンドジョブにLaunchAgentが用意されていて、ログイン中のGUIセッションの文脈で実行されます。 GUIアプリの定期起動はこちらのほうが素直に動くので、launchdを使うことにしました。
plistを作る
~/Library/LaunchAgents/com.user.meetingbar-launch.plist を作成します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.meetingbar-launch</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/open</string>
<string>-g</string>
<string>-j</string>
<string>-a</string>
<string>MeetingBar</string>
</array>
<key>StartCalendarInterval</key>
<array>
<dict><key>Minute</key><integer>28</integer></dict>
<dict><key>Minute</key><integer>58</integer></dict>
</array>
</dict>
</plist>
ポイントは2つあります。
1つ目は、コマンドを空白で区切った1つの文字列ではなく、ProgramArguments の配列に要素ごとに分けて書くことです。
launchdはシェルを介さずにコマンドを直接実行するので、open -g -j -a MeetingBar とまとめて書くと1つの実行ファイル名として扱われて動きません。
2つ目は、スケジュールを表す StartCalendarInterval です。
Minute に 28 と 58 を指定した辞書を配列で2つ並べ、Hour を省略しています。
Hour を省略した項目はすべての時にマッチするので、これで毎時28分と58分の2回発火します。
cronで書くと 28,58 * * * * になります。
ロードする
作った定義をlaunchdに読み込ませます。
すでに読み込み済みでもエラーにならないよう、先に unload してから load します。
launchctl unload ~/Library/LaunchAgents/com.user.meetingbar-launch.plist 2>/dev/null
launchctl load ~/Library/LaunchAgents/com.user.meetingbar-launch.plist
一度ロードしておけば、以後はログイン時に自動で読み込まれます。
動作を確認する
まずplistの構文をチェックします。
plutil -lint ~/Library/LaunchAgents/com.user.meetingbar-launch.plist
# => .../com.user.meetingbar-launch.plist: OK
ロードされているかは launchctl list で確認できます。
launchctl list | grep meetingbar
# => - 0 com.user.meetingbar-launch
左端はPID(実行中でなければ -)、真ん中は直近の終了コードです。
0 なので正常に登録されています。
次の28分・58分を待たなくても、launchctl start で即座に発火させて確認できます。
launchctl start com.user.meetingbar-launch
pgrep -x MeetingBar >/dev/null && echo running || echo not-running
# => running
MeetingBarが起動すれば成功です。
無効化する
止めたくなったら以下のコマンドでアンロードします。
launchctl unload ~/Library/LaunchAgents/com.user.meetingbar-launch.plist
まとめ
- GUIアプリの定期起動は、crontabではなくlaunchdを使いましょう
- openコマンドに
-g付けるのを忘れないようにしましょう - これでPC再起動時も自動起動してくれるので、ミーティングに遅刻することはありません!クビ回避!