写点什么

热更新技术在游戏 SDK 中的实践

  • 2021 年 12 月 30 日
  • 本文字数:6735 字

    阅读完需:约 22 分钟

热更新技术在游戏 SDK 中的实践

一、前言


从产品运营角度来说,功能的用户触达是实现用户价值转化的最基本前提。所以如何快速将一个新的功能触达到用户,同时减少触达过程中对运营推广、用户带来额外的成本就成了一个必须被重视的课题。对于 APP 而言,以一个相对固定的节奏进行版本迭代,在一个迭代周期内,新版版基本可以达到一个相对较高的覆盖率。但对 SDK 而言,因为其并非直接面向用户,更像是一个 ToB 类产品,快速的版本迭代显然不是一个有效的途径,游戏 SDK 也不例外。

二、背景与目标

2.1 “三座大山”

  • 周期长,游戏 SDK 的功能触达用户需要一个月左右的时间。一个功能从需求到用户触达要经历 SDK 开发->SDK 测试→游戏接入游戏测试→版本发布一个漫长的周期。同时,游戏的强更与非强更也直接影响到最终的触达效果。随着国内对于游戏的政策监管力度日趋严格,经常会有一些针对未成年人保护、游戏防沉迷等方面的政策向需求。这类需求是有明确 DeadLine 的,如果触达周期过长甚至有被下架的风险。

  • 成本高,目前接入哔哩游戏 SDK 的游戏成百上千款,发布一个版本,如果要同时覆盖全部游戏,中间对于运营来说是一个巨大的沟通和推广成本。就算全部通知沟通到位,众多的游戏在接入过程中,因为引擎差异、游戏研发人员对 Native 开发知识的掌握程度不同、兼容性问题等,导致在技术支持上也要付出相当大的人力成本。

  • 灰度能力不完善,为了保证一个新版本的稳定性,我们一般会通过一两款游戏接入上线进行灰度验证。一方面沟通游戏接入需要花费一定的成本。另一方面,因为不同游戏之间因为引擎、玩法、接入第三方库等的差异,在整体灰度效果上,覆盖的场景比较局限。无法以一定采样率进行全平台的灰度。

2.2 目标

  • 实现功能快速触达;

  • 减少触达过程中对运营、游戏研发、技术支持以及用户带来额外的成本;

  • 具备全平台灰度的能力,进一步提升线上业务的稳健性。

如何翻越“三座大山”,实现业务价值转化呢?是否能将 APP 中惯用的热更新能力迁移到 SDK 场景中来使用呢?

三、热更新在游戏 SDK 场景下的思考

3.1 游戏 SDK 业务模式简介

因为游戏 SDK 与移动开发小伙伴们平时工作中接入的一些第三方 SDK 还是存在一定的差异。所以在分析具体业务与选型前,我先介绍一下游戏 SDK 的业务模式。

首先,应用场景不同。游戏 SDK 并非应用于原生 APP,而是游戏。而不同游戏因开发引擎(Unity、Cocos、UE4 等)的差异,在调用 SDK 相关 API 时需要封装一层 Bridge。同时因为游戏开发者对 Native 开发的技术数量程度参差不齐,在 SDK 的接入过程中,需要花费较大的人力成本去提供技术支持。

其次,业务流程不同。游戏 SDK 主要是为游戏提供统一的登录、支付等体系化功能,在流程上存在一些线性的固定逻辑。比如以登录为例,原生 APP 的登录基本是用户点击登录→提交账号信息→服务端验证→返回登录结果→登录成功/失败。但游戏的登录在这个过程中会增加很多强校验子流程,具体为:用户点击登录→提交账号信息→服务端验证→返回登录结果→三无账号检测→ 防沉迷检测 → 游客升级 → 实名认证检测 → 防沉迷提醒→ 登录成功/失败。这些额外的固定流程在每次登录都必须强校验,且流程不可阻塞。任何一个环节检测不通过都会导致登录失败。

