作者简介:

沈哲,擅长移动端、互联网后端技术,曾经在安硕信息、decarta(已被uber收购)、京东商城等国内外知名软件公司、互联网公司工作。开发过decarta第一款地图导航app,今夜酒店特价app,负责过京东到家上海的移动端团队。现负责魔窗移动端团队,负责研发魔窗的sdk以及移动端相关产品。

本人自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:

1. 脚本构建

2. 极限优化(网络、日志上报、图片格式等方面优化)

3. 第三方组件替换

4. 小版本稳步迭代

脚本构建

我们从开始开发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中,在程序下次启动后,根据发送策略再次发送。

为了减少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社区,接受所有开发者的监督。

魔窗研发副总裁沈哲:移动端SDK的优化之路相关推荐

  1. 微软副总裁沈向洋:三十年科研路,我踩过的那些坑

    来源:机器之心 机器之心编辑部 在近日举办的 X-Talk 上,美国工程院外籍院士.小冰公司董事长沈向洋博士分享了自己过去三十多年做科研的体会. 日前,首届 X-Talk 于 2020 年腾讯科学周期 ...

  2. 微软全球执行副总裁沈向洋离职;马云回应双十一数据作假;GitHub 官方终于出 App 了! | 极客头条...

    整理 | 郭芮 快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注 ...

  3. 蔚来辅助驾驶致死,副总裁沈斐或遇更大危机

    出品|智能好车 作者| 胥崟涛 大周末的,和大家分享一个不太正能量的新闻,但相信很多读者已经从其他渠道了解到了,就是: 8月12日下午,一名蔚来ES8车主在高速上发生事故不幸离世. 这位车主是个餐饮业 ...

  4. Hulu全球研发副总裁诸葛越谈人工智能

    马上要进入新的招聘季.对于有志投身技术领域的应聘者,面对当下正席卷全球的人工智能热潮,"数据科学家"和"算法工程师"绝对算得上热门职业."人工智能&q ...

  5. 原VIPKID研发副总裁朱会离职

    [TechWeb]8月12日,今日有消息称VIPKID研发副总裁朱会已离职加盟水滴筹,对此VIPKID方面确认朱会于今年8月从VIPKID离职. 2017年4月,VIPKID公布了最新管理层人事任命公 ...

  6. 从程序媛到全球研发副总裁,技术女神进击史!

    给你看一位海归人士的履历图,看完你觉得TA是男士,还是女士呢? 制图:CSDN 45K!刚面完 AI 岗,这些技术必须掌握! https://edu.csdn.net/topic/ai30?utm_s ...

  7. 百度副总裁沈抖:百度APP全面升级 打造新内容消费服务平台

    11月1日,百度在北京举办了2018年百度世界大会.百度副总裁沈抖在会上正式公布百度App11.0上线,新版App将从"搜索+信息流"模式升级到"综合性内容消费和服务平台 ...

  8. 百度副总裁沈抖:互联网的下一波红利是“互联互通”,将屏蔽清单变成机会清单

    2021百度联盟峰会中,百度集团执行副总裁沈抖表示:互联网的下一波红利是"互联互通".互联互通将大大拓宽商业的边界,互联网公司可以将"屏蔽清单"变成" ...

  9. 微软全球执行副总裁沈向洋:人工智能的机遇和挑战

    8 月 29 日,2019 世界人工智能大会在上海正式拉开帷幕.微软全球执行副总裁.微软人工智能及微软研究事业部负责人沈向洋发表演讲,其表示过去几年间,人工智能得到了快速的发展.在此趋势下,微软亚洲研 ...

  10. 微软全球执行副总裁沈向洋:你给自己的定位是什么,你就会得到什么

    来源:AI 科技评论 摘要:沈向洋,美国国家工程院院士.微软全球执行副总裁.ACM/IEEE Fellow.多年来,沈向洋专注于计算机视觉和计算机图形学的研究,并领导和开发了 Bing 搜索.目前,他 ...

最新文章

  1. linux的TCP连接数量最大不能超过65535个,那服务器是如何应对百万千万的并发的?
  2. Linux nginx 会话保持(session)
  3. LeetCode 1207. 独一无二的出现次数
  4. 【绿色版】飞鸽传书2011绿色版
  5. ubuntu 18.04,无线网卡无驱动,连不上wifi,显示wifi没有适配器的解决方法
  6. AIR ANE(本机扩展)使用中的一些问题(Android平台)
  7. Ubuntu做Tomcat服务:insserv: warning: script 'tomcat' missing LSB tags and overrides
  8. React 组件开发 传参(详解)。
  9. golang 猜数字小游戏
  10. 带grub的软盘镜像制作
  11. 近世代数概论------有理数与域
  12. ssm整合的简单案例(附源码)
  13. Django发送电子邮件
  14. Android大话设计模式 第二章----单一职责原则 乔峰VS慕容复
  15. 记录docker failed to initialize docker desktop is shutting down解决办法
  16. 一次计算机社团活动方案,社团活动方案设计方案5篇
  17. 【转】Hibernate中session的clear(),flush(),evict()方法详解
  18. 32位掩码转换成子网掩码
  19. layui信息加载流的方式加载数据
  20. SpringBoot项目入门,使用Eclipse创建Springboot项目

热门文章

  1. 京东联盟CPS API调用:我不想吐槽京东的接口。。。。
  2. 从MWC到AWE,中国柔性黑科技为消费电子产业撒下蒲公英的种子
  3. FlinkSQL字段血缘解决方案及源码
  4. python 数据可视化sns作图
  5. python3 import的一个细节
  6. mysql lob 操作_Oracle中LOB 处理
  7. Windows Server 2019 配置DHCP
  8. oracle官网(中文)
  9. chrome浏览器更新后重新安装配置chromedriver
  10. 笔记本电脑秒便WIFI热点