- macOSアプリケーションは、コマンドラインプログラムより複雑な構成要素を持ち、ウインドウやメニューなどのインターフェース資源を別構造で管理する
- Classic Mac OSでは実行コードとリソースがファイルのリソースフォークに保存されていたが、Mac OS Xからはバンドル(bundle) 構造へ移行した
- アプリバンドルはContentsディレクトリを中心に、MacOS・Resources・Frameworks などのサブフォルダと、Info.plist のような中核ファイルで構成される
- その後、コード署名・App Storeレシート・公証(notarization) などが追加され、セキュリティと完全性を強化した構造へ発展した
- このような自己完結型(app bundle)構造は、インストール・更新・削除を単純化し、セキュリティ性と保守効率を高める中核基盤となっている
Classic Mac OSのアプリ構造
- 初期のMac OSでは、ウインドウやメニューなどのUIリソースを実行ファイルと分離し、リソースフォーク(resource fork) に保存していた
- 例として、QuarkXPress 4.11 のリソースが ResEdit で表示される
- 実行コードは CODEリソースに含まれ、Finderが認識できるよう ファイルタイプ(type)とクリエータ(creator) 情報もあわせて保存された
Mac OS Xのバンドル構造
- Mac OS Xは、NeXTSTEPに由来するバンドル(bundle) 構造を導入した
- アプリは
.app 拡張子を持つディレクトリ形式で、内部に Contents フォルダを含む
- MacOSフォルダにはGUIアプリの実行ファイルとコマンドラインツールが含まれる
- Resourcesフォルダにはアプリアイコン、GUI構成要素などのリソースファイルが保存される
- 一部のアプリは Frameworksフォルダを含み、dylib(動的ライブラリ) を内包する
- Info.plist ファイルは必須で、実行ファイル名、アイコン、最小macOSバージョン、文書タイプ、バージョン番号などを定義する
- PkgInfo ファイルはClassic Mac OSのタイプ・クリエータ情報を維持するが、必須ではない
- アプリ実行時には launchd が実行コードを開始し、LaunchServices と RunningBoard が Info.plist 情報に基づいて初期化手順を実行する
macOSにおけるセキュリティと拡張
- Mac OS X 10.5 Leopard(2007) から コード署名(Code Signature) が導入され、
_CodeSignature フォルダが追加された
- CodeResourcesファイルにはコードディレクトリハッシュ(CDHash)が含まれ、アプリの完全性を検証する
- App Store配布アプリは
_MASReceipt フォルダに ストアレシートを含む
- 2018年以降は 公証(notarization) が導入され、Appleが発行した チケット(ticket) を CodeResourcesファイルへバンドルに「ステープル(staple)」できる
- 現代のアプリバンドルは、過去にはシステムフォルダへインストールされていた構成要素を自前で含む
- Libraryフォルダ: LaunchDaemons、LoginItems など
- XPCServicesフォルダ: アプリが使用する別実行サービス
- Plugins / Extensionsフォルダ: アプリ拡張機能および App Intents を含む
- 一部のアプリには version.plist ファイルも存在する
アプリバンドルの利点
- すべての構成要素をバンドル内部に統合することで、インストール・更新・削除が容易になる
- 構成要素の欠落可能性が減り、署名と公証による保護を通じてセキュリティ性が強化される
- App Storeアプリは追加でレシートと公証チケットを含み、信頼性を確保する
- IntelとArmアーキテクチャ間で構造差はなく、Mach-O実行ファイルが両プラットフォーム向けコードをすべて含むユニバーサル(fat)バイナリ形式で保存される
- 同一ファイル内に各アーキテクチャ別の署名(signature) もあわせて存在する
アプリ構造の視覚的概要
- ダイアグラムでは淡い黄色が必須、またはほぼすべてのアプリに存在する構成要素を示す
- 緑色はApp Store配布アプリのみに存在する項目、青色は任意の公証チケットを意味する
- 追加でAutomatorワークフロー、スクリプトなどの付加要素が含まれることもある
- 全体として、macOSアプリは自己完結型・セキュリティ重視の構造へと進化してきた
1件のコメント
Hacker Newsの意見
青で示されている部分は notarisation ticket(公証チケット)だが、実質的には任意ではない。
公証されていないアプリはユーザーにとって不便すぎるため、結局は年額99ドルの Apple Developer Program 登録料を払うことになる。
個人用にビルドして実行するだけなら問題ないが、配布用だと macOS が警告ダイアログを表示し、アプリが壊れているかのように見える。
以前は右クリックで実行できたが、今ではシステム設定まで入って許可しなければならない。
関連スクリーンショットは Appleサポート文書 と Developer News で見られる。
私は Apple のセキュリティ思想は好きだが、App Store外アプリの公証制度 はすべての当事者にとって損だと思う。
実際に公証がセキュリティ問題を防いだ事例は見つけられなかった。
macOS の公証は面倒だと思っていたが、Windows 配布をやってみると、あれはさらにひどかった。
Windows Defender の信頼を得るには証明書を買う必要があり、企業も個人も 厳格な本人確認 を通らなければならない。
ハードウェアトークンで署名しなければならないため、リリースを配布できるのは1人だけになる。
しかも認証局が任意に鍵をロックすることもあり得るので、セキュリティパッチを出さなければならない時に止められたら悲惨だ。
その点では macOS エコシステムの方がずっとましだと感じる。
私は複数プラットフォームにコンパイルされる プログラミング言語 を開発中だが、署名と公証はこの流れにまったく合っていない。
こうした署名制度は 統制の手段 にすぎず、Epic の事例のように乱用されるリスクがある。
署名されていないバイナリを合理的に実行できないなら、そのプラットフォームは閉じていると見なし、サポートしない。
iOS や Android のような閉鎖的プラットフォームは PWA である程度代替できる。
ただし Google が自己署名アプリの実行を今後も許し続けるかについては、信頼が薄れている。
Apple が App Store外アプリの証明書を取り消した事例は2件しか知らない。
1つは Facebook の Research App、もう1つは Google の Screenwise Meter だった。
どちらも未成年を対象にしたスパイウェア的なアプリで、証明書取り消しによって社内ツールまで麻痺した。
その後 Screenwise Meter は App Store に再掲載されたようだ。
関連記事: Wired, EFF
私のアプリフォルダの半分くらいは公証されていないが、実際には 特に問題ない。
公証後の stapled ticket(添付チケット)は任意だ。
チケットを添付しない場合、ユーザーはインターネット接続を通じて公証状態を確認する必要がある。
AppBundler.jl を開発しながら、macOS アプリの構造には不満が多い。
Frameworks フォルダ構造の強制 は見た目にはきれいだが、実際にはバンドル作業が煩雑なので Libraries フォルダで回避している。
最大の問題は コード署名 だ。すべてのバイナリに署名を付けるのは無駄に感じる。
ファイルハッシュを集めて一度だけ署名すれば済むことを、なぜこんなに複雑にするのか理解しがたい。
また entitlements がランチャーバイナリにしか付かないのも非効率だ。
公証基準は時間とともに厳しくなるため、後になって突然アプリが通らなくなる可能性もある。
Tauri アプリを署名・公証しようとして Apple Developer Program に加入したが、3週間ずっと失敗中だ。
Mac がないので GitHub Actions で試したが、最初の公証には時間がかかることがよくあるらしい。
GitHub の費用だけで100ドル近く使ったのに、まだ公証できていない。
Apple サポートは、Mac がなく Tauri を使っているという理由で支援を拒否した。
公証 API の認証プロセス も悪夢レベルだ。PKCS8 で JWT を作らなければならないのに、文書がほとんどなく、自分で Node プログラムを書くしかなかった。
これまでで最悪の 開発者体験(DX) だった。
Apple ハードウェアなしでこれを解決しようとするのは 時間の無駄 だという。
最初の OS スクリーンショットを見て、ひやりとした。
昔は 実用的ですっきりした UI だったのに、今は角が丸く泡のようなアイコンになって、空間を無駄にしている。
それでも Mac のハードウェア品質が高いので、ThinkPad には移れずにいる。
角の丸みはむしろ 人間の視覚に有利な機能 だ。
角ばった形状が視覚疲労を引き起こすという研究がある。
関連記事: Round Rects Are Everywhere
私も最新の macOS はあまり好きではないが、そのスクリーンショットも完璧ではない。
線が多すぎて色が足りず、視線が散る。
個人的には Leopard 時代の Aqua UI が情報密度と視覚的な奥行きのバランスが良かった。
ピクセル比で見れば、昔の UI の方がむしろ空間を多く使っている。
5K 解像度基準では、現代の MacBook Pro の方が効率的だ。
クラシック Mac もすでに少し丸い角を持っていた。
参考: Infinite Mac
コンピュータは仕事用だけでなく、楽しむための道具 でもある。
ただ最近の UI は実用性から離れすぎている感じがする。
画面の大半が 101101 のような無意味な情報なので、実用的とは言いがたい。
macOS でコマンドラインツールを実行する際に launchd が実行主体だという話は誤りだ。
実際には他の UNIX システムと同様に、シェルから fork/spawn で実行される。
NeXTSTEP のバンドルシステムは Java の JAR ファイル 設計に影響を与えた。
クラシック Mac OS の Power Mac アプリでは、PPC コードはデータフォークに保存 されていた。
CFM-68K バイナリも同様で、CODE リソースを使っていたのは旧来の 68K コードだけだった。
昔 ResEdit でアプリをいじっていた頃が楽しかったのを覚えている。
最後の図のように 官僚主義が爆発 しているのは良い兆候ではない。
macOS 26 に「アップグレード」する理由がさらに減る。
今の構造が macOS の「標準」ではあるが、唯一の方法ではない。
RPATH をうまく設定すれば、任意のサブフォルダにライブラリを入れても公証を通せる。
たとえば AppName.App/Contents/Libraries というパスでも動作する。
ただしこの方式の実質的な利点はほとんどなく、私のシステムにある100個あまりのアプリのうち /Libraries フォルダを使っているものは1つもない。
.dylib ではなく必ず .framework 形式を使わなければならず、これは文書化されていないルールだ。
提出時に自動検出されてリジェクトされることがある。