开始阐述背景之前,先分享一个实验数据,经过线上灰度版本的验证,前置广告流程可以缩短启动平均耗时约300ms。接下来就展开说说为什么我们需要做这件事了。
启动优化是老生常谈的话题了,Soul App也持续在进行启动相关的优化。常规和"黑科技"方案都有探索并上线。但一直有一个痛点难以跨越,在核心的启动流程中,因为业务特定要求,需要等到Application执行结束后开启广告加载的流程,这样串行执行的过程,其实非常影响启动体验。
在上图中可以看出,这样的线性启动流程其实无法最大程度利用启动资源。
我们很自然就会想广告流程能和Application并行,那该多美好啊。按照正常逻辑来说,直接将广告初始化流程放至Application最早可执行的地方即可。但核心一个问题在于,Application可能会有其它启动方式,不一定来自用户点击桌面图标的方式。对于其它方式,实际上不应该初始化广告流程的,因为没有曝光广告的必要,如此一来势必会造成广告资源的浪费。
在收益和问题之间犯了难,但内心的倔强又无法躺平接受,绞尽脑汁想各种办法。分析到这里清楚了要解决问题的本质是:如何判断启动来自用户点击图标的方式,这样既能前置初始化广告流程,同时也避免了资源的浪费。
了解到要解决本质问题以后,颤抖的手,激动的小心情,感觉问题不大了。一直在印象中系统有API可以获取启动来源。但是真的写逻辑时才发现,系统获取方式必须依赖Intent对象,但在Application阶段无法获取Intent,仔细想想这样也很合理,刚进入启动阶段没有进入界面之前无法获取Activity(主界面)任何信息。看样子这个方案行不通,继续探索吧。
既然非点击图标方式会影响广告流程的前置,可以考虑排除方式。主要排除以下情况:
根据现状,制定了一系列的排除流程,目的就是尽可能剔除非点击图标的启动来源。尽管考虑了这么多方面,但依然还是遇到一些问题:
通过这么多排除以后,发现能够符合流程要求的样本不多,这样收益大打折扣。
在所谓符合样本里面,通过观察灰度版本的广告曝光情况,依然有20%左右的折损,无法接受。
如此一来,还得继续摸索,另想办法。
在Android中所有的界面启动过程中,都绕不开Handler的分发处理,那是不是可以从Handler中去获取一些相关信息呢,实际上验证下来是可以的,但也有存在一些遗憾的问题。
也是一些常规处理方式了,直接贴代码。
接着设置自定义的callback,就可以实现消息拦截了。
具体的系统机制,篇幅原因不做过多的展开。拦截到消息以后,我们可以从消息中获取一个很关键的信息,即mReferrer ,代表启动来源信息字段,有了这个信息就知道从哪来启动的App。
逻辑本身不复杂,需要注意的是隐私API反射问题,相信Android同学都懂得咋绕过。得到调用者包名以后,可以比较简单的粗暴的判断下是否包含launcher或home之类的关键字,一般系统的桌面应用包名都是这样命名的,极少量个性命名方式就不考虑了。到这里也算一大进步了,可以获取到准确的启动方式。
但是刚才提到遗憾的一个结果:虽然可以在Application阶段获取,但非常滞后,因为依然依赖主界面的启动,只不过是在启动主界面最早的阶段拿到来源信息,比起主界面真正起来之后获取来源大概提前100ms左右,蚊子肉也是肉,基于这个方案,在线上运行过一段时间。这点收益多少有点不甘心,才有了后续的探索。
听起来稍微有点高大上。这个方案是"逼"出来的,面对启动优化的压力,不得不去想各种骚操作。通过上述的Hook方式,虽然效果不佳,但是得到一些启发:
Hook方案验证下来稳定性还不错,没有出现过异常。
既然启动来源这么严重依赖进入主界面信息,那能不能先进主界面再来初始化Application呢,听起来有点疯狂,不妨试试看呢。
其实思路比较简单,既然依赖进主界面才能获取相关信息,那就在Application未执行任务之前直接先启动界面。注意了,需要真正的调用界面的生命周期之前,反过来初始化Application,不然进主界面肯定各种崩溃。本质上只是需要临时获取启动来源信息。
上图中initProxy的代码是Application阶段主要执行的逻辑,和之前的区别在于,不是立马执行initProxy,而是先Hook Handler,这样Application 快速的结束掉,立马开始进入主界面流程,这样我们就可以在第一时间拿到启动来源信息。接着,这是重点:
这个意思是,在执行主界面的生命周期之前,需要反向再执行一遍刚才未执行的initProxy逻辑。这一套动作下来,既拿到了启动来源信息,同时又正常进行初始化流程。当然要注意一些异常和边缘的处理,例如发生异常时,无论是否获取到启动来源信息,都要强制执行initProxy,不然启动会造成崩溃。此方案目前已经线上运行中,考虑到核心流程,目前采用小范围验证的方式,还是得保持敬畏之心啊,稳中推进。
以上就是在广告流程前置流程上的心路历程。可能写得简单轻松,实际上也踩了不少坑,走了不少弯路。接下来的重点慢慢将方案推全。
回到最重要本质上事情上来,快速启动是非常重要的用户体验,也和业务核心指标息息相关,这是一条永无止境的路,需要不断的去挖掘一些优化方式,不断的铸造进行防裂化墙。