最后,界面交互不同。因为游戏 SDK 的所有功能界面,都是展示在游戏场景之上,所以所设计的页面都是以弹窗的形式进行展示。

下面是一个登录入口的截图,希望可以帮助您对游戏 SDK 业务场景有一个大概的了解。


图 3.1 SDK 登录入口截图

3.2 常用的热更新方案

目前行业内比较常用具备热更新能力的方案大致可以分为四类:动态化布局、虚拟运行环境、业务插件化和 Web 容器增强。

图 3.2 不同方案的代表性框架

 3.3 业务场景分析

具备热更新能力的方案百花齐放,我们该如何选择呢?鲁迅说,没有最好的技术方案,只有最契合业务的方案。


所以我们首先要做的就是对业务场景进行审视。我们将业务大概划分为三类:

  • 核心业务 —— 对于游戏 SDK 而言,核心业务就是指登录和支付。这部分业务是基础也是重点,对性能和稳定性有着极高的要求。

  • 附加业务—— 比如修改密码、账号升级等。生命周期长,需要长期维护;同时需求整体稳定、沉淀性高;业务逻辑结构相似,提炼性强;用户触发频率相对较低,对性能有一定的敏感性,但不追求极致。

  • 展示型业务—— 比如活动、公告等。内容调整频繁,整体逻辑性不强以展示为主。有一定的可沉淀性,对性能极致性不敏感,更多的是追求对需求和内容变化的快速响应。

3.4 技术选型

明确了不同业务场景的特征与需求重心,回到问题本身,我们如何选择合适的技术方案呢?

布局动态化方案通过布局引擎,对动态下发的布局模板进行解析,底层通过 Native 组件进行承载,保证了一定的动态化能力,同时充分发挥 Native 极致性能。但一个适配双端的页面模板的开发需要一定的配套设施开发,方案落地有一定的成本。对于需求相对稳定、业务逻辑可抽象性强的附加业务类型匹配度较高。

web 容器增强方案通过提供一个高性能 WebView 容器,同时沉淀大量通用性 bridge 来承载 html 页面,实现和移动开发框架的有效结合,开发成本低,整体性能与 Native 有一定差距。对内容变更频繁但对性能要求不追求极致的展示型业务比较符合。

业务插件化是提供宿主 APP,通过远程下载代表各个功能模块的插件,实现资源和代码的动态加载。整体开发模式与现有 Native 迭代没有太大差异,性能和稳定性最高,但仅支持 Android 平台。对登录、支付等核心业务插件化后业务价值较大。

图 3.3 不同方案优缺点与适用场景对比

不同技术方案各有优劣,适用场景也有所差异,很难通过一种方案完全匹配业务需求。所以我们索性就采用新的方式——多种方案相结合,将 SDK 容器化,根据不同的需求类型和业务场景选择最佳的容器来承载,打造一个集多种容器于一身的复合型热更方案。

四、方案设计

4.1 整体架构

本方案整体可以分为服务端、SDK、发布运维系统和质效保障四大部分。其中:

  • SDK:采用分层化设计,自上而下将 SDK 分为应用层、协议层、容器层、框架层、组件层、基建层和系统层。应用层主要是为游戏研发提供相应的 API 能力,如登录、支付等。协议层是建立统一的路由协议,对业务模块进行模块化拆分和路优化改造后,方便进行统一的调度和交互;容器层是本案的核心,即建立多种类型的容器承载不同类型和场景的业务需求;框架层主要是对容器层能力的支撑和管理,如插件管理、引擎管理、模板管理等。组件层是将不同的业务模块进行组件化拆分,化整为零实现模块解耦;基建层主要承载网络、图片、APM 等通用能力;系统层主要是指 Android 和 iOS 双端的系统服务;

  • 服务端:主要负责根据不同用户的信息状态(设备信息、游戏信息、用户信息等)进行筛选匹配,完成产物的动态下发。

  • 发布运维系统:负责从发布、灰度配置、相关性能指标收集、全流程性能监控等工作。

  • 质效保障:建立完善的设计和编码规范,结合自动化检测能力,确保开发质量可靠;沉淀统一的工程手脚架、模板和组件提升开发效率。

