冷启动 “结束” 的主流落点
结束时间点 | 常用场景 | 精度 | 采集方式示例 | 说明 |
---|---|---|---|---|
首帧渲染完成(Time‑to‑First‑Draw) | Apple 官方度量(Xcode Instruments「App Launch」模板、MetricKit、XCTApplicationLaunchMetric ) | ★★★★☆ | 在根 UIViewController 的 viewDidAppear: 或 SwiftUI onAppear {} 中打点 | 代表用户“第一次看到界面”,符合 Apple “从点按图标到第一帧绘制” 的定义 citeturn3search0turn3search1 |
applicationDidBecomeActive: / scenePhase == .active | 大多数 APM SDK(Firebase Perf、Blue Triangle SDK 等) | ★★★☆☆ | 监听 UIApplicationDidBecomeActiveNotification 或 @Environment(\.scenePhase) | 生命周期已走完,主循环开始处理事件;和首帧差几个 runloop,但埋点简单稳健 citeturn0search9 |
首交互可用(First‑Interaction) | 游戏、重模板 App | ★★★★★ | 在 UI 线程上插入 CADisplayLink ,等待第一次 touchesBegan: | 确保真正可操作;成本高,除非业务必须 |
application:didFinishLaunching 返回 | 早期统计、兼容旧代码 | ★★☆☆☆ | 在 didFinishLaunching 尾部打点 | 只能说明系统和 AppDelegate 初始化结束,距离首帧仍有 UI 构建与渲染时间,不再推荐 |
该选哪一个?
-
对齐 Apple 官方、与 Xcode/MetricKit 报表一致
→ 选首帧渲染完成(Time‑to‑First‑Draw)。这是 Apple 定义冷启动的正式终点,也是用户感知最直观的时间点。 citeturn3search1 -
想快速接入、对误差容忍度高
→ 选applicationDidBecomeActive:
。它比首帧晚数毫秒到几十毫秒,绝大多数业务能接受,且在所有框架(UIKit / SwiftUI / React‑Native)都易于监听。 -
App 需要真正“可点击”再算启动完成(如大型游戏、重 Web 容器)
→ 用 首交互可用,但要写自定义逻辑收集——成本最高。
实战落点建议
// Objective‑C 示例:记录 Time‑to‑First‑Draw
@interface RootViewController : UIViewController
@end@implementation RootViewController
- (void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{uint64_t ttd = mach_absolute_time() - g_appStartTime; // g_appStartTime 在 main() 里记录[APMLogger recordColdLaunchTTD:ttd];});
}
@end
- 不侵入业务:
dispatch_once
保证只记录冷启动那一次。 - 对齐官方:
viewDidAppear:
触发时,系统已提交第一帧到 Core Animation,和 Apple 定义一致。 - SwiftUI 可在
@main
App 的WindowGroup { ContentView() } .onAppear { … }
中同理处理。
总结一句话
“iOS 冷启动”官方结束点是 “第一帧成功绘制”;
若想实现简易但相对准确的埋点,可退而求其次选applicationDidBecomeActive:
。