React-Native 热更新以及增量更新
来源:互联网 发布:小米网络机顶盒哪个好 编辑:程序博客网 时间:2024/06/06 19:44
简书链接:http://www.jianshu.com/p/7503a7ad093f
不是增量更新,Rn的热更新,流程是下载服务器端上的一个解压包到本地 解压到应用的文件目录
这是一个打包后的apk文件,在Rn中我们的js代码都是打包后存放在assets目录中,其中index.android.bundle,可以理解我们js写后打包的代码文件
其中Rn加载bundle 的文件的代码片段在ReactNativeHost,在MainApplication中就为我们初始化好了
protected ReactInstanceManager createReactInstanceManager() { ReactInstanceManager.Builder builder = ReactInstanceManager.builder() .setApplication(mApplication) .setJSMainModuleName(getJSMainModuleName()) .setUseDeveloperSupport(getUseDeveloperSupport()) .setRedBoxHandler(getRedBoxHandler()) .setUIImplementationProvider(getUIImplementationProvider()) .setInitialLifecycleState(LifecycleState.BEFORE_CREATE); for (ReactPackage reactPackage : getPackages()) { builder.addPackage(reactPackage); } //这是可以重写的方法,为我们提供重写获取bundleFile的方法 String jsBundleFile = getJSBundleFile(); if (jsBundleFile != null) { builder.setJSBundleFile(jsBundleFile); } else { //加载assets目录下的文件 builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName())); } return builder.build(); } public Builder setBundleAssetName(String bundleAssetName) { mJSBundleAssetUrl = (bundleAssetName == null ? null : "assets://" + bundleAssetName); mJSBundleLoader = null; return this; }
开工
首先为我们旧的应用打包
http://reactnative.cn/docs/0.42/signed-apk-android.html#content(react-native 中文网打包教程)
注意点
- keystore放在android/app的目录下
安装apk
之后修改代码 生成我们新的jsbundle 和图片资源文件(更新必须是要附带图片的即使旧版本的资源已经有了,也要重新下载)
react-native bundle --platform android --dev false --reset-cache --entry-file index.android.js --bundle-output E:\test\index.android.bundle --assets-dest E:\test
生成后的 文件 对其进行生成压缩包
注意点
- 因为使用的zipinputStream 这个api 如果是生成rar解压包后改成zip 可能获取不到getNextEntry() 所以最好是直接生成zip格式的解压包
代码部分
private String bundleParentPath = null; private String bundlePath = null; private String bundleName = "index.android.bundle"; private File bundleFile = null;private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), //无视这个 new GankViewManager() ); } @Override protected String getJSMainModuleName() { return super.getJSMainModuleName(); } @Nullable @Override protected String getBundleAssetName() { String bundleName = "index.android.bundle"; if (bundleFile != null && bundleFile.exists()) { Log.d(TAG, "assets bundle exit"); return null; } // Logger.d("assets bundle does not exit"); return bundleName; } @Nullable @Override protected String getJSBundleFile() { if (bundleFile != null && bundleFile.exists()) { Log.d(TAG, "js bundle file " + bundleFile.getPath()); return bundleFile.getPath(); } return null; } }; @Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); //adb push到sd卡中 File file = new File(Environment.getExternalStorageDirectory().getAbsoluteFile() + "/test.zip"); if (file.exists()) { try { ZipUtils.unzip(Environment.getExternalStorageDirectory().getAbsoluteFile() + "/test.zip", Environment.getExternalStorageDirectory().getAbsoluteFile() + "/bundle"); } catch (Exception e) { e.printStackTrace(); } } bundleParentPath = Environment.getExternalStorageDirectory().getAbsoluteFile() + "/bundle"; bundlePath = bundleParentPath + File.separator + bundleName; bundleFile = new File(bundlePath); }
public class ZipUtils { private final static int BUFFER_SIZE = 1 << 12; public static void unzip(String zipFilePath, String destDirectory) throws Exception { File destDir = new File(destDirectory); if (destDir.exists()) { destDir.delete(); } destDir.mkdir(); ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath)); ZipEntry zipEntry = zipInputStream.getNextEntry(); while (zipEntry != null) { String filePath = destDirectory + File.separator + zipEntry.getName(); if (!zipEntry.isDirectory()) { extractFiles(zipInputStream, filePath); } else { File dir = new File(filePath); dir.mkdir(); } zipInputStream.closeEntry(); zipEntry = zipInputStream.getNextEntry(); } zipInputStream.close(); } private static void extractFiles(ZipInputStream inputStream, String path) throws IOException { BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(path)); byte[] bytes = new byte[BUFFER_SIZE]; int read = 0; while ((read = inputStream.read(bytes)) != -1) { outputStream.write(bytes, 0, read); } outputStream.close(); }}
上面的方式是在Application中替换掉加载的JSBundle ,图片资源和代码最好在一个目录下
如果文件被情况,默认加载assets下的原始的bundle
注意点
- 原始的Android 代码打包成dex是没法做热更新的
增量更新(暂未实现)
- index.android.bundle文件增量更新:使用Google的google-diff-match-patch对比老版本的index.android.bundle文件和新版本的index.android.bundle文件生成一个补丁包,客户端下载后与assets中的文件合并,由于google-diff-match-patch 适合字符串文本的对比,在这里 使用的jbdiff这个来进行更新 https://github.com/jdesbonnet/jbdiff/tree/master/src/ie/wombat/jbdiff,需要注意的是 在Android中assets中的文件操作,如果单纯是文件的修改可以实现, 在assets中通过InputStream的方式还未实现
- 资源的增量更新,需要修改内部的image加载的方式
资源的增量更新 需要看到图片的加载方法
//这样加载一张图片 内部的代码<Image source={require('./imgs/test.png')} />在//image.android.js 中render: function() { const source = resolveAssetSource(this.props.source); const loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource); .... }//继续查看 resolveAssetSource function resolveAssetSource(source: any): ?ResolvedAssetSource { if (typeof source === 'object') { return source; } var asset = AssetRegistry.getAssetByID(source); if (!asset) { return null; } //主要是AssetSourceResolver 这个对象传递了,这里看出非网络图片的时候,加载图片的方式和bundle的路径有关 const resolver = new AssetSourceResolver(getDevServerURL(), getBundleSourcePath(), asset); //这里应该是图片变换才会走的 if (_customSourceTransformer) { return _customSourceTransformer(resolver); } //最后来到defaultAsset这个方法 return resolver.defaultAsset();} //是否是网络图片function getDevServerURL(): ?string { if (_serverURL === undefined) { var scriptURL = SourceCode.scriptURL; var match = scriptURL && scriptURL.match(/^https?:\/\/.*?\//); if (match) { // Bundle was loaded from network _serverURL = match[0]; } else { // Bundle was loaded from file _serverURL = null; } } return _serverURL;}//加载bunle的路径function getBundleSourcePath(): ?string { if (_bundleSourcePath === undefined) { const scriptURL = SourceCode.scriptURL; if (!scriptURL) { // scriptURL is falsy, we have nothing to go on here _bundleSourcePath = null; return _bundleSourcePath; } if (scriptURL.startsWith('assets://')) { // running from within assets, no offline path to use _bundleSourcePath = null; return _bundleSourcePath; } if (scriptURL.startsWith('file://')) { // cut off the protocol _bundleSourcePath = scriptURL.substring(7, scriptURL.lastIndexOf('/') + 1); } else { _bundleSourcePath = scriptURL.substring(0, scriptURL.lastIndexOf('/') + 1); } } return _bundleSourcePath;}
defaultAsset(): ResolvedAssetSource { //这里开始加载网络图片 if (this.isLoadedFromServer()) { return this.assetServerURL(); } if (Platform.OS === 'android') { //加载本地图片,如果是离线文件 加载drawableFolderInBundle这个方法,而这个方法是bundle和资源文件在一个目录下 return this.isLoadedFromFileSystem() ? this.drawableFolderInBundle() : this.resourceIdentifierWithoutScale(); } else { return this.scaledAssetPathInBundle(); } } drawableFolderInBundle(): ResolvedAssetSource { const path = this.bundlePath || ''; return this.fromSource( 'file://' + path + getAssetPathInDrawableFolder(this.asset) ); }
如果要实现资源的热更新,思路是修改代码加载图片的路径问题
参考文章:http://blog.csdn.net/shandian000/article/details/54582603
http://blog.csdn.net/u011050541/article/details/52703209
http://www.cnblogs.com/liubei/p/RNUpdate.html
- React-Native 热更新以及增量更新
- React Native Android 即时热更新bundle 以及增量更新bundle~
- React Native 实现热部署、差异化增量热更新
- React Native 实现热部署、差异化增量热更新
- React Native 实现热部署、差异化增量热更新
- React Native 实现热部署、差异化增量热更新
- react native热更新
- React Native热更新
- react native增量热更新生成合并补丁文件
- react-native 热更新(android)
- React Native 热更新实现
- React Native-Pushy热更新
- React Native热更新方案
- React-Native 热更新 CodePush
- React Native 详细实现热部署、增量差异化热更新
- React Native 详细实现热部署、增量差异化热更新
- Android React Native 热更新 自己搭建热更新平台
- React-Native热更新部署/热更新CodePush集成详解
- git 使用总结
- MySQL使用记录
- 中、前、后缀表达式
- Java中break跳出循环的层数
- 信号的VIEW
- React-Native 热更新以及增量更新
- 微信架构(转)
- 从工业角度谈推荐系统的过去、现在和未来(二)
- html 5 createPattern()函数,必须在服务器环境中才生效?
- ZJOI 2017
- 将数组A中的内容和数组B中的内容进行交换(数组一样大)
- 图解Android
- 第六届蓝桥杯【国赛试题1】积分之迷
- 网易笔试题:合唱团