通过对 SDK 的分层化设计改造,以多容器化模式承载不同的业务场景;建立统一的业务路由协议,对业务模块进行路优化改造,实现多容器之间的调度与交互;通用组件和基架做下沉处理,实现多容器多业务服务用;最后建立完善的发布运维系统,保障动态化产物从构建→配置→白名单内测→灰度→发布等全流程的跟踪监控,结合完整的流程规范与能效工具,保障整个系统的高效性与稳定性。

图 4.1 方案架构图

4.2 子系统设计

4.2.1 动态化路由协议

4.2.1.1 整体思路

动态化路由总体设计思路是通过对业务组件进行组件化拆分,指定路由入口。然后根据业务流程,通过服务端动态下发相应的业务路由配置表。当新增业务模块或现有业务模块有调整时,直接动态修改路由配置,即可完成新业务的调度与新流程的调整。有两个核心接口,通过 RouteMapProcessService 定义完整业务流程的路由表。通过不用业务模块实现 RouteProcessService 并完成相应的状态和逻辑处理后,实现流程的流转。

图 4.2 RouteMapProcessService 接口

图 4.3 RouteProcessService 接口

 

4.2.1.2 路由协议规则

路由协议整体采用 Scheme URL 的格式,主要分为 Scheme、group、path、固定参数和自定义参数几个部分,其中:

  • Scheme:自定义协议,主要是方便内部和游戏研发侧对路由协议的调用

  • Group 和 Path:模块名和路径名,按需加载路由映射表

  • 固定参数:一些与路由流程调度相关的必要参数,如:allow_failure,标识该流程是否为强校验流程。

  • 自定义参数:不同业务场景所需特殊字段,如:通用 web 容器路由需要配置 url 参数

图 4.4 路由协议结构示例

4.2.2 多容器

4.2.2.1 插件化容器

插件化容器我们采用的是 VirtualAPK 方案(此处手动鸣谢 VirtualAPK 开源项目组)。其基本原理主要有三部分:

  • 合并素组和插件的 ClassLoader;

  • 合并插件和宿主的资源;

  • 去除插件包对宿主的引用。

整体功能比较完备,支持 Android 四大组件,四大组件实现原理:

  • Activity:采用宿主 manifest 中的占坑方式绕过系统校验,然后再加载真正的 Activity;

  • Service:动态代理 AMS,拦截 Service 相关请求,将其中转给一个虚拟空间(Matrix)去处理,Matrix 会结果系统的所有操作;

  • BroadcastReceiver:将插件中静态注册的广播重新注册一遍;

  • ContentProvider:动态代理 IContentProvider,拦截 Provider 的相关请求,将其中转给 Matrix,由 Matrix 接管。

具备较好的兼容性和较低的侵入性。整体框架如下图所示(图片来源于网络):

图 4.5 VirtualAPK 架构图

因为 VirtualAPI 从 2017 年开始已经停止维护,所以我们针对整个框架做了大量的升级和兼容工作,主要包括:

  • 升级对高系统版本的支持(目前已完美适配 android 11)

  • 升级对对 androidx 的支持

  • 升级对 gradle plugin 高版本的兼容

  • 优化插件资源加载(包括 res、layout、theme、so 等)

  • 优化对四大组件中 Service、Broadcast、ContentProvider 的支持能力

  • 优化对类加载器、插件包安装等方面能力

  • 还有一些机型适配等方面的兼容性问题

4.2.2.2 动态化模板容器

