您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
移动端SDK的优化之路
 
作者:沈哲 发布于 2016-6-27
  2517  次浏览      17
 

 

本人自2015年9月底加入魔窗,开始着手优化魔窗移动端sdk的工作。

魔窗是基于Deep Link技术的开放平台,通过提供生态落地最后一公里的deep link、跨App store渠道的归因分析以及场景还原(deferred deep link)等解决方案为App开发者构建一个去中心化的高效连接时代。最重要的产品就是iOS和Android端的SDK。

sdk优化过程,是一段血泪史,可以吐槽的地方无数。移动端sdk不像app一样方便,sdk发布后出现任何问题,都会影响到很多家的app。不能像一家app一样,可以及时发布一个hotfix,或者强制升级app,又或者热更新app。所以sdk发版之前,必须经过严格的测试,每一次sdkhotfix的发布都会对我们的用户造成严重的影响。

sdk的优化,最大的痛点是它的大小。每次对接客户,他们都会问我们sdk的大小是多少?每当提到iOSsdk时,他们都会说还蛮大的,他们自己家的app都已经几十M了,接入我们的sdk会增加他们app的大小。所以,不得不开始痛苦的sdk优化之路。

我们主要从以下几个方面进行优化sdk:

脚本构建

极限优化(网络、日志上报、图片格式等方面优化) 第三方组件替换 小版本稳步迭代 脚本构建

我们从开始开发sdk到目前正在开发中的3.8版本,一直推崇借助脚本进行自动化打包,例如android使用gradle。借助脚本的好处在于:

1)androidsdk混淆

2)自动生成文档,便于开发者查阅,例如android可以很方便的生成javadoc文档

3)androidsdk上传aar包,iOSsdk发布到cocoa-pods,便于开发者集成

4)节省人工时间,减少出错

脚本通常能帮助我们实现很多自动化的事情,能提高工作效率的方法是一定会被采纳的。

接下来我们来看看借助gradle如何实现sdk混淆,核心的task是proguardJar这个task。

(点击放大图像)

极限优化

所谓极限优化,是指从多个角度、维度对sdk进行优化,重点是考虑网络优化以及电量消耗优化。能够做到代码精简,低网络流量,微能耗而不仅仅是低能耗。

香农定理是所有通信制式最基本的原理,我们知道C=B lb(1+S/N)

其中:C是信道支持的最大速度或者叫信道容量,B是信道的带宽,S是平均信号功率,N是平均噪声功率,S/N即信噪比。

从最初的1G网络到现在的4G网络,都是在利用这个公式提高速度。要么充分利用频道资源,要么提高整体带宽。但是频段资源都是有限的,所以不得不制定出更优秀的策略来提高资源的利用率。结合网络情况、手机电量等因素,我们采取以下几种方式进行优化:

1)合并网络请求,减少服务器压力和dns请求时间,减少手机的网络流量。

2)数据缓存到本地,最省电的方式就是不使用移动网络,数据缓存能大大减少网络请求的次数。

3)日志上报策略,批量非实时上报。日志生成后,首先存储在RAM中,基础策略是满30条发送,每隔一分钟轮询一次。为了满足客户定制需求,发送策略可通过后台配置。如果遇到异常情况,比如网络异常或者crash等,我们会将日志存储在本地sqlite中,在程序下次启动后,根据发送策略再次发送。

(点击放大图像)

相关厂商内容

想要快速学习Amazon EMR最佳实践,赶快报名InfoQ在线课堂 ArchSummit 晚场活动对外招募,邀您和架构师畅聊技术 如何快速搭建一个完整的移动端直播系统 你离成为一位合格的技术领导者还有多远? 证券行业的Docker应用实践
相关赞助商


GMTC全球移动技术大会2016年6月24日-25日,北京,点击了解详情!

为了减少app的网络流量消耗,我们还将活动的图片新增了WebP的格式。

(点击放大图像)

WebP格式的图片好处是什么?举个例子,做一个简单的测试对比PNG 原图、PNG 无损压缩、PNG 转WebP(无损)、PNG 转WebP(有损)的压缩效果。

可以得出结论:PNG 转WebP 的压缩率要高于PNG 原图压缩率,同样支持有损与无损压缩。

