問題現象:Xcode 正常,冷啟動閃退
最近在開發 Flutter iOS App 時遇到一個詭異的問題:透過 Xcode 按下 Run 按鈕啟動 App 完全正常,但當我停止 Debugger、從多工畫面滑掉 App、再從主畫面點擊圖示重新開啟時,App 只顯示 Launch Screen 就立刻閃退。
這個問題讓我走了不少彎路,最後發現答案簡單得令人意外。
誤導方向:UIScene 與 Plugin 註冊
由於 Xcode 26 開始顯示 UIScene lifecycle will soon be required 警告,我最初懷疑是 UIScene 遷移不完整導致的問題。接著又懷疑是 Plugin 註冊的 race condition,甚至在 GeneratedPluginRegistrant.m 中加入大量 debug log 來追蹤每個 Plugin 的註冊狀態。
嘗試過的「修復」包括:
- 完整實作
SceneDelegate與FlutterSceneDelegate - 在 Flutter Engine 初始化前加入 0.5 秒延遲
- 逐一排除可能有問題的 Plugin
這些方向全部是錯的。
找到根本原因:iOS Console Log
關鍵轉折點是查看 iOS 的 Console log。使用 Xcode 的 Devices and Simulators > Open Console 或 macOS 的 Console.app 連接 iPhone,重現冷啟動閃退後,看到了這段關鍵訊息:
[ERROR:flutter/runtime/ptrace_check.cc(75)] Could not call ptrace(PT_TRACE_ME): Operation not permitted
Cannot create a FlutterEngine instance in debug mode without Flutter tooling or Xcode.
To launch in debug mode in iOS 14+, run flutter run from Flutter tools,
run from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.
Alternatively profile and release mode apps can be launched from the home screen.
真相大白:這根本不是程式碼問題,而是 iOS 14+ 的安全機制。
技術原理:ptrace 與 Debug 模式
為什麼 Debug 模式需要 Debugger?
iOS 14 開始,Apple 強化了 ptrace 系統呼叫的權限控制。ptrace 是 Unix 系統用於程序追蹤和除錯的機制,Debug 模式的 Flutter App 依賴它來實現:
- Hot Reload / Hot Restart:即時更新程式碼
- Dart VM 連接:與 Flutter DevTools 通訊
- 斷點除錯:暫停執行、檢查變數
當 App 嘗試呼叫 ptrace(PT_TRACE_ME) 但沒有 Debugger 連接時,iOS 會拒絕這個請求並終止 App。
不同建置模式的差異
| 建置模式 | 執行方式 | ptrace 需求 | 可獨立運行 |
|---|---|---|---|
| Debug | JIT 編譯 | 需要 | ❌ |
| Profile | AOT 編譯 + 效能追蹤 | 不需要 | ✅ |
| Release | AOT 編譯 + 最佳化 | 不需要 | ✅ |
Debug 模式使用 JIT(Just-In-Time)編譯,需要 Dart VM 持續運行並與開發工具通訊。Release 模式則是 AOT(Ahead-Of-Time)編譯成原生機器碼,完全不需要 Dart VM。
解決方案:使用 Release 模式
如果需要在沒有 Xcode 連接的情況下測試 App(例如給 QA 測試或自己日常使用),必須使用 Release 模式建置:
# 建置 Release 版本
flutter build ios --release
# 或使用 Profile 模式(保留部分除錯資訊)
flutter build ios --profile
建置完成後,可以透過 Xcode 安裝到裝置:
# 使用 devicectl 安裝(Xcode 15+)
xcrun devicectl device install app \
--device <device-id> \
build/ios/iphoneos/Runner.app
為什麼容易踩到這個坑?
這個問題之所以難以發現,是因為開發流程中的盲點:
- 開發時總是透過 Xcode 或
flutter run啟動:Debugger 自動連接,問題不會發生 - 測試時也是如此:很少有人會特意停止 Debugger 後再測試冷啟動
- 錯誤訊息不會出現在 Xcode Console:必須查看 iOS 系統 Console 才看得到
經驗法則:當 iOS App 出現「Xcode 正常但獨立運行異常」的情況,第一步應該查看 iOS Console log,而不是猜測程式碼問題。
結論
| 問題 | 答案 |
|---|---|
| 為什麼要用 Release 模式? | iOS 14+ 的 ptrace 安全限制,Debug 模式必須有 Debugger 連接 |
| 不這樣做會怎樣? | 每次冷啟動都會閃退,只能透過 Xcode 啟動 |
| 未來如何避免? | 分發測試版本時一律使用 Release 或 Profile 模式 |
這個問題的答案雖然簡單,但診斷過程卻充滿了誤導。記住:Flutter Debug build 在 iOS 上無法獨立運行,這是設計如此,不是 bug。