动态化模板容器我们采用的是基于 FlexboxLayout 渲染引擎(谷歌开源框架)的 Native + DSL 方案。动态化能力建设主要可以分为四个部分:DSL 定义、动态视图管理、视图构造和数据绑定。

  • DSL 定义:基于 Flexbox 布局系统进行视图布局,采用 JSON 语言描述视图结构,使用属性区分视图控件类型。其中常用的属性大概有布局属性、视图属性、数据属性、交互属性等。

  • 动态视图管理:基于 DSL 语言进行页面样式编写→ 进入相应的动态化页面时请求服务端样式接口→ 服务端根据客户端相关信息(设备信息、游戏信息、用户信息等)进行策略匹配后下发模板→ 客户端接受到模板信息后进行校验、缓存、解析和渲染。

  • 视图构建:客户端为每一个 UI 组件创建对应的解析器,当客户端获取到动态模板后,由解析器觉得采用什么原生控件进行承载。因为业务场景的特殊性,目前在组件支持上主要以 ImageView、TextView、Button、EditText 等基础组件为主。

  • 数据绑定:对于一些接口数据,直接通过 NodeJs 服务在下发的页面模板中进行相应属性的配置。对于本地资源则在编写模板时进行指定。解析器完成对控件相应参数的设置。

整体架构如下图所示:

图 4.6 动态化模板方案架构图

4.2.2.3 通用 web 容器

对于通用 web 容器相信很多 app 和场景下都会用到,就容器而言整体实现方式也大同小异。这里主要介绍以下我们 SDK 容器的一些差异点。一方面因为游戏 SDK 本身场景的特殊性,页面基本以弹窗形式展示。所以我们对于整个容器的样式做了大量的个性化配置能力。包括主题(原生主题、游戏主题)、样式(全屏、横屏、竖屏、特定大小、特定比例、自定义等样式)最大限度去保证不同游戏,不同需求在配置时的需要。另一方面就是 JsBridge 能力,我们梳理了目前业务场景中可能用到的一些 bridge,包括(登录态、网络、埋点、设备信息、参数传递、页面跳转、双向交互等等)。

4.2.3 发布系统

对于发布系统,首先采用基于 jenkins 实现插件、动态化模板等动态化产物的自动、持续构建。然后,设计了一个从灰度配置、过滤配置和排除配置三个步骤的灵活发布方案。

  • 灰度配置:主要分为基于用户进行灰度分桶和基于设备进行灰度分桶两个维度。支持千分之一级别的灰度粒度。主要针对新功能热更时按 0.1% -> 100%施行逐渐放量发布,最大限度降低可能发生的异常事件造成线上事故的损失。

  • 过滤配置:主要从 SDK 版本、游戏、渠道、ROM 版本、网络环境、设备品牌、设备型号等维度进行灵活的配置,同时支持用户白名单配置。主要针对一些定制化需求和定向化优化需求。

  • 排除配置:排除配置从维度上与过滤配置相似,也是从 SDK 版本、游戏、渠道、ROM 版本、网络环境、设备品牌、设备型号等维度进行配置,同时支持配置多组。但作用有所差异,主要用于线上偶发性缺陷和一些兼容适配问题的降级。通过灵活的配置方案,结合对热更新产物从下发、下载、应用等全生命周期的数据打点,对异常情况进行实时监控,发现问题快速进行配置兼容、回滚、修复,确保线上业务稳定运行。

通过灰度配置,实现灰度逐渐放量能力;通过过滤配置,可多维度灵活配置灰度范围;通过排除配置,规避一些可能发生的线上兼容性问题。三管齐下建立一个相对完善的灰度发布系统,实现全平台灰度能力。

五、实践

5.1 不同方案在业务侧的尝试

插件化方案目前主要应用与登录及其子流程(实名认证、防沉迷、未成年人保护等)、悬浮球(截屏、自动录屏发布、一键直播等)。选择这两个场景主要处于两点考虑:一方面插件化本质上采用的是 Native 开发的方式,在整体性能和稳定性上可以得到有效保障,同时对端能力的依赖上没有任何瓶颈。另一方面从业务场景上来说,这两个场景可能发生功能拓展的可能性较高,作为插件化改造,后续的版本迭代上适用性更强。