转换后的WebP 体积大幅减少,图片质量也得到保障(同时肉眼几乎无法看出差异)。转换后的WebP 支持Alpha 透明和 24-bit 颜色数,不存在 PNG8 色彩不够丰富和在浏览器中可能会出现毛边的问题。

WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量。除此之外,国内外很多知名的应用已经使用了WebP格式,这也是我们使用它的原因之一。

在3.8版本的sdk中,用于活动的Marketing接口会返回PNG和WebP两种格式的图片。对于Android而言,如果操作系统版本在4.0以及4.0之后,它天生支持WebP格式,sdk会优先加载这种格式,加载不成功才会去加载PNG的图片。如果是Android 4.0以下,sdk只加载PNG图片。

对于iOS而言,目前iOS本身不支持WebP格式(但愿iOS10会支持它:(),要借助第三方库才能支持,比如SDWebImage。但是iOS sdk已经足够大了,不可能把SDWebImage集成到sdk。所以,目前iOSsdk不会像androidsdk一样存在imageloader,iOSsdk把图片加载的权利交给开发者。当然以后,我们肯定会给iOSsdk提供类似android的imageloader的功能。

借助Webp,我们替用户节省了流量,节省了手机内存和CPU资源。

未来,网络请求还会进一步优化。会考虑使用protobuf协议替换现在的返回json格式。protobuf返回的数据更小,而且是二进制的格式。从安全性的角度上说,在一定程度上能够防止被恶意抓取数据包进行分析。

第三方组件替换

对于移动端sdk的开发者来说,移动端其余的开发人员都是幸福的。他们可以尝试使用无数的第三方库,在github上每天都会诞生很多优秀的第三方库。sdk的开发者不得不自己去实现很多功能,因为考虑到sdk大小的问题。

对于sdk的开发者来说“这是一个最好的时代,也是一个最坏的时代”。他们必须自己去“造轮子”,但是会给他们带来更多收获,无论是接触到os的底层还是设计模式,都会比普通的开发者了解更多。

我们魔窗的sdk包括Androd、iOS版本在不断迭代的过程中,都经历过第三方组件的替换。以android为例,我们替换了json解析器和网络框架等等。

最初,我们使用fastjson,它是由阿里巴巴的工程师编写的,性能和稳定性都很好。我自己写app时,也会首选它作为json的解析器。但是它明显增大了sdk的体积,于是我们使用gson替换了fastjson。用了一段时间后,觉得gson还是很大。

最终,我们考虑重写jsonparser。重写的jsonparser,必须能兼容原先gson的一些api,避免sdk工程做太大的改动,这是我们重写的一个目标。

重写jsonparser之前,我们先对反射做了一次封装。传统的反射是这样写的:

(点击放大图像)

封装之后的写法是这样的,基于流式API:

依托于简洁的反射,实现了自己的jsonparser。除此之外,还需要将http请求返回的结果借助自己的json工具类转换成对象、对象数组。类似于这样:

(点击放大图像)

借助这个反射我们还获得的额外好处是,在android4.0以后的版本能够随时获取到App的ApplicationContext,以前还担心获取不到ApplicationContext,这样一来还能防止memory leak。因为,Activity的Context使用不当经常会引起内存泄露。

(点击放大图像)

另一个被替换的第三方组件是volley。它是google开发的网络框架,便于android应用操作网络。替换volley的原因,是它功能太强大了,简直就是一个“全家桶”。我们用不到那么多功能,sdk需要的是一个符合自身业务需求的网络框架。同样,替换的准则是能够兼容原先volley的大部分api。于是我们做了一个简化版本的volley,它大致的流程如下图所示:

它最主要的四个部分是:Request、RequestQueue、NetworkExecutor和ResponseDelivery。

Request,即各种请求类型。包括StringRequest和ImageRequest,分别表示返回的数据是字符串和网络图片的请求。Request支持Get、Post请求,支持header、支持请求缓存、支持postbody、支持请求的重试机制。Request类还包含了一个回调处理的接口ResponseListener。

第二部分为消息队列RequestQueue,消息队列维护了提交给网络框架的请求列表,并且根据相应的规则进行排序。默认情况下更具优先级和进入队列的顺序来执行,该队列使用的是线程安全的PriorityBlockingQueue,因为我们的队列会被并发的访问,因此需要保证访问的原子性。

第三部分是NetworkExecutor,它是网络的执行者。该Executor继承自Thread,在run方法中循环访问第二部分的请求队列,请求完成之后将结果投递给UI线程。为了更好的控制请求队列,例如请求排序、取消等操作,这里我们并没有使用线程池来操作,而是自行管理队列和Thread的形式,这样整个结构也变得更为灵活。它的主要代码是这样的:

其中,doRequest()方法用于真正的网络请求和分发网络请求返回的Response。doRequest()支持重试机制,它的大致流程如下图所示:

第四部分是ResponseDelivery,在第三部分的Executor中执行网络请求,Executor是Thread,但是我们并不能在主线程中更新UI,因此我们使用ResponseDelivery来封装Response的投递,保证Response执行在UI线程。

总之,每个部分都符合单一职责的原则,便于日后的独立维护。

我们再看看怎么借助这个网络框架如何调用httppost请求。

一. NeteaseAPM是什么

对于普通的app开发来说,小版本快速迭代几乎是不可或缺的方法论。而对于sdk开发而言,“小步快跑,快速迭代”的策略不再适用。我们必须采取相对稳健的更新策略。

sdk是面向所有的开发者使用的,高版本必须向下兼容api。如果某个api确实需要过期的时候,至少保留几个版本后再删除过期的api,并附有详细的说明文档。

对于sdk而言,版本发布也不宜频繁,否则会让开发者会感觉自己是“小白鼠”。这样的体验,对于开发者是相当不友好的。

对于每一个小版本除了新增的功能之外,我们都会集中精力优化好某一块地方。每一个小版本都是“小步迭代”,但是经过几个版本的迭代之后,还是能够实现量变。下面的表格是我开始接手魔窗sdk之后,androidsdk体积的大小的变化。

从3.0到3.7版本,android sdk的大小,总体趋势是不断减少的。其实功能不断增加的,sdk的稳定性也得到提升,这就是我们采用小版本不断迭代带来的好处。

未来,sdk拆分

关于未来,我们追求的是在保证sdk稳定的前提下,继续努力减少sdk的大小。将我们的sdk拆分成多个组件,供用户挑选自己想要的各个组件。我们目前sdk的模块如下图所示。

sdk最核心的部分是sdkcore,它是sdk必不可少的组成部分。它有以下几部分组成:

1)http组件,是我们自己开发的http模块,符合自己的业务需求。

