React native增量更新,支持多入口多业务。
后台雏形代码已经上传github:https://github.com/xagreenpoint/react-native-diff-update-server
目前业界还没有一款足够适应大部分增量更新场景的方案,要么不支持多业务入口,要么没有开源,要么没有开放后台源码。基于这些需求,我们想通过开源社区的力量,大家一起打造出比较完善易用的增量更新框架,因此,需要大家的参与及支持,为RN的生态系统做点儿小贡献(为了项目的灵活自由发展,我们采用了MIT许可)。
目前增量更新采用native实现,后续会暴露功能接口,供js控制更新流程。
为了更好的用户体验,所有业务包进行工程内置,增量包后台下载合并操作,App下次启动更新生效(后续增加立即生效功能)。
增量算法采用bsdiff差异算法。
客户端与后台相对独立,可集成客户端增量更新模块,自己构建后台版本接口,也可采用我们后台框架搭建(暂时还未开源)。
工程根目录执行:
npm install --save react-native-diff-update
react-native link react-native-diff-update
打开工程可以看到Libraries
下LDRNDiffUpdate
就是增量更新模块。
npm install --save react-native-diff-update
在工程Podfile
文件中加入:
pod 'LDRNDiffUpdate', :path => '../node_modules/react-native-diff-update'
然后执行:pod install
假如原有工程已经存在SSZipArchive库,与本pod spec冲突,建议采用v1.0.5
版本,此版本没有将SSZipArchive进行分离,因此更容易处理冲突问题,install时增加版本号:
npm install --save react-native-diff-update@v1.0.5
这样集成到工程中时,只需要把原有工程SSZipArchive删除即可。至于SSZipArchive工程分离方式,目前没有找到比较好的方法,可以参见code push
的处理方式也是这样。
microsoft/react-native-code-push#241
首先进行相关配置,配置信息在LDRNBundleList.m
文件中,核心设置有:
appKey //应用唯一标识
rnVersion //当前工程使用的React Native版本
originBundles //工程内置的业务bundle
originBundlesHash //业务bundle的md5 (可选)
entryJSName //bundle入口文件名称
patchFileName //补丁bundle入口文件名称
versionUrl //版本请求接口地址
配置信息不应该直接修改LDRNBundleList.m
源文件,更合理的方式是创建LDRNBundleList的分类
,当然只需设置需要项:
@implementation LDRNBundleList (setting)
+(NSString *) appKey {
return @"11111111";
}
+(NSString *) rnVersion {
return @"0.48.3";
}
+(NSDictionary *) originBundles {
return @{
//首次集成置空
};
}
@end
注意首次集成时originBundles设置为空字典,否则在工程中找不到zip文件,会引起程序崩溃。等增加zip文件后再进行配置。
配置好信息后,在自己的需要加载bundle的viewController
中引入头文件#import "LDRNDiffUpdate.h"
,然后指定jsBundle文件名即可(每个jsBundle代表一个独立的业务):
NSURL *jsCodeLocation = [LDRNDiffUpdate jsBundleUrl:@"LDBusinessEntry"];
在Android中有时候npm 的link会不成功,这时可通过如下步骤进行配置:
找到 android/settings.gradle文件并添加:
include ':react-native-diff-update'
project(':react-native-diff-update').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-diff-update/android')
找到 android/app/build.gradle 文件并添加:
dependencies {
compile project(':react-native-diff-update')
}
配置完后需要在应用启动的第一个Activity的onCreate方法中调用
LeadeonDiff.init(this, this);
第一个参数是应用程序的上下文,不能为null,第二个参数是CopyCompletedCallback接口的实现,当首次复制完assets目录下的rn模块后会回调此接口。
每次启动app时,检测本地所有jsBundle是否有更新,如果有更新则根据下载条件浸没下载,再根据加载策略进行实时更新还是下次启动更新RN业务。也可以对有问题的jsBundle业务进行回滚操作。
接口名称[POST]:/RN/patchVersion
请求body:
{
appKey: "", //app唯一标识
appVersion: "", //app当前版本
rnVersion: "", //react native集成版本
platform: "", //平台ios android
resBody: {
"LDBizName1": "1.2.0", //业务名称: 版本号
"LDBizName2": "1.1.0",
...
}
}
响应body:
```json
{
retCode: '000000', //响应码:000000代表成功,其他代表失败
retDesc: 'xxx', //失败原因描述
rspBody: [
{
"loadType": "ReactNative", //业务类型:ReactNative、HybridApp
"zipPath": "https://xx.xx.com/patchzip/LDBizModuleName1.zip", //下载路径
"version": "1.3.0", //业务版本号
"moduleName": "LDBizName1", //jsBundle名称
"zipHash": "xxxxxx", //zip文件md5值
"jsbundleHash": "xxxxxx", //差异合并后js文件md5值
"downloadNow": "3", //0:总是下载, 1:wifi下载,2: 4g和wifi下载
"loadNow": "true", //true:即刻更新,false:下次启动更新
"needGoBack": "false", //是否需要回退版本
},
...
]
}
增量更新安全主要涉及到jsBundle,jsBundle只是js代码,虽然经过混淆处理,但依然是纯明文,虽然可以对js做加密处理,但这种行为不太明智。
主要考虑以下安全因素:
-
网络接口安全。这点其实和增量更新关系不大,版本接口复用原有后台安全策略即可。
-
jsBundle篡改安全。为防止篡改js入侵app业务,需对jsBundle做签名校验,一是下载文件后校验其完整性,二是每次加载jsBundle时校验,这样就防止了整条链路篡改风险。
-
jsBundle业务安全。因为jsBundle是明文,所以业务中需要进行加解密等敏感措施就不能在js侧实现,解决的办法是native实现加解密暴露给js接口调用。加解密可作为RN独立module实现,不在增量更新体现。
(MIT)