动态化模板方案目前主要应用于账号系统(修改密码、找回密码等)二级页面。这些页面与 Native 之间有较多的逻辑交互,但交互的方式可以被很好的抽象封装成通用能力。具体场景如下图所示:

图 5.1 动态化模板配置页面一

图 5.2 动态化模板配置页面二

通用 web 容器,目前主要应用于双协议(用户协议、隐私协议)和一些游戏系统公告等场景。这些场景具有重展示轻交互的特点。内容上有较高的动态化需求,但没有太复杂的逻辑,性能上也没有过高要求。具体场景如下图所示:


图 5.3 Web 容器应用场景——隐私协议


图 5.4  Web 容器应用场景——公告

5.2 上线效果

5.2.1 产物下发及应用情况

以插件为例,图 5.1 为"get_config_success",即成功获取插件配置信息数据;图 5.2 为"download_success",即成功对插件包进行下载的数据;图 5.3 为"install_success",即成功完成对插件包的安装情况数据。其中配置下发->成功下载转化率为 97.24%(其中绝大部分为网络异常,此部分有进一步优化空间)下载成功-> 安装成功转化率为 99.99%,整体框架稳定性和兼容性得到有效验证。


图 5.5 成功获取插件包配置信息数据走势图


图 5.6 成功完成插件包下载数据走势图


图 5.7 成功完成插件包安装数据走势图

5.2.2 紧急回滚

同样以插件为例,2021-11-02 11:00 点开始对插件进行回滚。回滚后下载和安装数据断崖式归零,同时成功卸载的日志大量产生。具体数据情况如下图:


图 5.8 插件回滚后成功下载数据走势图


图 5.9 插件回滚后成功安装数据走势图


图 5.10 插件回滚后本地卸载成功数据走势图

六、 避坑指南

1)R8 兼容:插件框架在 gradle 版本升级后,低版本 R8 生成的 mapping.txt 文件存在大量重复的映射记录,这样的 mapping 文件直接进行 applaymapping 时解析过程会因报错而终止插件构建,无法构建成功。直接使用高版本 R8 对低版本进行覆盖构建结果中,插件功能存在一些不可预见的异常,需要在构建时,先对 mapping.txt 进行指定,然后再构建过程中 applymapping 指定的 mapping 文件,确保构建和功能正常。

图 6.1 mapping 内容示例

图 6.2 动态处理 mapping 文件脚本

2)混淆 mapping 处理:游戏 SDK 是以 aar 形象进行交付,本身在交付前进行了一次混淆。同时不同的游戏完成 SDK 接入后,会再一次进行混淆,不同游戏的混淆结果不同,且无法将混淆结果回调给 SDK,比如交付的 A.class,游戏打包后变成了 B.class 或者 C.class。如果要求游戏接入方不做混淆处理,对游戏和 SDK 都存在一定的安全隐患。如果 SDK 对可能被插件调用的 API 做特殊处理不进行混淆,则需要大量的人工介入操作,且无法完全预计后续业务迭代过程中可能需要用到的 API。可以采用在构建混淆结束后,读取混淆结果,输出混淆结果为 proguard-rules 规则,确保游戏二次混淆后,游戏 SDK 不会被再次混淆。

图 6.3  输出混淆规则示例

七、未来发展与规划

1)建立完善的监控预警机制,实现自动通知、降级、回滚的分级预警的干预措施。

2)基于大数据和用户标签,实现千人千面的个性化动态下发,提供精细化运营能力。

八、总结

本案为我们在游戏 SDK 侧的一点尝试,以动态化路由协议为媒介,多种容器并行的热更新方案。很多地方有优化的空间,但从效果上也基本达到了预期。感谢您能阅读到最后,希望在某些设计思路上能让您有所收获。如有不足之处,欢迎在下方进行评论指教。


文 / 哔哩哔哩游戏 - 大前端

发布于: 刚刚
用户头像

bilibili游戏技术 2021.05.20 加入

分享bilibili游戏技术干货

评论

发布
暂无评论
热更新技术在游戏 SDK 中的实践