2)imageloader组件,在sdk中显示活动图片的组件,是自己开发的模块。

3)domain,是sdk所需要的对象,包括http返回的对象以及业务模型。

4)config组件,是sdk必须的配置组件。

5)jsonparser组件,json解析器,是我们自己开发的模块。

6)utils,sdk中各种帮助工具类。

7)sqlite组件,操作数据库的相关类,把一些数据缓存到sqlite数据库。

其余的组件虽然没那么重要,但是可以通过自由组合的方式,组成开发者想要的功能。这是我们未来1-2月的努力方向——sdk的拆分。将sdk拆成更小更细粒度的模块,开发者也能更好地选择他们想要的模块。

比如一个开发者只想要tracking功能,那么他只需使用sdkcore包和tracking包。再比如一个开发者只想要mLink(基于deeplink深度改造)的功能,那么他会需要sdkcore包、tracking包、magicwindowview包和mLink包这几个包。

Ending

sdk无论怎么拆分,稳定性是最最重要的。它涉及到使用sdk的所有app,以及app背后的无数用户。作为sdk的开发者,必须对用户负责,要抱有一颗敬畏之心。

经历sdk的拆分之后,我们会逐步开源sdk的功能到github社区,接受所有开发者的监督。

   
2517 次浏览       17
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新课程计划
信息架构建模(基于UML+EA)3-21[北京]
软件架构设计师 3-21[北京]
图数据库与知识图谱 3-25[北京]
业务架构设计 4-11[北京]
SysML和EA系统设计与建模 4-22[北京]
DoDAF规范、模型与实例 5-23[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   

Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合

领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...