背景
app内已完成rn模块的集成
jsbundle以静态文件的方式随app发版,缺少热更新能力
热更新能提高发版的效率
需要建设热更新包管理平台
热更新的概念
不用重新发布app版本,即不用更新app的安装包,在用户无感知的情况下,就可以对应用实现版本迭代、bug修复的技术解决方案称为热更新
对比常规开发流程而言,热更新的开发流程更加灵活方便,优势很多:
无需提交商店审核,实时发版
用户无感知,无需下载新应用,代价小
版本覆盖率高,新功能可快速触达用户,避免依赖app的版本升级
实现方式
react-native使用脚本语言js开发,具有“即读即运行”的特性,在“读”之前将之替换成新版本的脚本,运行时执行的便是新的逻辑了。js语言可以通过jsbundle的方式下载到app内,然后通过js引擎执行。继而可以实现最新的代码,不通过应用商店,直接下发到app内。
存在的问题
需要后台支持,不然无法实现包的分发
线上客户端会存在多个版本,根据不同版本的具体差异的不同,可能需要根据不同的客户端版本,下发不同的热更新内容
需要管理好app的版本和jsbundle包的版本,否则会出现线上问题
解决方案
jsBundle包需要一个后台服务来上传、管理和分发,需要区分不同的环境:feature、uat、production等
需要封装客户端sdk,封装向平台请求jsbundle包、传输解密、版本管理等功能
系统架构
包管理平台
提供应用管理、应用版本管理、js包管理、js包上传和分发、异常时的回滚、传输过程中的加密、条件下发等功能
客户端SDK
提供了向后端请求js包,js版本管理、传输后的解密等功能
主要流程
热更新流程如下
前置工作:
-
在热更新平台创建App应用: 即需要接入热更新的app。
设置应用名称、应用版本、管理员等信息
后续需要获取到当前app应用的所有上线版本(或许需要打通app的Jenkins平台自动维护版本,或者手动维护)。
-
创建js包应用:
选择需要投放的app,可以多选。
设置git仓库
设置打包脚本
-
App内接入热更新SDK。
配置好appKey
app启动会查询是否存在新版本,需要携带app标识、app版本号、本地已存在版本等参数
客户端sdk根据服务端给的数据,进行下载、回滚或者不进行操作。
如果需要下载,下载完毕后,本地签名校验文件完整性,然后存储到本地
上报下载成功/下载失败的信息给管理后台
-
包管理服务
- 服务收到客户端的请求后,根据参数返回当前app是否有新版本,以及新版本下载相关的信息。是否需要回滚等
-
App打开RN页面
查找本地Bundle信息,加载最新版本
上报版本加载成功/失败的信息给管理后台
管理平台发版流程:
-
js打包
设置目标平台:iOS/Android的Bundle包,
设置是否dev模式的包
-
发布
选择发布的环境:feature/uat/beta(测试环境)
选择投放的app版本:是一个区间,比如投放到1.0以上的版本, 1.0-2.0之间的版本
-
上线
从已发布的版本中,选择要发布的jsbundle。
必须是已发布过测试环境的包才可以操作上线,不允许直接上线
设置是否灰度
控制放量0%~100%
App应用管理
整体方案设计为多app的应用场景。接入sdk时,必须要使用appkey作为标识。应用管理中要管理appkey的生成,以及app版本信息的管理。
Bundle包管理
新建Bundle: 创建bundle的入口
bundle名称: 工作中,交流沟通的名称
唯一标识: 唯一id,代码中使用的名称
入口组件名称:bundle内允许多入口
投放的app: 当前bundle会投放到哪些app上
-
操作
查看详情: 更多细节信息,包大小,更新时间,版本号、打包、发布、上线、回滚等操作
编辑: 编辑基础信息:git仓库地址等
新建bundle
打包
[图片上传失败...(image-92aa41-1712815885556)]
发布
[图片上传失败...(image-6ebf8d-1712815885556)]
上线
[图片上传失败...(image-4d65bb-1712815885556)]
存储
条件下发
在发布一个包之前,需要在小范围内进行测试或者线上回测,比如特定某个 iOS 版本或者特定某个用户;在验证通过后再进行全量用户的下发。这时可以用到条件下发。
分发平台在发布包时可以选择使用条件下发,除上传包外,还可以填写条件语句,只有满足条件的设备才会获取到最新版本的包。
特定版本
设备id
用户ID
当包的下发状态处于条件下发,且相关参数与 SDK 上报参数中的条件一致时,才会将包发送给该 SDK。
白名单
支持设置白名单,只有白名单里的用户id 或者设备id才可以获取最新版本的包
设备白名单
用户白名单
数据统计
提供分日、分 App、分版本的包分发数据统计功能。
SDK 设计
SDK只需实现版本的查询和 bundle包的下载即可。
以 iOS 为例:
客户端 SDK 启动时会发请求询问服务端,根据服务端返回数据进行相应处理。客户端 SDK 会保存下载到的jsbundle包,避免重复下载造成的流量损失。具体流程如下:
App 启动同时 SDK 也启动,并发送查询请求给服务端,请求携带 App 标识、App 版本号等参数;
服务端根据收到的请求判断下发该app对应的配置信息,包括包版本信息、下载地址和其他一些信息。客户端 SDK 根据接口返回的数据判断进行下载、回滚或不进行任何操作;
如果未返回任何信息,说明不存在新版本需要下发,此时客户端 SDK 不进行任何操作;
如果返回的配置信息中,包的版本号等于本地生效脚本的版本,说明客户端保存的包已是最新的,SDK 直接执行本地保存的包;
如果返回的包信息中,包的版本号不等于本地生效脚本的版本,说明服务端有新的修复包发布,或发生了回滚操作,客户端 SDK 判断本地是否存在该版本的包,存在时直接执行本地包;不存在时发起下载请求获取最新的包,并在本地缓存,然后执行。
成本
从三个方面了对比成本问题
使用第三方那个付费服务
私有化codepush
完全自研
应用数
共计118个独立的功能模块。我们按照60%的业务使用react-native开承载,我们简单把每个模块划分为一个应用(实际可能比模块数多),预计需要71个应用。
pushy最大支持20个应用。无法支持,pass
Codepush 根据应用数量收费:40/月
codepush | codepush私有化部署 | 完全自研 | |
---|---|---|---|
成本 | 2840$/月 | 服务器成本 少量人力开发成本 | 服务器成本 人力开发成本 |
优缺点 | * 成本较低 * 功能受限于codepush,无法扩展 * 源码需要上传到微软服务器。存在一定的信息安全风险 |
* 成本在于人力成本和服务器成本 * 前期投入低,功能可渐进式演化迭代,更符合自身需求 * 源码无外泄风险,信息安全的风险较低 |
* 成本在于人力成本和服务器成本 * 前期投入多余私有化部署,功能可渐进式演化迭代,更符合自身需求 * 源码无外泄风险,信息安全的风险较低 |
私有化部署和完全自研的工作量对比
私有化部署 | 完全自研 | 备注 | |
---|---|---|---|
客户端SDK(提供版本管理和下载功能) | 使用codepush SDK | 自研SDK | 工作量: 私有化部署<自研 |
* 需要花时间研究codepush的sdk * 熟悉使用方法和私有化接入方式 * android 1人 * 5,iOS1人 * 5 |
* 需要设计版本管理和下载方案 * 开发sdk并接入 * android 1人 * 15,iOS1人 * 15 |
||
存储服务(提供jsbundle包的存储和增删改查等功能) | 可通过修改源码的方式,设置自己的服务器,快速部署,开发成本低 使用nodejs实现 |
可自己设置服务器,开发成本高 可自主选择编程语言 |
私有化部署<自研 N >> 5 |
服务器资源预估: 以71个应用为标准(当前2个应用): * 单应用的bundle大小600k以内(一般90k-300k就足够了) * 单应用全年迭代以10次估算(实际单一应用全年应该不至于迭代这么多) * 开发测试阶段的发版,按照50次为标准,(实际应该会在10-40次之间) * 上线按照每次需要紧急修复2个版本为标准。共上线3次,(大部分应该不需要紧急修复) 合计全年占用存储资源: 71 * 600K * 10 * (50 + 3)= 22260000kb = 21738.2812Mb = 21.22879Gb |
|||
* 熟悉源码,修改相关设置项 * 部署工作 * 后端:1人 * 2天 |
* 开发供sdk使用的接口 * 开发用户管理、应用管理、版本管理、编译、打包、发布、上线、回滚 * 部署 * 后端:≥1人 * n天(具体待评估) |
||
可视化管理后台 | * 需要自研 * 前端: 1人 * m天 |
* 需要自研 * 前端1人 * n天;后端1人 * n天 |
私有化部署 =自研 m > n |
优缺点 | 功能简单; 开发成本低; 可通过二次开发的方式,拓展更多功能; |
功能强大; 开发成本高; 后续可以拓展更多功能; |