メニューバーに常駐するアプリを開発するときは、Dockにアイコンを表示したくない場合が多い。Info.plistのLSUIElementがtrueのアプリは、Dockから隠れるエージェントアプリとして扱われる。
Xcodeでは、ターゲットのビルド設定INFOPLIST_KEY_LSUIElementをYESにする。
GENERATE_INFOPLIST_FILE = YES
INFOPLIST_KEY_LSUIElement = YES
INFOPLIST_KEY_LSUIElementが有効になるのは、GENERATE_INFOPLIST_FILE = YES(Info.plistを自動生成する設定)のときである。
実行例はXcode 27.0、macOS 27.0.1のもの。
ビルド設定でLSUIElementを設定する
Xcodeでは、ターゲットの「Build Settings」でUIElementを検索する。「Info.plist Values」の「Application is Agent (UIElement)」が、INFOPLIST_KEY_LSUIElementである。
INFOPLIST_KEY_LSUIElementに指定した値は、ビルド後のInfo.plistに、bool型のLSUIElementとして出力される。
INFOPLIST_KEY_LSUIElementの値 | 出力されるLSUIElement |
|---|---|
YES、true、1 | true |
NO、false | false |
| 設定しない | キーが出力されない |
ビルドしたアプリのInfo.plistは、plutilで確認できる。
$ plutil -extract LSUIElement raw [アプリ名].app/Contents/Info.plist
true
ビルド設定の値は、xcodebuild -showBuildSettingsで確認できる。
$ xcodebuild -project [プロジェクト名].xcodeproj -scheme [スキーム名] -showBuildSettings 2>/dev/null | grep -E "^\s+(GENERATE_INFOPLIST_FILE|INFOPLIST_KEY_LSUIElement) ="
GENERATE_INFOPLIST_FILE = YES
INFOPLIST_KEY_LSUIElement = YES
参考: 【xcodebuild】MACOSX_DEPLOYMENT_TARGETの優先関係を-showBuildSettingsで確認する
Dockに表示されないことを確認する
LSUIElementがtrueのアプリは、UIElementの種類のアプリとして扱われる。Appleのドキュメントでは、バックグラウンドで実行され、Dockには表示されないエージェントアプリと説明されている。
参考: LSUIElement | Apple Developer Documentation
アプリの種類は、lsappinfoで確認できる。open -gでアプリをバックグラウンドで起動し、バンドルIDを指定する。
$ open -g [アプリ名].app
$ lsappinfo info -only applicationType -app [バンドルID] | grep -o 'type="[A-Za-z]*"'
type="UIElement"
LSUIElementを設定していないアプリは、Foregroundになる。Foregroundのアプリは、起動するとDockにアイコンが表示される。
$ lsappinfo info -only applicationType -app [バンドルID] | grep -o 'type="[A-Za-z]*"'
type="Foreground"
手書きのInfo.plistと併用する
SparkleのSUFeedURLのように、INFOPLIST_KEY_のビルド設定が用意されていないキーは、INFOPLIST_KEY_では設定できない。このようなキーは、手書きのInfo.plistをINFOPLIST_FILEに指定して設定する。GENERATE_INFOPLIST_FILE = YESのままであれば、自動生成される内容と、手書きのInfo.plistの内容がマージされる。
参考: 【Sparkle】SwiftPMで導入してアプリに更新チェックを組み込む
手書きのInfo.plistとINFOPLIST_KEY_LSUIElementの両方に、LSUIElementを設定した場合の結果は次のとおりである。
GENERATE_INFOPLIST_FILE | 手書きのInfo.plistのLSUIElement | INFOPLIST_KEY_LSUIElement | ビルド後のLSUIElement |
|---|---|---|---|
YES | なし | YES | true |
YES | true | なし | true |
YES | false | なし | false |
YES | false | YES | true |
YES | true | NO | false |
NO | false | YES | false |
両方に設定すると、INFOPLIST_KEY_LSUIElementの値が優先される。手書きのInfo.plistにだけ設定した場合は、その値が、ビルド後のInfo.plistに残る。
GENERATE_INFOPLIST_FILE = NOのときは、INFOPLIST_KEY_LSUIElementが無視される。手書きのInfo.plistの値が、そのまま使われる。
GENERATE_INFOPLIST_FILE = NOで、INFOPLIST_FILEも指定しないと、ビルドに失敗する。
error: Build input file cannot be found: '[ビルド成果物のパス]/[アプリ名].app/Contents/Info.plist'. Did you forget to declare this file as an output of a script phase or custom build rule which produces it?
どちらの方法を選ぶか
LSUIElementは、INFOPLIST_KEY_LSUIElementが用意されているキーである。ビルド設定だけで済み、手書きのInfo.plistを用意しなくてよい。
Sparkleの設定のように、手書きのInfo.plistが必要なプロジェクトでも、LSUIElementはINFOPLIST_KEY_LSUIElementに設定できる。ただし、同じキーを両方に設定すると、手書きのInfo.plistの値が使われなくなる。どちらか一方に統一すると、設定を確認しやすい。
手書きのInfo.plistを使う場合は、PlistBuddyで値を確認できる。
$ /usr/libexec/PlistBuddy -c "Print :LSUIElement" Info.plist
true
参考: 【PlistBuddy】Info.plistの値をコマンドで読み書きする
