チームで開発しているmacOSのメニューバーアプリを、ユーザーのログイン後に起動させたいとします。リモートMac上で「ログイン時に起動」をオンにすると、画面には有効と表示されます。その後、リモートデスクトップを切断して再接続しても、アプリは終了せずに残っていました。しかし、これではログイン項目が機能した証拠にはなりません。検証では、登録、ユーザーによる許可、実際に再ログインした後の起動を分けて記録します。特に、リモートクライアントの切断をmacOSからのログアウトと取り違えないことが重要です。
テスト対象と範囲を決める
ここで検証するのは、SMAppService.mainAppで登録するメインアプリのログイン項目です。バックグラウンドのヘルパーアプリやシステム起動時に動くサービスは対象ではありません。対象アプリはmacOS 13以降に対応し、アプリ自身のプロセスから登録APIを呼び出す必要があります。コマンドラインでSwiftスクリプトを単独実行しても、アプリに代わって同じ登録を行うことはできません。
テスト用に独立した標準ユーザーを用意し、そのアカウントのグラフィカルデスクトップへ再ログインできることを事前に確認します。ビルド作業中のアカウントをそのままテストに使わないでください。ログアウトすると対話セッションが終了し、そのセッションに依存するプロセスも中断される可能性があります。作業内容を保存し、再接続の方法を記録してからテストを始めます。
「登録済み」「許可済み」「ログイン後に起動済み」は、それぞれ異なる結論です。各段階に対応する証拠を残し、前の状態から次の状態を推測しないでください。
インストール済みアプリを確認する
Xcodeから実行するだけでなく、実際に配布する予定のアプリバンドルを使ってテストします。以下のパスは実際のインストール先に置き換えてください。
APP="/Applications/ExampleApp.app"
test -d "$APP" || { echo "App bundle not found"; exit 1; }
/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' \
"$APP/Contents/Info.plist"
codesign --verify --deep --strict --verbose=2 "$APP"
出力されたbundle identifierを記録し、今回のビルド対象と一致することを確認します。codesignによる検証が失敗した場合は、先にアプリバンドルの問題を解決してください。アプリが正常に起動できない状態を、ログイン項目の不具合と誤認してはいけません。また、署名の検証が通っても、ユーザーによる許可やログイン後の起動を確認したことにはなりません。
アプリ内で登録状態を扱う
登録処理は、起動のたびに無条件で呼び出すのではなく、アプリの設定画面にある明示的なスイッチに結び付けます。次のコードはmacOSアプリのターゲット内に配置し、呼び出し側で返された状態を画面表示に反映してください。
import ServiceManagement
@MainActor
func enableLaunchAtLogin() throws -> SMAppService.Status {
let service = SMAppService.mainApp
if service.status == .notRegistered {
try service.register()
}
return service.status
}
画面上で「有効」と表示できるのは、戻り値が.enabledの場合だけです。.requiresApprovalの場合は、操作失敗と表示したり、登録を密かに繰り返したりせず、システム設定を確認するようユーザーに案内します。例外も画面側で処理できるようにしてください。スイッチをオフにするときは、アプリ内でtry SMAppService.mainApp.unregister()を呼び出してから状態を再取得します。スイッチの見た目だけを変更してはいけません。
ユーザーによる許可を確認する
同じテストアカウントでシステム設定を開き、ログイン項目に関する画面で、アプリが表示されているか、手動での許可が必要かを確認します。設定画面の項目名はmacOSのバージョンによって異なる場合があるため、使用中のシステムの表示に従ってください。許可した後はアプリに戻り、SMAppService.mainApp.statusを再取得します。システム設定にアプリ名が表示されただけで、「自動起動を確認済み」と記録しないでください。
実際にログアウトして再ログインする
まずアプリを通常の手順で終了し、実行中でないことを記録します。次にmacOSのメニューからテストアカウントを明示的にログアウトし、同じアカウントのグラフィカルデスクトップに再ログインします。アプリのウィンドウ、メニューバーアイコン、またはアプリ自身で確認できる実行状態を観察してください。起動直後にクラッシュした場合を合格としないよう、どの状態を「起動成功」とするか事前に決めておきます。
| 確認時点 | 残すべき証拠 |
|---|---|
| 登録前 | アプリのバージョン、bundle identifier、テストアカウント |
| 登録後 | アプリが取得したログイン項目の状態 |
| 許可後 | システム設定での状態と、アプリが再取得した状態 |
| 再ログイン後 | アプリが実行中か、正常に操作できるか |
| 無効化して再度ログインした後 | このログイン項目によってアプリが自動起動しないこと |
最後の行は、アプリ内でログイン項目を無効にしてからテストします。アプリが別の仕組みでも起動する場合は、まずその仕組みを特定してください。プロセスが存在するという理由だけで、無効化が失敗したと判断してはいけません。テスト後は必要に応じて再び有効にし、スイッチの状態を確認します。
リモートセッションによる見かけ上の成功を除外する
リモートデスクトップクライアントを閉じる、ネットワークが一時的に切れる、画面をロックする、といった操作では、macOSのユーザーセッションが終了するとは限りません。再接続後に以前のウィンドウが見えたとしても、通常はセッションが継続していたことを示すだけで、ログイン項目が動作した証拠にはなりません。SSH経由でアプリを起動することも、グラフィカルログインのテストにはなりません。SSHのシェルとデスクトップセッションでは環境が異なります。
登録状態は正しいのにログイン後にアプリが見当たらない場合は、登録時と同じユーザーでログインしたか、別のビルドではなくインストール済みのアプリバンドルをテストしたか、システム設定で引き続き許可が必要になっていないか、アプリが起動直後に終了していないかを順に確認します。アプリに起動ログがある場合は、イベントの時刻と今回のログイン時刻を記録し、「起動しなかった」のか「起動後に失敗した」のかを切り分けます。ログにはアクセス用の認証情報を書き込まないでください。
検証結果を次のビルドに引き継ぐ
アプリのバージョン、bundle identifier、macOSのバージョン、テストアカウント、登録前後の状態、許可の操作、再ログインの結果、無効化後の再テスト結果を簡潔に記録します。アプリバンドルを更新するたびに、少なくともインストール済みアプリの識別情報と再ログイン後の結果を再確認してください。ログイン項目の実装を変更した場合は、登録と無効化の両方を改めてテストします。
この手順の目的は、あるマシンで「必ず自動起動する」と証明することではありません。特定のビルドの動作を再現し、問題を切り分けられるようにすることです。グラフィカルログインとリモート接続を区別すれば、ログイン項目の問題は通常、アプリバンドル、ユーザーによる許可、またはアプリの起動そのものに絞り込めます。
よくある質問
登録できたのに再ログイン後にアプリが起動しないのはなぜですか?
ユーザーの許可が必要な状態か、インストール済みアプリを試しているか、実際にログアウトしてグラフィカルセッションへ入り直したかを確認します。起動直後にアプリが終了していないかも調べてください。
リモートデスクトップを切断すればログアウトの検証になりますか?
いいえ。接続を切ってもmacOSのユーザーセッションは続く場合があります。テストアカウントから明示的にログアウトし、再度デスクトップにログインしてください。
クラウドMacをワークフローに取り入れる
VPSPushでは、リモート接続できる専有の物理Macをご利用いただけます。ロケーションと契約期間を選び、注文画面で接続情報と最終金額をご確認ください。