美文网首页
集成第三方登陆SDK的优化方案

集成第三方登陆SDK的优化方案

作者: RoFF | 来源:发表于2016-11-23 16:24 被阅读741次

    在做项目代码静态分析的过程中,我们发现,第三方登录的SDK的代码占比在9%左右。从功能上看,这些SDK的主要作用有三个,一是账户登录,二是分享,三是能在微信里发送图片表情。从产品数据了解到,前两个功能用户使用比例不高。

    总结起来,就是说,第三方登录的SDK代码占比大,且不常用。因此考虑将这部分代码剥离出输入法的dex文件,实现按需加载。

    从广义上来说,按需加载也是插件化的一种。只是,考虑到这部分代码里没有资源文件(只有少量的assets),更新频率极低,且交互简单(单向调用为主),因此,可以忽略一般插件化中的复杂问题(资源文件合并等),做成一个简化的插件化方案。

    注:因为使用微信SDK的代码较多,且有在微信中发送图片的功能,暂时不做优化处理。

    要解决的问题

    要做成按需加载,首先要解决三个问题:

    1 如何制作SDK插件?

    SDK以jar的形式提供,需要把它转成dex文件。可以使用以下命令:

    # 把class文件目录转成jar包
    $ jar cvf sdk.jar <sdk_classes_dir>
    
    # 将jar包转成dex文件
    $ <SDK_PATH>/<SDK_VERSION>/dx --dex --output sdk.dex sdk.jar
    
    2 SDK的代码如何加载?

    SDK被打成dex包,使用DexClassLoader类来加载,原理可以参考Andrioid MultiDex和热修复。

    3 主应用和SDK的代码如何交互?

    主应用对SDK不可见,因此不能直接访问其代码,能想到的最直接的方式就是反射。输入法和SDK之间是单项调用关系,调用形式也比较简单,用反射方法也能够做到。

    本质上,这里要解决的是主应用(host)和插件(plugin)之间的交互问题,这就包括双向调用和功能扩展。因此,我们想用一种更好的方法来解决它。下面就详细说明两种解决方案。

    host和plugin交互的实现方案

    方案一:反射

    • 优点:直观
    • 缺点:代码可读性差,且容易出错;代码改动大

    方案二: 代理类+接口类+实现类

    • 优点:
      • 代码可读性好,改动小(跟当前集成方法比)
      • 方便实现双向调用
    • 缺点:
      • 需要添加的类多
      • 插件代码中需要加入新的类,打包流程需要改

    说明:使用反射方式时,对于SDK提供的API带有接口类参数的case,可以使用Java的动态代理技术,生一个跟接口类对应的代理类对象并传入API中。

    结合项目的实际情况对比两种方案,我们认为方案二优于方案一。而且,考虑到以后可能把更多的外围功能改造成插件,那就需要一种扩展性好的得方案。

    下面详细讨论方案二的实现细节。

    假设Foo.java是SDK中的类,提供了一个func()的API,下面的UML图说明如何用“代理类+接口类+实现类”的方式实现集成SDK。

    约定:XXX_Proxy是代理类,XXX_Interface是接口类,XXX_Concrete是实现类。

    在host中调用plugin的代码实现如下:

    image

    上边展示的比较简单的情况,实际情况比较复杂,可能API含有枚举类参数,接口类参数,接口类可能还有其它类的参数。解决问题的方法跟上边的差不多,都是加接口类。比如下边这个例子,Foo::func()使用到一个Callback接口类,这样就需要添加一个Callback_Interface,在Foo_Concrete中处理两个接口的转换

    image

    上图没法说清一个问题,就是Foo_Concrete如何访问到Foo_Interface接口?毕竟它俩不在同一个包中。这个还要看具体情况,看下一节的说明。

    代码组织和生成SDK插件

    分两种情况进行说明:

    1 没有SDK源码(适合集成第三方SDK的情况):
    • 调试阶段

      可以先把实现类和接口类都放在host中,SDK也以jar的形式引入进来,这样就能直接运行看到调用结果了。

    • 打包阶段:

      • host

      打包前把实现类从host中删掉,并保留其编译后的.class文件。

      注意:使用到接口类的时候可能产生匿名对象,因此编译器也会为生成一个对应的匿名类,注意把实现类和匿名类的class文件都保留出来。

    • plugin

      把上一步保存的.class文件,放到SDK jar的解压目录下,注意文件路径要跟反射时查找路径一致。再使用上边介绍的生成dex文件的方法来生成。

    2 有SDK源码(例如内部项目的子module)

    待更新:在做插件化的过程中发现一个更好的组织代码的方法,就是把接口类做成一个module,让host和plugin都依赖它,但是plugin打包时会把它排除掉(原理是debugCompile)。

    需要为SDK创建一个module,就是下边的plugin。

    • 调试阶段

      • host

      代码不变,只包括Proxy类和Interface类。

      • plugin

      需要Concrete类和Interface类,注意Interface类的路径跟在host中一致。

    • 打包阶段:

      • host

      跟普通流程一样。

      • plugin

      打包时需要删掉Interface类的class文件,否则host加载插件时会报错。

    优化后效果

    通过剥离SDK,输入法的两个dex文件共减小了1.2M,在art手机上,odex减小3.6M。主要好处是减小输入法应用的存储空间,在6.0.0上,从70M减少到66.5M。在dalvik手机上,优化后的dex文件不计算在应用存储空间内,所以没有明显效果。

    优化带来的问题

    功能还没开始测试,待补充。

    待解决的问题

    1 删除插件中Interface类的class文件。有两种方式
    • 一是半自动化模式(生成插件后)
      • 通过脚本,把dex中多余的文件或目录删掉,再重新生成dex文件。辅助工具有smali/baksmali。这种方式已经基本完成,还需要后期集成到打包系统中。
    • 二是通过gradle插件完成(生成插件前)

      开发中

    2 plugin调用host代码

    跟host调用plugin一样,有反射和接口两种实现方式。待补充。

    相关文章

      网友评论

          本文标题:集成第三方登陆SDK的优化方案

          本文链接:https://www.haomeiwen.com/subject/plsvpttx.html