37手游SDK架构分享

2 阅读6分钟

37手游SDK架构分享

大家好,我是加权,本篇文章向大家分享下发行SDK的架构。

需求背景

问题

作为发行SDK,通常需要面对的几大需求

  1. 渠道需求,研发接入发行SDK后,可以适配到TapTap,华为,应用宝等其他渠道
  2. 广告上报需求,广告投放时,需要接入不同的上报SDK,如抖音,腾讯等
  3. 皮肤替换需求,如特定游戏皮肤定制
  4. 试验性功能,如当前较常见的云游戏、直播等功能,特点时效果不佳时会移除

方案:插件化

以上需求,最大的问题是要解决功能灵活性的问题,需要做到面对不同的渠道、广告,游戏,做到功能灵活删减。

为此我们引入功能插件化的概念。

通常行业中的插件化是指

是将整个App拆分成很多模块,每个模块都是一个Apk(组件化的每个模块是一个lib),最终打包的时候将宿主Apk和插件Apk分开打包,只需发布宿主Apk到应用市场,插件Apk通过动态按需下发到宿主Apk。

这里我们只需要实现模块为apk,在切包时灵活组合即可,动态下发、加载可以视为高阶功能,本文不讨论。

方案架构

切包架构

切包是实现插件化的关键步骤,基本架构如下 切包基本结构

  1. 37 SDK*(蓝色):是指提供给研发接入的sdk,当不涉及对外API改动时,不需要更新
  2. 37 SDK(绿色):是指包含核心功能的apk包
  3. 渠道功能、广告工程(插件工程/模块):是用来构建插件apk的工程/模块

通过切包流程需要实现

  1. 覆盖37 SDK*(蓝色)的代码,实现功能更新
  2. 合并核心apk和插件apk,往最终包体中接入插件功能

具体的工程结构如下 切包架构

  1. 打包后台:统一管理sdk、插件、母包以及插件参数
  2. 切包主工程:核心切包逻辑
  3. 补丁工程:针对特殊游戏或者渠道定制化切包流程时使用
  4. 母包:由研发提供
  5. sdk apk:核心功能apk
  6. 插件apk:插件功能apk

代码架构

在具体实现中,为了实现功能的灵活组装,我们需要解决以下问题

  1. 插件不存在的情况
    1. 插件不存在,意味着功能不可用,我们在代码中需要进行特殊处理,避免程序异常
  2. 存在多个插件的情况
    1. 多个插件,意味着我们需要有手段选择具体插件,例如增加配置文件和后台下发配置
  3. 新增插件的情况
    1. 当某个功能没有预留插件功能,需要新增开发,我们需要有手段让旧版本也可以动态加载该插件功能

为了实现以上目的,代码构架设计如下(以登录功能为例) 代码基本架构 我们对功能实现划分以下概念

  1. 对外接口类:这里会直接引入管理类,是所有功能的集合,我们直接替换整个对外接口类就可以实现替换任意功能
  2. 管理类抽象:在代码实现中,大部分都是引用管理类抽象类,这样在替换实现时不会出现问题
  3. 管理类实现:管理类通常是同个模块下多个功能的组合,这样可以提供手段批量替换多个功能
  4. 功能抽象:单一功能的抽象,是最常用的插件层级
  5. 功能实现:具体的实现

对功能进行划分后,我们就可以根据实际需要,使用插件类对不同的类进行替换,来实现不同程度的功能替换。

关于如何处理无插件情况和插件配置化,在下文讲解

插件

参数

对于大多数第三方sdk,都有单独的参数,因此当我们通过插件接入第三方功能时,我们需要有手段处理这些插件的参数。

这里我们主要通过字符串资源获取参数,并通过gradle插件脚本处理参数文件的方式处理,架构如下 参数处理

  1. 打包后台:统一管理插件和参数,可以输出sdk和插件关联的参数到json中
  2. JSON参数文件:sdk和插件使用的所有参数
  3. 参数插件、切包工程:逻辑一样,将JSON参数文件中的参数转换成string资源

这里利用了安卓字符串资源加载的特点,可以做到

  1. 编译时修改参数
  2. 动态获取参数,可以通过切包修改参数

实例化

插件的实例化常见的几种形式

  1. 代码枚举
    1. 通过直接枚举所有插件类型进行实例化
  2. 配置文件/接口下发
    1. 根据配置文件的类型,将对应插件实例化
  3. 插件注入
    1. 插件apk自己注入插件实例到sdk中

我们实际会结合第2和第3种方法处理插件的实例化问题

配置文件/接口下发

根据配置实例化

关键步骤

  1. 通过读取文件或者接口下发的配置获取配置项
  2. 根据配置项,通过插件管理类获取插件实例
  3. 在插件不可用时,返回fake实例,避免程序异常

插件注入

根据配置获取实例时,我们可以指定插件类型获取,那么sdk是如何知道有哪些插件的呢,比较合适的方法是让插件自己持有插件信息,通过切包注入插件信息到skd中,这样sdk本身对插件完全无感知,解耦更加彻底。

代码架构如下图 插件注入

  1. PluginContentProvider:我们利用provider的特点,在应用启动时,通过解析AndroidManifest.xml中的meta-data来获取插件信息,然后注册到PluginManager中
  2. PluginManager:保存所有插件信息,注意在外部获取插件时才实例化插件
  3. Plugin Apk:插件apk,带有插件的meta-data信息,在切包时把插件信息合并到sdk中,实现注入
  4. 插件注解+脚本:使用注解标记插件类,并且利用脚本自动生成插件信息,可以提高插件开发效率和出错几率

至此,我们就已经完整构建了整个插件化架构,包括了插件的基本架构,sdk使用插件的形式,切包架构等多个模块。

总结

使用插件化架构需要多个模块互相配合,关键点如下

  1. 代码需要足够解耦,功能需要足够抽象
  2. 插件模块,包含注册插件、插件实例化等
  3. 切包模块,需要支持多apk融合,并且可以处理多插件参数等情况
  4. sdk模块,需要支持适配多插件情况
  5. 打包后台,需要管理所有插件

整个方案大致就是这样,欢迎大家在评论区回复讨论~