讲讲 iOS 中鲜为人知的"预热启动"

这里每天分享一个 iOS 的新知识,快来关注我吧

启动类型

在 iOS 上,我们都清楚启动类型分为"热启动"和"冷启动"。

按照苹果的定义,如果你打开 App 后滑回到主屏幕并手动杀掉程序,然后立即重新打开 App,这种启动方式通常称为"热启动"。

如果你刚刚玩了一款需要使用大量内存的游戏,你的 App 可能会被系统杀掉,并清空你的 App 所占用的内存,以允许这个游戏拥有更多内存。然后你再次进入你的应用,那么它可能会比你的平均启动速度慢得多。你的应用程序所依赖的框架和进程也可能需要重新启动和从磁盘分页。这种情况,或者在手机重启后的启动,通常被称为冷启动。

还有一种严格意义上说不叫启动,就是从后台到前台,打开 App 后,先退到后台,再点击图标打开,这种情况一般称为"恢复"(resume)。

按照 WWDC 的这张图,可以很生动的看出,冷启动像乌龟速度最慢,热启动像兔子,速度次之,恢复像豹子,速度最快。

iOS 15 新增的启动类型

在 iOS 15 及更高版本中,系统会学习用户习惯,比如你几点经常打开某个 App,为了让你启动速度更快,在你打开之前,系统会先帮你把这个 App 进程启动并加入内存中,这就是苹果新增的一种启动类型,Prewarming Launch(预热启动)

按照苹果的文档,预热会启动 App 进程,直到(但不包括),main() 调用 UIApplicationMain。但是经过我的测试,预热启动不但会调用到 main 函数,甚至有时候会调用到 Appdelegate 中的 application(:, didFinishLaunchingWithOptions:) 方法。因此苹果的文档是不准确的(也可能是个 bug)。

预热启动带来的问题

虽然预热启动可以让启动速度更快,这的确提升了用户体验,但同时也带来了一些问题。

比如市面上很多 APM 工具,例如 FirebaseSentry 等,统计启动时间都是从进程启动到第一个页面展示出来,如果这次启动是预热启动,那么就可能导致启动时间出现非常大的误差,比如进程启动时间为早上 8 点,可能用户晚上 8 点才启动 App。

另一个问题是预热启动下有些 API 是无法正常调用的,比如钥匙串相关的 API 就无法正常调用,正如前面所说,预热启动下可能会走到 application(:, didFinishLaunchingWithOptions:) 方法,也就是说在这个方法调用的时候,之前所有访问钥匙串的代码可能都是无效的,比如你在 +load() 方法里访问了不能访问的 API,就会导致非预期的结果发生。

解决方案

这时候大家可能会想,如果可以知道这次启动是否为预热启动就好了,但是苹果并未提供相关的 API,但是国外有个 iOS 开发小哥发现苹果在环境变量中增加了一个名为"ActivePrewarm" 的字段来标记是否为预热启动,那么我们就可以顺利使用这个标记来知道是否为预热启动了:

bash 复制代码
if ProcessInfo.processInfo.environment["ActivePrewarm"] == "1" {
    print("本次启动为预热启动")
} else {
    print("本次启动为非预热启动")
}

可以尝试通过以下步骤测试预热启动:

  1. 启动你的 App

  2. 简单使用一会儿

  3. 强制退出 App

  4. 锁定设备,放置大概约 30 分钟

  5. 解锁设备

  6. 再次启动应用程序

以上步骤有概率复现预热启动的情况。

然后就可以根据是否为预热启动来分别解决上边提到的问题,衡量启动时间的时候可以把预热启动的情况过滤掉。

如果为预热启动,把无法正常调用的 API 放到启动成功之后。

这里每天分享一个 iOS 的新知识,快来关注我吧

本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

相关推荐
往来凡尘9 小时前
Flutter运行iOS26真机的两个问题
flutter·ios
方白羽10 小时前
Android 中Flags从源码到实践
android·app·客户端
普通网友11 小时前
Objective-C 类的方法重载与重写:区别与正确使用场景
开发语言·ios·objective-c
denggun1234513 小时前
卡顿监测原理
macos·ios·xcode
@大迁世界16 小时前
iOS 26.2 引入三种全新 iPhone 自定义方式
ios·iphone
Sheffi6616 小时前
iOS 触摸事件完整传递链路:Hit-Test 全流程深度解析
macos·ios·cocoa
Swift社区18 小时前
用 Task Local Values 构建 Swift 里的依赖容器:一种更轻量的依赖注入思路
开发语言·ios·swift
2501_9159090618 小时前
苹果应用加密方案的一种方法,在没有源码的前提下,如何处理 IPA 的安全问题
android·安全·ios·小程序·uni-app·iphone·webview
TouchWorld18 小时前
iOS逆向-哔哩哔哩增加3倍速播放(4)- 竖屏视频·全屏播放场景
ios·swift