【Android SDK 开发】谈谈Sdk迭代开发设计需要考虑的方面

原文地址:https://mp.weixin.qq.com/s/mXFBaoRHGnzb3DIlCeeEzA

作者:Trilen

链接:

http://blog.csdn.net/u010019468/article/details/75425742

本文由作者投稿推送。

 

Sdk开发设计与Apk开发不同的地方还是有些明显的不同之处,明显的区别是使用对象不一样,Sdk是基于开发者使用的,都是有一定的开发水平,相对于Apk用户而言基本是大众用户,做得好不好不仅仅是运行起来性能、稳定行以及功能,还需要顾忌开发者调用是否方便、嵌入成本、更新维护成本,因为Sdk是作为一个库给对方使用,但又不是开源的,还得注意保护知识产权,个人认为一个不错优秀的sdk开发需要注意如下方面:

 

1. Sdk架构设计-模块化、组件化、插件化

 

便于层次分清,避免代码臃肿,提高代码阅读性以及单元测试。可以参考下《Android彻底组件化方案实践》http://blog.csdn.net/u010019468/article/details/76547798 如何组件化的思路,但是实际下来顾及到各自的项目大小,可以先从抽离、独立各个业务层做起,尽量分清层次,来提高项目层次感,降低维护难度。

 

2. Sdk更新修复能力

 

一个成熟的热更新框架对降低使用者嵌入成本、快速应用业务发展以及及时修复bug很有必要,但是目前市场开源的框架都是针对Apk热修复的,其实要针对sdk只要从中抽离出核心思想即可,目前见到具有自动更新能力的sdk实现思路有 :


 1、在PathClassLoader中把更新下载下来的dex文件插入到pathList中的dexElements中 
这种方式适配起来麻烦,且会有品牌机型问题,且只能更新逻辑功能,对资源不能修改 
 

2、使用DroidPlugin、VirtualApk等开源框架 
每个开源框架都有一些特点,需要结合起来使用,并最新这些开源的使用范围以及问题性 
 

3、定义DexClassLoader来实现动态加载,判断版本号选择加载最新版本 
 

下面图片来自滴滴开源插件框架一文中:VirtualAPK和其他主流开源方案的对比: 


这里写图片描述

 

3. Sdk接口Api设计统一、简单

 

有统一接口设计避免使用继承方式来调用sdk的api,Api接口设计简单方便使用,命名让使用者一目了然。参数设计要利于扩展,避免sdk升级时发生找不到方法的异常。 


在需要调整SDK API时,优先选择添加新方法,而不是在原方法上修改.对于实现相同功能的新方法,尽可能的要兼容原始方法,这样避免升级时找到不方法或者使用者更新时候避免重新改写接口;在需要废除某些方法时,需要在正式版发版前使用@deprecated标识,并给出替代方案和废弃的时间(通常是SDK版本号)

 

4. Sdk资源内容组成设计-接入和维护更新便利性

 

做过很多sdk,也接触过不少,最头疼的是那种资源特别多,文件命名混乱,类路径简单,这些都会导致开发者在接入时候麻烦,更新版本时候分不清对应内容归属者,尤其是一些资源文件,甚至还遇见过命名空间一样情况。故结构一定要清晰简单,命名清楚,对于有res资源的Sdk可以通过库文件(aar,lib)导入,而不是零散的给与。

 

 

5. Sdk接口回调设计

 

要对任何情况下考虑到有回调响应,避免出现使用者调用之后阻塞没有反应情况,例如网络异常,超时处理,调用过快,异常等情况下要有回调。 
 

同时必须提供明确的错误信息回馈给使用者,方便接入者自己就能解决接入中问题,而不是什么问题都需要开发者亲身去维护,回调错误中采用errorCode+errorMsg组合,最好不宜使用通过调试日志形式显示错误信息,这样一旦忘记关了调试模式,泄漏了信息就止这样。

 

6. Sdk日志设计

 

日志:用户行为日志(埋点)、调试日志、运行异常日志

 

用户行为日志(埋点) 
 

作为开发者都希望了解自己的sdk使用中表现,运营都希望得到业务相关数据,这时开发一套完整数据统计就很必要,包括sdk运行稳定性,兼容性数据,异常数据,同时上传用户相关行为数据。做到这些的同时还要注意如下: 
 

