记录APP优化的过程
最近在做APP性能优化,在做这个工作之前,也调研了一些东西,考虑性能优化的方面与入手方面,这个需要说明一下,每一个项目的特点不同,优先考虑优化的切入点也不同,但是总体的方向是有的,总结一下,以免后续忘记!
优化APP的考虑方面其实有很多需要考虑的方面,根据不同的业务、功能、性能点可以从不同的方面切入开始,下面我记录一下我接触的APP的优化考量的方向和优化的点!
之前我也记录过 iOS中APP的性能检测指标和考量的参数,可以作为参考,结合需要优化的APP的业务和实际情况
,暂时定义优化的切入点为如下几个方面:(这里解释一下,对于产品来讲,我们相对注重用户的直观体验,所以在考虑优化时,优先处理了以下方向,没有提及的优化的点不代表在优化中不重要!)
需要优化的APP性能初始记录:
* 启动总时长:2.5s - 3s左右,
* ipa包的大小:75M左右,
* 网络响应时长: 700ms左右
* 单页面加载时长: 700ms左右
解释一下: 启动总时长规则为 warm-launch,用户在点击打开APP - 首页完全加载完成的时间记录!
有些同学看到启动时长这个数据可能会震惊,其实在没有优化之前的APP
,启动时长5s
都是有可能
的,原因是:APP的启动需要初始化很多东西
,越复杂的APP,需要初始化的功能越多,例如:基本的记录功能
、初始化分享功能
、下载功能
、业务线的manager初始化
、内购
、推送
,网络请求
等功能的初始化,想象一下这些过程全部放在主线程执行,并且有一些初始化的过程需要网络的介入
,那么,从用户的角度看到首页界面的加载完成其实是一个很漫长的过程!
优化APP的启动时长的具体切入点:
<1>、 main函数执行之前的加载时间
* dyld 会初始化动态库
* Rebase/Bind 相关资源
* 加载 object - 对象
* initializer : 方法加载
main函数加载之前的四个过程
,建议大家一个查看 iOS性能检测指标 查看具体的功能,这里只是针对这个过程做优化
的具体操作:
在以上四个过程中可以看出,其实动态库
、object对象
以及相关资源
这些 数量级
的内容可以影响到加载时长,那么优化的目标就很明显了:
1、尽量减少动态库的使用,摒弃掉不再使用的动态库,合并响应的动态库等方法就可以针对具体的项目情况具体实施!
2、针对object也一样,尽量少的存在对象,当然优化的方式如上,删除无用的,在业务上合并一部分对象等,包括资源也是如此,这里的资源并不是单一的指代图片资源!
为何上述两点叙述的如此简单呢?
因为上述两点的优化其实很多人都知道,并且需要结合自身的项目而言,例如针对我需要优化的项目,动态库的数量与合并
其实并不是由个人来决定的,那么这个优化对与我的操作来说是枉然
的!
所以针对项目,我遍历查询了无用的对象,删除掉废弃的业务线,这一模块就暂时优化完成了!
还有一个过程是
initializer
方法的加载,这个结合项目自身,需要优化的就比较细致了,每一个类初始化的时候:load
、initialize
方法的选择和自身view的加载:viewDidLoad/viewWill~等方法的选择都需要结合实际情况考虑!
需要注意的是:initialize方法的调用需要注意哦!
<2>、main函数执行之后的加载时间
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions ;
这一个过程中其实不止这一个方法的执行时间,还有applicationDidBecomeActive:
方法需要记录!这个根据自己的项目具体记录优化!具体介绍一下我优化这一过程的具体操作!
待优化的APP具体需要初始化的功能有如下:
推送
、分享
、打点记录
、bugly日志
、路由
、内购
、webView(Hybrid引擎启动,设置白名单等)
、通知
、下载模块
和多条业务线
的初始化,当然还有每一个项目必备的window初始化
这些模块!
针对这些模块,优化大方向是
并行执行
、延迟加载
,
即留下必要的模块加载,区分出一部分模块可以并发执行,区分出一部分模块可以延迟加载
那么重点来了,哪些模块是可以并行的,哪些又是需要延迟加载的呢?
如下,记录一下我踩过的坑!
并行的模块: 针对于可以放入子线程的模块,过程中1、需要注意是否有UI的切换,都知道,
UI
需要在主线程执行,在子线程
中,需要在合适的地方切换到UI线程中!
2、需要注意的是初始化的及时性,例如:待优化APP中有一个打点记录模块
,如果放在子线程中初始化,那么就可能会出现初始化不及时
的情况,那么didFinishLaunchingWithOptions:方法的记录其实是不准确的,存在风险!
延迟加载模块:针对于一些并是不必须第一时间初始化的模块,
例如:上述提到的下载模块
,这个模块主要工作
分析后得知,初始化后,继续下载未完成的视频的作用
,针对于这种功能呢,其实是可以放在首页初始化
的,或者延迟加载几秒后再执行
也是可以的~
总结得知:针对于不影响首页UI框架
展示的模块其实都可以延迟加载,不是需要第一时间初始化
的模块也可以延迟加载,
需要注意的是,反面例子
:外部唤醒需要注意,不能延迟加载,原因,待优化的APP中其实有外部唤醒
的功能,初始化推送的模块起初使用延迟加载
,发现没有影响,但是,针对于远程推送
,唤起APP,如果还需要跳转到相应的模块
,可想而知,didFinishLaunchingWithOptions
方法完成后,推送相关的SDK还没有初始化完成,如何响应跳转链接呢,这是优化中踩过的一个坑,祭奠一下!!!
如下,针对特殊的功能模块分析一下:
通知模块
初始化,发送通知
其实可以延迟加载
或者并行加载
,iOS中影响通知方法执行的是接收通知
在哪个线程
,那么方法执行就在哪个线程
,不在于发送通知的线程
,所以在初始化通知模块的时候,注意一下模块中是否有接收通知的方法
,并关注一下方法的具体需要
,一般初始化通知中如果只有发送通知,初始化通知,那么可以放入子线程!
业务线初始化
模块:这个模块是待优化APP中重要的一个入口,是业务入口的网络manage初始化
模块,优化的时候检测到这个方法非常耗时
-800ms
左右,我把这个方法放入的子线程并行执行
~
需要考虑的点是: 模块内部界面
与数据
的分离状况,好的一点是我们的项目在这一点做的很好,业务线初始化模块中不涉及任何一点UI,所以我可以并行执行业务入口
,
考虑的点在于,加快启动速度
,其实对于用户
来说是尽快进入到首页的界面框架
中去,那么基于这一点考虑,数据的获取的权重
就小于了页面框架的展示
,所以业务模块的初始化不必要第一时间加载!
记录类
、日志类
的SDK初始化,建议不要
延迟和并行加载,
当然前提是初始化方法的执行时间
,如果方法执行时间过长,那么需要考虑方法初始化方法内部是否需要减少执行时间!
window
初始化:WiFi万能钥匙
针对这一模块有一个不一样的方法,记录一下,可以思考一下~
APP界面架构为: tabbarVC -> navigationVC -> VC,
优化入口为:用户第一时间看到首页
,WiFi万能钥匙做了一个极致的优化操作,我们知道,tabbarVC添加子控制器
一般循环添加
四个、三个等,WiFi万能钥匙启动之初,先添加首页一个子控制器
,其他的子控制器延迟加载
,延迟时间设置大一点,可以看到,用户首先看到底部tabBar只展示首页
的子视图,后续再加入其它子控制器
,这样极大的保证了用户第一时间看到首页的思想,可以思考借鉴一下!
这里个人觉得可以加快速度的地方为,可以先不设置navigationVC
,这个可以在进入相对应的Controller
的时候再设置即可!
share
模块:其实这个建议在相对应的界面初始化是最完美
的,即进入需要分享的界面
的时候,再初始化share模块
的SDK,但是,待优化的APP
由于某种不可抗力,不允许这样,所以把分享模块
的初始化延迟加载了2s
左右,效果也是比较明显的!相同
的初始化模块还有webView相关
的配置!
路由的分发模块:路由的分发模块在待优化APP中涉及到了启动页的展示和界面的跳转,这个在此次优化中没有做过多的调整!
<3>、首页加载时长
秉着用户第一时间看到首页的原则,在首页Controller中可以调整数据请求与页面渲染的执行,如下:
load -> viewDidLoad -> viewWillAppear -> viewDidAppear
这几个方法中,页面是在viewWillAppear之后
开始渲染
的,也就是说,在此之前用户是看不到界面
的,那么需要平衡
的是,用户看到的是框架界面后
再注入数据刷新
界面,还是直接看到的就是注入数据的界面
!
如果对于网络响应这一块已经有很好的性能,或者可以保证网络的响应时间
,其实可以让用户首次看到的就是有完整数据
的界面,否则,其实可以先加载一个框架页面
,后续注入数据
再刷新界面!
那么二次刷新界面的方法需要放入viewDidAppear中,结合数据二次刷新!
数据请求就不用多说,一定是子线程执行~
需要注意的是,如果有大图展示,需要单独针对图片做显示优化的处理,这里就不再多说!