Jane books links: www.jianshu.com/p/7503a7ad0…

Instead of incremental updates, hot updates of Rn, the process is to download a decompression package from the server to the local directory of the application


This is a packaged APK file. In Rn, all our JS codes are packaged and stored in assets directory, where index.android.bundle, so you can understand our packaged CODE file after js writing


Where the snippet of the file Rn loads the bundle is initialized for us in the 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); String jsBundleFile = getJSBundleFile(); if (jsBundleFile ! = null) { builder.setJSBundleFile(jsBundleFile); } else {/ / loading assets directory file builder. SetBundleAssetName (Assertions. AssertNotNull (getBundleAssetName ())); } return builder.build(); } public Builder setBundleAssetName(String bundleAssetName) { mJSBundleAssetUrl = (bundleAssetName == null ? null : "assets://" + bundleAssetName); mJSBundleLoader = null; return this; }Copy the code

starts

First of all, for the application of our old packaging reactnative. Cn/docs / 0.42 / s… Chinese package tutorial)

Pay attention to the point

  • Keystore is stored in the Android /app directory

Install the apk

Then modify the code to generate our new Jsbundle and image resource files (updates must include images even if the old version of the resource is already available).

react-native bundle --platform android --dev false --reset-cache --entry-file index.android.js --bundle-output E:\test\index.android.bundle   --assets-dest E:\testCopy the code

The generated file generates a compressed package

Pay attention to the point

  • GetNextEntry () may not be available if the zipinputStream API is used to generate a RAR package and then change it to zip, so it is best to generate a ZIP package directly

Code section

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(), // Ignore this 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 in the sd card File File = new File (Environment. External.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); }Copy the code
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(); }}Copy the code

The above approach is to replace the loaded JSBundle in the Application, preferably in the same directory as the image resources and code

If the file is damaged, the original bundle of assets is loaded by default

Pay attention to the point

  • Raw Android code packaged as dex cannot be hot updated

Incremental update (not yet implemented)

  1. Index. android.bundle incremental update: Use Google’s Google-diff-match-patch to generate a patch comparing the old index.android.bundle file with the new index.android.bundle file Package, downloaded by the client and merged with the assets file, because google-diff-match-patch suitable for string text comparison, here use jbdiff this to update github.com/jdesbonnet/… , it should be noted that in Android, the operation of files in Assets can be realized simply by modifying files, but it has not been realized by InputStream in Assets
  2. An incremental update to a resource requires modifying the way the internal image is loaded

Incremental updates to resources require seeing how images are loaded

<Image source={require('./imgs/test.png')} /> render in //image.android.js: function() { const source = resolveAssetSource(this.props.source); const loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource); . } function resolveAssetSource(source: any):? ResolvedAssetSource { if (typeof source === 'object') { return source; } var asset = AssetRegistry.getAssetByID(source); if (! asset) { return null; } // The main object is AssetSourceResolver. Const resolver = new AssetSourceResolver(getDevServerURL(), getBundleSourcePath(), asset); If (_customSourceTransformer) {return _customSourceTransformer(resolver); } // 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; } 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; }Copy the code
If (this.isloadedFromServer ()) {return this.assetServerURL(); } if (platform. OS === 'android') {if (platform. OS === 'android') { And this method is a bundle and resource files in a directory return enclosing isLoadedFromFileSystem ()? this.drawableFolderInBundle() : this.resourceIdentifierWithoutScale(); } else { return this.scaledAssetPathInBundle(); } } drawableFolderInBundle(): ResolvedAssetSource { const path = this.bundlePath || ''; return this.fromSource( 'file://' + path + getAssetPathInDrawableFolder(this.asset) ); }Copy the code

If you want to achieve hot update resources, the idea is to modify the code load picture path problem

Refer to the article: blog.csdn.net/shandian000… Blog.csdn.net/u011050541/… www.cnblogs.com/liubei/p/RN…