1、日志服务能够记录有效的信息,在SDK要关键位置进行打点,避免浪费用户流量,减少上传不必要的数据。 
 

2、日志服务上传日志信息到服务器时,要保证最大的可靠性,不能发生上传失败后抛弃日志的情况,避免数据分析时数据不完整,缺乏可靠性。做到不论当前网络情况如何,都要保证数据完整性上传 
 

3、日志服务不能影响对正常的操作流程有过多的性能影响,SDK产生的日志信息往往是非常多的,因此必须考虑日志IO操作所带来的开销。

 

调试日志设计:在维护中分析问题,经常需要结合日志来分析问题,这时候如果Apk已经发布没有日志、或者如何避免使用者忘记了关掉日志而导致泄漏敏感数据。所以要设计可以不论是否发布状态都能强制打开(强制改成调试状态),发布之后统一关闭日志(服务端控制)

 

7. Sdk运行稳定性捕获自身异常

 

不要出现未捕获的异常,应该在接口内部进行统一的全局对未捕获异常进行捕获,并上报日志供分析改善Sdk,同时也帮助调试中分析问题。

 

8. Sdk自身内容安全性

 

sdk的安全性用来对抗外界的反编译,保护内容不被窥探,详细如下:

原文地址:谈Android接入Sdk开发的安全性方案https://blog.csdn.net/u010019468/article/details/72794442

Android 接入sdk是指某公司作为能力提供方经常以接入Sdk形式来暴露能力供用户使用,这样的能力对公司来说是财富实现的资本,不能被外界窥探或者破解成免费使用,那下面来分析下有哪些危害以及解决方案。

 

裸sdk的危害

 

裸Sdk是指sdk未进行加固,直接简单的通过反编译工具就可以看到其实现,现在混淆不算加固,但很多sdk就仅限于混淆而已,就没有其他安全措施了,这样就很容易暴露如下问题:

  1. 窥视内部实现方法

  2. 暴露了内部调用流程

  3. 避开流程直接调用关键代码从而破解流程以达到某种目的 
    这种情况很多,如第3方sdk功能存在推广或者界面不符合咱们使用,这个时候需要绕过其流程,如脱掉界面,直接绕过界面显示在按钮点击之后的功能才是我们需要的,这个时候可以查看其调用的方法,不能显示调用就直接反射调用。

  4. 泄漏核心技术

 

Sdk调用入口未鉴权

 

未鉴权导致Sdk存在随意被其他未经授权用户调用的情况,或者用来未经授权的应用使用Sdk,导致能力未经许可而导致损失

 

