←→ Underneath: Background Apps · 所有 Mac 指南
為什麼 Mac 重新開機後 App 又回來了
你結束了它,甚至在活動監視器中強制結束了它。兩秒後,或是下次重新開機後,它又在執行了。有東西刻意在啟動它。在 Mac 上,這個東西幾乎總是 launchd。
簡短回答:這個 App 有一個 launchd 工作。RunAtLoad 會在每次登入時啟動它,KeepAlive 則會在它停止時再次啟動它。結束程序並不會改變工作。若要永久停止,請停用工作,而不是程序。
launchd 是什麼
launchd 是 macOS 啟動的第一個程序(程序 ID 1),幾乎其他所有東西都是由它啟動的。它會讀取小小的 .plist 檔案,這些檔案稱為工作,說明要執行什麼以及何時執行。每個工作都有一個標籤,也就是像 com.google.keystone.agent 這樣的唯一名稱。
App 會把工作安裝在 ~/Library/LaunchAgents、/Library/LaunchAgents 或 /Library/LaunchDaemons 中,或從自己的 App 套件內註冊。
讓 App 回來的鍵
以下是一個典型的啟動代理程式:
<key>Label</key>
<string>com.example.helper</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Example.app/Contents/MacOS/Helper</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
| 鍵 | 效果 | 你會看到 |
|---|---|---|
RunAtLoad | 工作一載入就啟動,也就是每次登入時(代理程式)或開機時(常駐程式) | 每次重新開機後它都在 |
KeepAlive = true | 程序每次結束時都重新啟動它 | 強制結束沒有用;幾秒內它就回來了 |
KeepAlive 附條件 | 只在某些情況下重新啟動,例如當機後(SuccessfulExit = false)或網路連線期間 | 它有時會回來,但不是每次 |
StartInterval | 每 N 秒執行一次 | 它出現、短暫執行、消失,然後重複 |
StartCalendarInterval | 像 cron 一樣在設定的時間執行 | 它每天在同一時間出現 |
WatchPaths | 在檔案或檔案夾變更時執行 | 它在你做了不相關的事之後出現 |
對於不斷結束的工作,launchd 會在每次重新啟動之間等待約 10 秒,因此 KeepAlive 工作看起來也可能像是在「閃爍」。
App 回來的其他原因
- 登入時打開。App 位於系統設定 › 一般 › 登入項目與延伸功能中。macOS 每次登入時都會打開它。
- 再次登入時重新打開視窗。「重新開機」和「關機」對話框中的這個勾選框,會還原所有原本打開的 App。
- App 把自己加回去。它自己的「登入時啟動」設定每次執行時都會重新註冊它。
- 輔助程式打開主 App。一個小小的背景輔助程式先啟動,然後打開完整的 App,例如為了顯示同步狀態。
- Homebrew 服務。
brew services start會寫入一個帶有RunAtLoad的啟動代理程式。請用brew services stop <name>停止它。
找出是哪一個
- 找出工作標籤。使用 App 或開發者名稱的一部分執行
launchctl list | grep -i example。第三欄就是標籤。 - 讀取工作內容:
查看launchctl print gui/$(id -u)/com.example.helperpath(plist 檔案)、state、runs(啟動了幾次)和last exit code。啟動次數很高通常代表KeepAlive。 - 打開 plist,檢查
RunAtLoad、KeepAlive和間隔相關的鍵。 - 如果沒有工作,請檢查「登入時打開」和 App 本身的設定。
停止與停用的差別
| 你的操作 | 會回來嗎? |
|---|---|
| 結束或強制結束程序 | 會:若有 KeepAlive 會立刻回來,若有 RunAtLoad 則在下次登入時 |
launchctl bootout gui/$(id -u)/label | 現在不會。若有 RunAtLoad,下次登入時會 |
launchctl disable gui/$(id -u)/label + bootout | 不會,直到你執行 launchctl enable |
| 將 plist 移出 LaunchAgents + bootout | 不會,直到你把它移回去 |
| 在「允許在背景執行」中關閉 | 不會,直到你重新打開 |
逐步指令請見如何安全地停用啟動代理程式。
常見問題
為什麼我在活動監視器中結束程序後,它馬上又重新啟動?
因為它的 launchd 工作設定了 KeepAlive。launchd 會監看該程序,在它結束時再次啟動它。請用 launchctl bootout 停止該工作,而不是結束程序。
RunAtLoad 是什麼意思?
RunAtLoad 是 launchd plist 中的一個鍵。當它為 true 時,launchd 一載入 plist 就會啟動工作;對啟動代理程式來說,就是每次登入時都會啟動。
KeepAlive 是什麼意思?
KeepAlive 會要求 launchd 讓工作持續執行。如果程序結束或被終止,launchd 會再次啟動它。它也可以是一組條件,例如只在當機後重新啟動。
停止和停用啟動代理程式有什麼差別?
停止(launchctl bootout)會卸載工作,直到下次登入或重新開機。停用(launchctl disable,或將 plist 移出 LaunchAgents)則會讓它在重新開機後不再被載入。