苹果在WWDC2019专题单元讨论了APP启动----- Optimizing App Launch
https://developer.apple.com/videos/play/wwdc2019/423/
本次讨论有几大亮点:
- dyld3终于来了;
- Instruments 新增 App Launch 功能,可精准测量APP启动的各个环节的耗时;
- XCTest新增了app启动测量的API;
- MetricKit is coming,苹果完成了各种性能监控的大一统。
第一、什么是启动?
1、app启动类型
苹果将app启动分为三类:冷(Cold)启动、热(Warm)启动、恢复(Resume)启动。其具体判定规则如下:
前两者比较容易理解:新装app启动属于cold,杀死app然后重新启动属于warm。Resume比较难理解,这里APP的状态是suspended。我们来看这是一种什么状态?
Suspended更接近于background,但最大的区别是background是APP在后台执行代码,而 Suspended在后台未执行代码,可以将Suspended看成是进入后台时间较长但还未被系统kill的状态。
- Non-running - The app is not running.
- Inactive - The app is running in the foreground, but not receiving events. An iOS app can be placed into an inactive state, for example, when a call or SMS message is received.
- Active - The app is running in the foreground, and receiving events.
- Background - The app is running in the background, and executing code.
- Suspended - The app is in the background, but no code is being executed.
2、APP启动过程
以上是苹果对APP启动过程的划分,我们来逐个看看:
System Interface:
最令人期待的事情莫过于从iOS13开始Dyld3可以使用了,关于Dyld3,其与Dyld2的区别,苹果在WWDC2017大会上做了分享:
其最大的特点是Dyld3是部分进程外的,即操作系统在当前app进程之外完成了一部分dyld2在进程内的工作。以达到提升app启动性能和增强安全的目的。
而WWDC2019 苹果宣布针对Dyld3做了以下优化:
- 避免链接无用的framework;
- 避免在app启动时链接动态库;
- 硬链接所有依赖项
dyld3读取启动闭包,然后进行验证,再进行mach-o文件的映射、bind、rebase等一系列工作,最后进行libSystem初始化,这里主要是初始化一些系统的底层组件,其耗时相对固定。
Static Runtime Init
- 初始化语言的Runtime,对应OC就是初始化OC的runtime组件
- 执行所有类的load方法
这里可以需要注意以下事项,以减小对启动时间的影响:
- framework暴露专用的API------这个建议不是很理解
- 减小load方法执行的影响
- 尽量使用initialize方法去执行静态初始化
以上均是main函数执行前的操作
UIKit Initallization
实例化UIApplication和UIApplicationDelegate
开始事件处理并与系统交互
这里需要注意以下事项,以减小对启动时间的影响:
- 最小化UIApplication 子类中的工作
- 最小化UIApplicationDelegate的初始化
Application Initialization
这一部分主要是生命周期回调,包括UIApplicationDelegate app 生命周期回调
- application:willFinishLaunchingWithOptions:
- application:didFinishLaunchingWithOptions:
和UIApplicationDelegate UI 的生命周期回调
- applicationDidBecomeActive:
以及UISceneDelegate UI的生命周期回调-------------此回调是iOS13新增,用来代替UIApplicationDelegate的部分功能
- scene:willConnectToSession:options:
- sceneWillEnterForeground:
- sceneDidBecomeActive:
app生命周期内需要注意的是:
- 推迟不相关的工作
- 共享多个scenes的资源
First Frame Render
首帧渲染,其流程为创建View,进行布局,绘制views,提交绘制指令并渲染第一帧,相关的系统方法为:
- loadView
- viewDidLoad
- layoutSubviews
这里需要注意:
- 平展视图层次结构并延迟加载视图
- 优化自动布局
Extend
这一步有如下特征
- 首帧后app指定周期性操作
- 展示异步获取的数据
- APP不可交互与相应
它的影响可以利用os_signpost来测量
第二、如何特征化的测量启动?
测试APP启动需要测试环境的一致性,可以参考以下建议:
Reboot系统,然后让系统静止2-3分钟
飞行模式可用或者mock网络
使用未付费或者没有iCloud的账号
使用release版本的app进行测试
另外,在设备选取时,可以使用比较老旧的机器进行测试
Xcode11 开始 XCTest也支持了App launch的测试API
测量热启动
第三、使用Instruments来测量启动
Xcode11 的Instruments提供的App launch功能可以很详尽的测量app启动的各个环节的耗时,这里先混个脸熟吧!
此工具的使用后续单独成文,这里不再赘述
第四、长期监控启动
iOS13带来了一个很好的工具类MetricKit,此类的作用是可以周期性的生成当前App的启动、耗电、性能各方面的指标报告,开发者可以据此来构建自己的性能监控系统。我们来先睹为快:
class MXCellularConditionMetric
用于测量蜂窝网络质量.
用于测量CPU
用于测量展示时间
用于测量GPU
class MXLocationActivityMetric
用户测量定位
用于测量网络切换
用于测量App启动
class MXAppResponsivenessMetric
用于测量App响应
用于测量App运行时间
用于测量内存
用于测试磁盘IO
用于测量自定义的os_signpost
可以看出,苹果据此完成了app整体监控的大一统!也为开发者优化APP提供了更直接、更准确的依据。