如何提高安全

 

  1. 关键核心功能实现隐藏

    java代码实现代码很容易被反编译,转而用Ndk开发实现生成so动态库,提高反编译难度,进一步可以通过加固so文件加密,从而更难被反编译查看。同时要注意的so作为核心库防到了反编译时也要注意对方可以直接使用so库,所以要对jni接口调用进行鉴权判断,入口调用栈检测,以及串联下上下文,尽量避免仅仅是个工具库,不要太解耦。

  2. 文件加密及Sdk加壳加固

    Sdk中dex文件和so文件加密从而屏蔽外部窥探,提高反编译难度。并且进一步通过jni本地方法来屏蔽核心方法,在so文件内解密dex文件并加载,Sdk暴露的接口全部通过jni来跳转或者通过反射跳转到核心dex内实现。其中对so文件加固可以参考:对Native层(so文件)进行加固

  3. 网络安全

    如果网络请求不安全,直接被抓包,接口和参数直接被窥探从而被模拟,提高安全的话直接用https,如果条件不允许,那至少得加密传输,对参数加密,加密算法必须得so文件来实现。同时配合服务端做一些防刷,有限性鉴定。同时也要简单地对抗网络代理抓包

  4. 方法调用栈检查

    如果不对调用栈入口检查,就会出现方法被肆意调用,用户不受控制的调用干扰调用流程,如上述直接去掉sdk调用中出现的界面,所以可以直接在某个方法入口处先检查下此时的调用栈顺序是否符合流程的设计,可以检查下第一个入口,以及后上方的几个入口是否为设定的流程。

  5. 方法入口统一扎口

    Java实现方法在sdk,总能通过反射任意调用各个方法,单独使用某个方法来实现某个功能,所以假如我们经常为了共用功能而经常封装成单独方法,这样就为避开sdk设计的流程而单独调用提供了机会,这时会有人会说那我把所有的功能用一个方法实现来达到避免流程干扰,这样显示不切实际,那样的代码又长又臭,没有人敢来维护。即使如此,有个工具通过javassit来实现注入代码从而干扰代码执行流程。那到底有没有好点的办法来统一扎口呢?个人觉得比较好的方式就是通过Ndk来实现封装,毕竟jni接口入口可以独立出来使用,比起java代码反编难度大,调试难,又不好注入代码,更难随意调用ndk内部c++实现的相关方法。 
    用一个jni入口暴露出来给java层调用,内部封装整个流程,很好避开大部分破解流程。

  6. 云方案

    这种方案要是能行的话,觉得是最安全的,绝对避免了核心方法的泄露,这种sdk通过请求调用云端直接获取结果,如市场中大多图像识别sdk都是这样来做的。

  7. 调用鉴权

    主要可以分为静态鉴权和动态鉴权。前者主要是用来检查固定参数,如appKey和appSecret,以及结合限定应用包名(packageName)和应用名(appName)达非到限定sdk被未经授权而扩散使用。 
    动态鉴权就是类似授权令牌一样由服务端分发token,调用着带这token来访问接口,这里面就涉及了多次本服务端和目标服务端多次交互,生成token透传给使用者,被调用者再次跟服务端交互校验调用者来源合法性。这种是保护token的生成规则而不在乎是否泄漏使用,即使泄漏,也只是表面这个合法使用者在使用,而不在乎是模拟的合法使用者,即不会生成出现新的合法调用者。

  8. 字符混淆以及字典混淆

    字符混淆用来对抗反编译工具,让字符常量不显示或着显示成16进制数组。 
    详细见这边文章:http://bobao.360.cn/learning/detail/3704.html?spm=a313e.7916648.0.0.11b0b6cqnOKtJ 
    字典混淆是指通常混淆字典都是abc…可以通过配置特殊字典,让反编译者看得怀疑人生,有常见开源项目示例如下: 这里写图片描述

开源项目地址: 

https://github.com/ysrc/AndroidObfuseDictionary

 

9. Sdk性能高效

 

(1) 减少内存占用 
在不使用多进程的情况下,SDK服务和宿主程序运行在同一进程中,这种情况下必须要求限制SDK内存的占用,不能因为说因为我们SDK占用太多的内存资源,导致应用的存活时间变短,但是这种抢资源必然会总宿主内存使用造成影响,从而会影响apk运行性能。 
 

(2)减少内存抖动 
在占用更少内存的前提下,SDK设计者必须刻意的减少反复GC造成的内存抖动问题,避免同一时间创建和回收对象,做到正确时刻正确创建对象。 
 

(3)减少电量消耗 
尽管很多时候无法对电量消耗做一个很好的权衡,但是仍然有一些可以参考的做法,比如减少使用耗电模块的时间.比如在使用定位服务时,不要求非常高的精度下优先使用网络定位而不是GPS定位. 
 

(4)减少流量消耗 
这里就是对Sdk内部网络请求尽量规范,充分利用每一次网络请求发起,复用资源,多次发起都会带来消耗。对数据内容不宜原始数据,尽量能够做到压缩上传。同时要减少后台进程频繁唤醒,做到有效控制。 
 

(5)减少同步阻塞主线程操作 
这样提高程序运行效率,避免阻塞主线程,导致app启动变慢或交互响应不及时。尽量提高程序执行效率,使用更高效的方法或api,以及异步初始化.

 

10. 细节事项 
 

1)Sdk开发生成的体积不要过大,尽量能够压缩库或文件,在加载时候解压出来,避免增加使用者Apk的体积大小。 
 

2)Sdk中的方法数不要过大,给Apk带来方法数超限额的问题尽量避免。同时结合运行高效来说以及安全性,过多的方法不安全且增加运行成本,影响应能。 
 

3)Sdk接入帮助文档要详细清晰,要做到接入者看文档就可以成功接入,并且有问题可以根据文档接入,而不是总要联系维护人员。

 

11. Sdk打包工具开发 
 

结合Android Stuido中Gradle强大的自定义功能,可以开发插件动态打包,组件化动态集成打包、动态修改字节码。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值