为App减负!!更精更小的MTA SDK模块化发展历程

原创
2017/07/20 18:26
阅读数 477

导语

SDK是一种方便常见的开发者工具形式,但越来越多的内嵌功能,可能让SDK服务越来越全,可能会出现功能的重复,造成SDK包越来越重,给App自身带来负担……为App减负,MTA踏上了探索的道路。

作者介绍

陈翔,腾讯大数据平台高级开发工程师。

从2009年工作至今,在前端和终端开发领域有着丰富的实战经验。

目前为MTA、腾讯移动推送(信鸽)等项目iOS端研发负责人。

 

随着移动互联网的高速发展, 出现了大量的公司以SDK的形式为App提供服务,例如统计、推送、Crash监控等等领域。接入各种SDK服务做开发,相对App从零开始自研的话,极大的提升了App的开发效率,节约了大量的时间和成本。开发一个爆款软件不再是几年,可能就是几个月时间。

MTA的产品定位是移动统计分析工具,在伴随着与开发者共同成长的道路上,也在不断响应用户的需求,提供更多更丰富的开发者服务,比如最近升级的Crash监控。同时也在提供更多的运营服务,比如最近上线的可视化埋点功能。

在MTA的成长道路上,不断的提供更多更好的服务,于是乎问题来了,这也是业界普遍的一个问题:SDK体积越来越大。

 

 

 

这对许多App来说是个噩梦,因为不只是增加了流量,可能也会带来更多的额外计算工作,造成卡顿,用户的电量也在加速消耗。

 

MTA技术总监顾孙炬(Raygu)适时提出:为App减负,MTA势在必行。

 

MTA怎么做

为了致力于提供最佳的体验,我们在思考,怎样能够保证SDK足够小,又能提供用户所需的各种服务,满足各种大小客户们的需求。截至现在经历了三个阶段

 

第一阶段:定制服务

在早期MTA有新功能的话, SDK版本就是一个体积一直累加的过程。有一天,突然有重要客户提出是不能接受体积大的。于是针对这个客户,通过沟通的方式,确定他们需要的核心功能,然后拉代码分支,做相应的修改。然后又有类似的第二个客户、第三个客户……  看着分支越来越多,无论是新特性的增加或者bug的修复,对于终端来说,维护的成本非常高。不禁要打个冷颤,再这样发展下去,维护的工作量不可估量。

图1. 苦逼的各种历史定制版本

 

第二阶段: 精简服务

针对第一阶段的问题,做了这样的设计,将SDK分成三种大版本。

 

超级精简版: 提供给各种二次封装*SDK使用,或者对SDK体积有超级严格要求的App。

适度精简版: 提供最常用的功能。

完整版: 所有功能的集合版本。

*备注:二次封装SDK是指各种聚合SDK,也就是包含了很多SDK服务的大SDK。

从上看出,通过对需求功能和客户分组的方式,三个版本可作为绝大多数客户的基线版本。在相对稳定的基线的基础上做不大的调整,相对第一阶段维护成本小了不少。

 

 

 

图2. 3种版本应对种种需求

 

在推广的过程中,因为满足了二次封装SDK的标准,但是超级精简版的功能不够完全,有的客户有独立接入MTA的需求。这样当App同时接入超级精简版和其他版本的时候,会产生许多” duplicate symbols”的错误。

 

 

图3. 不小心就报错了

项目的改造: 我们知道Objective-C这门编程语言是没有命名空间的,通过修改一个个类名前缀和字符串前缀,可以做到编译和运行级别的兼容。

 

通过短时间的实践,后来发现完全不可维护,因为有N家二次封装SDK的客户,这样只是超级精简版就要修改出N个项目,而一份代码有N个类和N个字符串,工作量大且容易出错。

 

回到初衷,我们想尽量降低维护的成本,在Objective-C命名空间上,我们做出了如下的设计:

 

在预编译文件(.pch)中,做一个类似这样的宏定义

 #define symbol  prefix##symbol

通过对prefix做一次修改,则可以全局修改符号的前缀。举个例子:   

#define MTA  QQ##MTA 

