Macで長期展示会用の準備（自動起動・クラッシュ対応）

# Macで展示会用アプリの自動起動・再起動設定

長期展示会で作品を投影する際に、自動で立ち上がり、アプリが起動してくれれば、現地に行く工数を避ける。しかし、クラッシュや何かの不手際で落ちることも、、、、

そんな時も、自動で立ち上げてくれる！！ 心強い！

この記事では、Mac（Monterey/Sonoma起動確認済）が自動で立ち上がり、LaunchDaemons内のplistファイルでシェルスクリプトを発火させ、アプリを起動、クラッシュ後も再度起動する方法を解説してます。

## 1. 準備

### shファイルを作成
まず、アプリを起動するためのシェルスクリプトを作成

```sh:launch_app.sh
#!/bin/bash

APP_PATH="/Applications/App名.app"
open "$APP_PATH"
```
shファイル実行 → 立ち上がればOK
```terminal
bash launch_app.sh
```

### セキュリティ設定
この時にファイルへのアクセス許可出しますか？と出た場合は、MacOSの設定を変更
> `システム設定 > セキュリティとプライバシー > フルディスクアクセス,ファイルとフォルダ`
>![スクリーンショット 2024-08-01 15.36.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616213/4d06cf8e-af73-e3dc-f68e-d90595d16259.png)


## 2. plistファイルを作成
後ほどファイルは移動させるので好きな場所に作って大丈夫！
### 展示用のplistファイル
```xml:com.user.startApp.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.startApp</string>
   <key>ProgramArguments</key>
   <array>
      <string>/path/to/launch_app.sh</string> <!-- あなたのpath -->
   </array>
   <key>RunAtLoad</key>
   <true/>
   <key>KeepAlive</key>
   <true/>
</dict>
</plist>
```
- `RunAtLoad`：デーモンがロードされた直後に実行。OS起動時に毎回ロードされるのでOS起動直後に実行される
- `KeepAlive`：デーモンプロセスが終了時に再起動する。つまり、アプリが落ちても常に再起動してくれる


## 3. plistファイルをLaunchDaemons配下に移動
>簡単に言うと、`LaunchDaemons` に入れておくと、ユーザーがログインしたタイミングでロードしてくれる。

- plistファイルを `/Library/LaunchDaemons/` にコピー
```terminal
sudo cp com.user.startPlayer.plist /Library/LaunchDaemons/
```
↓ここ
![スクリーンショット 2024-08-01 16.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616213/19f3e180-ea9f-6df7-7811-2b8ec4976266.png)


- 次に、plistファイルを読み込む
```terminal
sudo launchctl load /Library/LaunchDaemons/com.user.startPlayer.plist
```
何かエラー出た場合は下記でトラブルシューティングしていきましょう

## 4. トラブルシューティング

### plistファイルの検証
plistファイルのスペルチェック
```terminal
plutil -lint /Library/LaunchDaemons/com.user.startPlayer.plist
```

### ファイル権限の設定
権限周りが非常に面倒です。詳しく知りたい方は下記記事を参考にしてください。

https://qiita.com/ritumutaka/items/e74d2e1785c38dc265da

今回のケースの設定の仕方を記載します。
ターミナルで `ls -l` を打った時に出てくる権限が重要です
- NG例：`rw-rw-r--@ 1 user名 staff 843 6 26 18:05 hello.plist`
- OK例：`rw-r--r--@ 1 root staff 843 6 26 18:05 hello.plist`

ここで、 `root`, `rw-` 部分を権限変更します。
下記コマンドを打って、再度確かめてみてください。
```terminal
sudo chown root /Library/LaunchDaemons/com.user.startApp.plist
sudo chmod 644 /Library/LaunchDaemons/com.user.startApp.plist
```
## 5. 起動と停止

### 起動
起動したいときは、次のコマンドを使用
```terminal
sudo launchctl load /Library/LaunchDaemons/com.user.startApp.plist
```

### 停止
停止したいときは、次のコマンドを使用
```terminal
sudo launchctl unload /Library/LaunchDaemons/com.user.startApp.plist
```
### ジョブの確認
起動後にジョブがリストに登録されているか確認
```terminal
sudo launchctl list | grep com.user.startApp
```

## 追記：バックグラウンドで動かすアプリの設定
（これはもっと変なニーズになるのですが、）
やりたかったことは、同PC内で、制御アプリをバックグラウンドで動かしながら、最前面ではプレビューが動いてる状態を作ることです。

KeepAliveにはアプリの再起動と、最前面を保持する機能があります。
同PC内で2つのアプリをKeepAliveで管理すると、最前面を取り合ってしまいました。
常に片方をバックグラウンド、もう片方を最前面にするためのKeepAliveの設定方法について説明します。

このケースでは2つ、plistファイルを作る必要があります。最前面のplistファイルは上記のもので、下記はバックグラウンド用のplistファイルです。

### バックグラウンド用のplistファイル
```xml:com.user.startBGApp.plist
   <key>RunAtLoad</key>
   <true/>
   <key>KeepAlive</key>
   <dict>
      <key>SuccessfulExit</key>
      <false/>
   </dict>
```
`SuccessfulExit`： 
>値がtrueの場合、直前に終了した同ジョブのプロセスが正常終了(戻り値が0)の場合に限り、再起動を行うfalseの場合は逆に、正常終了以外の場合にのみ再起動を実施する

らしく、これで最前面に来ないで、クラッシュした時のみ再起動かけてくれるものになっています

## Macの設定

Mac側の設定部分は下記記事を見ていただければ完璧な設定が組めると思います。
起動/システム終了時間の設定やスクリーンセーバ、通知、passの自動ログインなど載っています。

https://leico.github.io/TechnicalNote/Mac/exhibit-check

## 終わりに
展示会用のアプリの自動起動からクラッシュ時の自動再起動まで記載しました。OSの自動起動設定と連携させれば、手のかからない、独り立ちした展示環境が作れるはずです！
変わったニーズではありますが、誰かの役に立てればいいなと思います。