macOS デプロイの落とし穴
微妙でデバッグが困難な問題を引き起こす macOS 固有のデプロイ上の問題
macOS デプロイの落とし穴
このページでは、Tauri の macOS デプロイにおいて最もフラストレーションの溜まるデバッグ問題を記録する。ビルド後に最新のコード変更が反映されない理由を探して何時間も費やしている場合、ほぼ確実にこれが原因である。
最大の落とし穴:cp -rf は .app バンドルに対して壊れている
Warning
既存の .app バンドルを上書きするために cp -rf を使用してはならない。必ず古い .app を削除してからコピーすること。
# 間違い - 内部のバイナリが古いまま残る cp - rf target/ release/ bundle/ macos/ MyApp. app / Applications/ # 正解 - 先に削除してからコピー rm - rf / Applications/ MyApp. app cp - r target/ release/ bundle/ macos/ MyApp. app / Applications/なぜこれが起こるのか
.app バンドルはディレクトリ構造である。
MyApp. app/
Contents/
MacOS/
MyApp <- - 実際のバイナリ
Resources/
. . .
Info. plist既存の .app の上に新しい .app を cp -rf すると、macOS の cp コマンドは予期しない動作をする。
新しいファイルと変更されたファイルを既存のディレクトリにコピーする
しかし、
Contents/MacOS/内のバイナリが置き換えられない場合がある。現在使用中であるか、カーネルにキャッシュされているか、特定のファイルフラグが設定されている場合に発生するその結果、
.appバンドルは新しく見える(新しいInfo.plist、新しいリソース)が、実際の実行ファイルは古いバージョンのままとなる
古いコードが新しいメタデータと共に実行される状態となり、非常に混乱する動作が発生する。変更が反映されず、ログには正しいバージョンが表示されるのに、動作が間違っているという状況に陥る。
正しい手順
常に以下の順序で実行すること。
# 1. Kill the running app (if any)
killall MyApp 2>/dev/null || true
# 2. Wait briefly for process to exit
sleep 1
# 3. Move old bundle away (not rm -- mv is atomic via rename())
mv /Applications/MyApp.app /tmp/MyApp-old-$$.app 2>/dev/null || true
# 4. Copy the fresh bundle
cp -R target/release/bundle/macos/MyApp.app /Applications/
# 5. Clear quarantine (targeted: only removes quarantine, not all xattrs)
xattr -dr com.apple.quarantine /Applications/MyApp.appNote
ステップ 3 は rm -rf ではなく mv を使用する。同じファイルシステム上では、mv は rename() を呼び出しアトミックに実行される -- 古いバンドルは部分的な状態を残さず一回の操作で消える。rm -rf は中断された場合に部分的に削除されたバンドルが残る可能性がある。
ステップ 5 は xattr -cr ではなく xattr -dr com.apple.quarantine を使用する。-dr フラグは検疫属性のみを再帰的に削除し、-cr はすべての拡張属性を削除する。ローカル開発では、対象を絞ったアプローチの方が安全である。
バイナリが最新であることの確認
インストール後、バイナリのタイムスタンプがビルドと一致していることを確認する。
# Check when the binary was last modified
stat -f "%Sm" /Applications/MyApp.app/Contents/MacOS/MyApp
# Compare with the source
stat -f "%Sm" target/release/bundle/macos/MyApp.app/Contents/MacOS/MyApp両方のタイムスタンプが同一(または数秒以内の差)であるべきである。/ のバイナリが古いタイムスタンプを持つ場合、コピーが正しく行われていない。
Tip
誤って cp -rf を使用しないよう、インストール手順をシェルエイリアスまたはスクリプトにしておくとよい。
# ~/ . zshrc install- tauri() { local app_ name= "${1: ? Usage: install- tauri AppName}" killall "$app_ name" 2>/ dev/ null || true sleep 1 mv "/ Applications/ ${app_ name}. app" "/ tmp/ ${app_ name}- old- $$. app" 2>/ dev/ null || true cp - R "target/ release/ bundle/ macos/ ${app_ name}. app" / Applications/ xattr - dr com. apple. quarantine "/ Applications/ ${app_ name}. app" echo "Installed ${app_ name}. app" }その他の macOS の問題
App Translocation
macOS は、特定の場所(ダウンロードフォルダなど)から初めて開かれたアプリを「トランスロケート」することがある。トランスロケーションはアプリをランダムな一時ディレクトリにコピーしてそこから実行するため、相対パスが壊れる。
検疫属性を xattr -cr でクリアすると、これを防止できる。
xattr -cr /Applications/MyApp.appLaunch Services キャッシュ
macOS はアプリ登録、ドキュメントタイプ、URL ハンドラ、アイコンを追跡するデータベース(Launch Services)を管理している。同じパスで .app バンドルを置き換えた場合、アプリの変更時刻が新しくないと自動的に再登録されないため、Launch Services が古いメタデータ(古いアイコン、古いドキュメントタイプ関連付け)を表示し続ける場合がある。
正しくインストールした後に Finder が古いアプリ情報を表示する場合:
# Force re-register the app
touch /Applications/MyApp.app
/System/Library/Frameworks/CoreServices.framework/Frameworks/\
LaunchServices.framework/Support/lsregister -f /Applications/MyApp.app
# Nuclear option: rebuild the entire Launch Services database
/System/Library/Frameworks/CoreServices.framework/Frameworks/\
LaunchServices.framework/Support/lsregister \
-kill -r -domain local -domain system -domain user
killall FinderNote
完全なデータベース再構築が必要になることは稀である。まず対象を絞った lsregister -f を試すこと。lsregister -kill -r はシステム全体のすべてのアプリ登録をリセットするため、再構築に時間がかかる場合がある。
コード署名の検証
.app バンドルを置き換えた後、コード署名が有効であることを確認できる:
# Verify code signature
codesign --verify --deep --strict --verbose=2 /Applications/MyApp.app
# Check Gatekeeper assessment (bypassing cache to get fresh result)
spctl --assess --type execute --verbose --ignore-cache /Applications/MyApp.app--ignore-cache なしで spctl が一貫性のない結果を返す場合、Gatekeeper の評価キャッシュが古くなっている。--ignore-cache フラグは新しい評価を強制する。
Gatekeeper の警告
署名されていないアプリは Gatekeeper の警告を発生させる。開発時には以下の方法で回避できる。
アプリを右クリックして「開く」を選択(ダブルクリックではなく)
または拡張属性をクリア:
xattr -cr / Applications/ MyApp. app
配布用には、Apple の開発者プログラムを通じてアプリの署名と公証を行う必要がある。
バイナリコード署名
開発時であっても、Tauri が作成した .app バンドル内のバイナリを作成後に変更すると、コード署名が無効になる。macOS がアプリの実行を拒否したり、「破損している」というエラーを表示することがある。
正しくインストールした後にこの問題が発生した場合は、以下を試すこと。
codesign --remove-signature /Applications/MyApp.app
xattr -cr /Applications/MyApp.appまとめチェックリスト
「変更が反映されない」と報告する前に、以下を確認すること。
コピー前に古い
.appをmvまたはrm -rfで削除したか?(cp -rfではない)実行中のアプリを
killallで終了させたか?ソースとインストール先のバイナリタイムスタンプは一致しているか?
xattr -dr com.apple.quarantineで検疫フラグをクリアしたか?フロントエンドアセットが実際に埋め込まれていることを確認したか?(Cargo キャッシュを参照)
Finder が古い情報を表示していないか?
lsregister -fでアプリを再登録してみること