这样就实现了开发时,在XCode项目中是MTA,编译后生成的符号是QQMTA,字符串也可以做类似的处理,给不同客户配置不同的前缀。因为解决了符号重名问题,这样的话,超级精简版就可以轻松的给各个二次封装SDK提供服务,同时和其他版本(适度精简版或完整版衍生的版本)共同生存。

伪代码示例:

Prefix.pch文件
//处理类名
#define ARK(symbol)  prefix##symbol
 
//处理字符串
#define ARKNSSTR (symbol) @ #prefix #symbol
 
#define MTA      ARK(MTA)
#define MTAConfig ARK(MTAConfig)
 
某个.m文件
static NSString *const  BUSINESS_ID = ARKNSSTR(MTA);

 

第三阶段: 模块化

做到第二阶段时,较少人力已经足够维护好MTA项目了。但是在最近一年,需求越来越多,人力的匹配速度却没有跟上,这样造成MTA的多版本维护变得有些吃力。这样就需要思考是否能进一步减少维护的成本。

通过重新梳理,以及在MTA技术总监顾孙炬(Raygu)的支持下,根据特点MTA被分成几大部分: 必需模块重要模块独立模块

 

必需模块: MTA运行必需的模块,属于核心中的核心。

重要模块: 依赖必需模块,功能非常重要,客户也可以不需要使用的功能。

独立模块: 轻度依赖必需模块,大部分逻辑都是独立运行。

 

在此划分的构想上,提出插件和组件机制。架构图如下:

 

图4. 清晰可拆解的模块化构建

 

首先,最底层是core,对应必需模块,包含上报模块基础功能,这两者代表是MTA最基础的核心功能,作为一切组件和插件的基础。同时是一个Service Provider的角色,把最基础的上报、网络、存储、通用函数等基础能力暴露出来复用。

往上是组件层,对应重要模块,这里是一些MTA重点服务的功能,依赖core层的功能。在原本组件都打包在一起的时候,MTA需要用到组件就直接使用。这里做了个代理的设计。把需要用到组件的功能做个对应的protocol定义,在MTA工作流程中一个组件对应一个delegate,delegate连接了对应的组件,组件实现了对应的protocol。这样在MTA工作流程中通过对delegate的判断,如果连接了组件,就可以使用对应模块,反之缺失对应组件的功能。即使没有组件,而增加这个逻辑带来体积的增加几乎可以忽略。

再往上是MTA的插件层,对应独立模块,这一层的模块基本都是可以独立运行或者和MTA主流程耦合很小。MTA核心状态的变更,会发出响应的通知,插件会订阅这些通知,也就是观察者模式。比如初始化完成后的状态通知,插件收到通知后才会进行自身的初始化,这样可以保证MTA核心功能的完整服务可用,使插件运行的更加稳定。

至此,MTA只需要维护一份代码,即可实现灵活的功能拼接,满足各个用户的需求,并且不会出现” duplicate symbols”的冲突问题。实现了一套代码N个版本。

 

编译和打包

MTA的架构,如果用XCode来打包,会非常复杂,不可控。实际上从第二阶段开始,我们已经进行脚本化打包,基于Xcode command line tools。通过灵活的参数传递,可以快速的生成各种binary和fat binary文件,非常方便。

最后,附上MTA官方版本的物理结构图, 下载地址请到MTA官网SDK下载页进行下载,或点击文末下载链接。

 

 

 

图5. 灵活可选的各个模块

 

用户需要什么功能,引用相应的.a文件即可,实现了用户自己灵活组装MTA功能。其中有部分组件打包在libmtasdk.a里,如果有特殊需求,也可以联系我们分离出来。

 

小编有话说:

MTA是一款为开发者提供服务的工具产品,核心是围绕开发者的需求,对外输出我们的能力与服务。

所以,如果大家在MTA使用过程中有任何问题,都可以随时联系我们哦~我们一直都在努力,请协助我们共建更棒的数据工具产品!

 

联系我们:

如果您希望试用或者体验腾讯移动推送MTA,请访问MTA官网接入试用。

如果您对该功能有疑问、或者在使用中遇到了困难,欢迎您联系信鸽官网在线客服,或者发送您的问题邮件至:dtsupport@tencent.com

商务合作或业务咨询,请联系以下邮箱:mta@tencent.com​​​​

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部