macOS application 的三種運行模式

平時,你不會遇到這個問題,直到你需要寫一個後台程序……

我們都知道 macOS 有一個全局的 Dock,這個東西上會顯示所有正在運行的程序,但如果你的程序是一個菜單欄小程序,或者是一個……輸入法,那你肯定不想讓這個 app 的圖標顯示的 Dock 上,因為這類 app 是要持續在後台運行的。

這時候我們就可以在 Info.plist 中寫 LSBackgroundOnly 字段,這樣這個 app 就會在後台運行,沒有 Dock 圖標,也不會在 cmd+tab 的切換選項中顯示出來了。落格輸入法就是這麼做的,這也是蘋果官方示例中的配置——但這麼做長久以來伴隨著一個問題,那就是如果你這個 app 還是需要顯示必要的設置界面的話,那這個界面會永遠在所有窗口的最下方,也就是說,窗口一彈出就立即被擋住了。甚至,除了標準窗口,其他任何警告彈窗,都是無法顯示的,除非先有一個標準窗口出現,且用戶點擊了一下該窗口的任何位置……

上文這些前提導致了很多問題,我不得不內嵌另外一個 app 來作為落格輸入法的專門設置軟件,然後兩者之間使用 xpc 通信,真的是令人絕望。

直到今天 TIL,我發現原來可以使用 NS應用程序.共享.設置激活策略(.配飾) 在程序中動態改變自己的運行級別,可以動態修改自己為普通 常規的 模式,或者是後台 禁止 模式。顯然,通過看代碼名稱也明白了,原來這個後台模式,是故意不允許彈出窗口的。

顯然,如果你聲明程序是後台程序,那它的一切窗口都是不能獲得焦點的,這個問題我一直以來以為是 macOS 的Bug😅

那麼,有沒有別的方案呢?還真的有,除了上文的兩種模式外,macOS 其實還提供了介於兩者中間的模式,既像後台程序那樣不顯示圖標,又能在必要的時候獲取焦點和類似普通程序那樣彈窗:

在必要的時候動態切換程序的運行模式為 配飾 即可。


當然,如果用代碼太麻煩,我們也可以直接改 Info.plist,把 LSBackgroundOnly ,改為 LSUIE元素 ,即可。

本文由 落格博客 原創撰寫:落格博客 » macOS application 的三種運行模式

轉載請保留出處和原文鏈接:https://www.logcg.com/archives/3531.html

關於作者

R0uter

如非聲明,本人所著文章均為原創手打,轉載請註明本頁面鏈接和我的名字。

註釋

  1. 博主您好 我現在遇到了這個問題:正常的邏輯是,我點擊主界面窗口的關閉按鈕,然後DOCK消失,但是彈出一個新窗口,提示進入後台運行。使用了NSApplication.sharedApplication().設置激活策略(0x1),但是這串代碼執行之後,我所有的窗口都不見了,請問如何解決。
    我使用的是JAVA的SWT框架。

    1. 我沒用過 SWT 框架,不過你試試用alert代替窗口,或者設置窗口為固定最前,就那個popup級別。理論上不應該出現這個情況。
      另外你檢查一下傳入 0x1 是否正確,這個我不確定 SWT 如何轉換傳值的,有可能轉成了無法識別的值於是出現意外行為。

      1. 目前在M1處理器 13.1上不會出現問題,在intel 10.15.7版本上,我先執行setActivationPolicy(0x1),然後彈窗(就是一個窗口),出現後立馬消失。然後我循環判斷setActivationPolicy(0x1)的返回值,當返回值為true的時候,彈窗將正常。是不是因為setActivationPolicy(0x1)底層是多線程,導致他在我彈窗生成後才執行。(但是即使是這樣,應該也是將彈窗置於最下面,而不是直接一閃而過)

          1. 有一個思路就監測app運行狀態,比如進入後台之類的?或者看看獲取這個狀態的API的結果,生效後再彈窗就是了。雖然我搞清楚了這個情況,後來由於其他原因,我並沒有用到,我的輸入法設置窗口還是使用了單獨的app實現的。

          2. 感謝您的解答,您的這個思路確實有效。但是我有一個疑問,監測APP狀態的時候,有沒有可能,app已經關閉了,但是setActivationPolicy還沒有執行完畢(目前沒有遇到)。那麼我判斷app狀態是關閉的時候,打開了彈窗,隨後setActivationPolicy執行,那麼我的彈窗將再次被其關閉。
            所以我新開了一個線程,判斷setActivationPolicy的返回值是不是true,是的話,說明他執行結束了,我就打開彈窗。這樣我的彈窗將一直在setActivationPolicy後執行,不會被關閉。
            還有一個疑問就是,我不知道為什麼在我的程序中,執行setActivationPolicy(1)後,會關閉我所有的窗口,他的效果不應該是關閉DOCK,並且將所有窗口置於最下面嗎?

          3. 是隱藏……他只是不顯示了,並不是給你關閉了。
            另外設置為1是既隱藏又允許顯示,所以窗口的開關只能你自己控制。
            你這個情況🤔我也不清楚,抱歉了哈。

發表評論

您的電子郵件地址不會被公開. 必填字段標 *