您好,欢迎来到二三娱乐。
搜索
您的当前位置:首页ReactNative和Android混合开发热更新实现

ReactNative和Android混合开发热更新实现

来源:二三娱乐

React Native所有的js文件都打包在一个jsbundle文件中,发布时也是打包到app里面,一般是放到asset目录.猜想是不是可以从远程下载jsbundle文件覆盖asset的jsbundle. 查资料发现asset目录是只读的,该想法行不通.
发现调用了setJSBundleFile方法, 而且该方法是public的, 也就是可以通过这个方法指定jsbundle文件。可以设置了jsbundle文件, 那我们就可以把jsbundle文件放到sdcard, 经过测试发现, 确实可以读取sdcard jsbundle.
后面继续实现项目时发现, 动态更新后, 本地图片始终不显示, 远程图片可以.

yasuo.png

以下是全部代码:

//解压Zip
public class RefreshUpdateUtils {

   /**
    * 解压
    */
   public static void decompression() {

       try {

           ZipInputStream inZip = null;
           inZip = new ZipInputStream(new FileInputStream(FileConstant.zipPath));
           ZipEntry zipEntry;
           String szName;
               try {
                   while((zipEntry = inZip.getNextEntry()) != null) {

                       szName = zipEntry.getName();
                       if(zipEntry.isDirectory()) {
                           szName = szName.substring(0,szName.length()-1);
                           File folder = new File(FileConstant.JS_BUNDLE_REACT_UPDATE_PATH + File.separator + szName);
                           folder.mkdirs();
                       }else{
                           File file1 = new File(FileConstant.JS_BUNDLE_REACT_UPDATE_PATH + File.separator + szName);
                           boolean s = file1.createNewFile();
                           FileOutputStream fos = new FileOutputStream(file1);
                           int len;
                           byte[] buffer = new byte[1024];
                           while((len = inZip.read(buffer)) != -1) {
                               fos.write(buffer, 0 , len);
                               fos.flush();
                           }
                           fos.close();
                       }
                   }
               } catch (IOException e) {
                   e.printStackTrace();
               }
           inZip.close();
       } catch (FileNotFoundException e) {
           e.printStackTrace();
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}
//常量
public class FileConstant {
   public static final String zipPath=Environment.getExternalStorageDirectory().toString()+ File.separator +"yasuo.zip";
   public static final String path = Environment.getExternalStorageDirectory().toString()+ File.separator + "index.android.bundle";
   public static final String JS_BUNDLE_REACT_UPDATE_PATH = Environment.getExternalStorageDirectory().toString();
   public static final String JS_BUNDLE_REMOTE_URL = 
   public static final String JS_BUNDLE_LOCAL_FILE = "index.android.bundle";
}
public class UpdateReactActivity extends Activity implements DefaultHardwareBackBtnHandler {

   private static final String TAG = "UpdateReactActivity";

   private ReactInstanceManager mReactInstanceManager;
   private ReactRootView mReactRootView;
   private CompleteReceiver mDownloadCompleteReceiver;
   private long mDownloadId;
   private File zipfile;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       iniReactRootView(true);
//        initDownloadManager();
//        updateJSBundle(true);
   }

   // 如果bundle在sd卡【 比如bundle在file://sdcard/react_native_update/index.android.bundle 那么图片目录在file://sdcard/react_native_update/drawable-mdpi】
   // 如果你的bundle在assets里,图片资源要放到res文件夹里,例如res/drawable-mdpi
   private void iniReactRootView(boolean isRelease) {
       Log.i("ReactNativeJS",">>>react react start:"+System.currentTimeMillis());
       File file = new File(FileConstant.path);
       if (isRelease && file != null && file.exists()) {
           mReactInstanceManager = ReactInstanceManager.builder()
                   .setCurrentActivity(this)
                   .setApplication(getApplication())
                   .setJSMainModuleName(FileConstant.JS_BUNDLE_LOCAL_FILE)
                   .addPackage(new MainReactPackage())
                   .addPackage(new MyReactPackage())
                   .setInitialLifecycleState(LifecycleState.RESUMED)
                    .setJSBundleFile(FileConstant.path)
                   .build();
           Log.i(TAG, "load bundle from local cache");
       }
       else {
           mReactInstanceManager = ReactInstanceManager.builder()
                   .setCurrentActivity(this)
                   .setApplication(getApplication())
                   .setJSMainModuleName(FileConstant.JS_BUNDLE_LOCAL_FILE)
                   .addPackage(new MainReactPackage())
                   .addPackage(new MyReactPackage())
                   .setInitialLifecycleState(LifecycleState.RESUMED)
                   .setBundleAssetName(FileConstant.JS_BUNDLE_LOCAL_FILE)
                   .build();
           Log.i(TAG, "load bundle from asset");
       }

       mReactRootView = new ReactRootView(this);
       mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
       setContentView(mReactRootView);
       Log.i("ReactNativeJS", ">>>react react end:"+System.currentTimeMillis());
   }

   private void updateJSBundle() {

       zipfile = new File(FileConstant.path);
       if (zipfile != null && zipfile.exists()) {
           Log.i(TAG, "new bundle exists !");
           zipfile.delete();
           Log.i(TAG, "js bundle file delete success");
       }

       DownloadManager.Request request = new DownloadManager.Request(Uri.parse(FileConstant.JS_BUNDLE_REMOTE_URL));
       
       //下面的代码片段是在外部存储中指定一个任意的保存位置的方法:
       request.setDestinationUri(Uri.parse("file://" + FileConstant.path));
       //获取DownloadManager
       DownloadManager dm = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
       //将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
       mDownloadId = dm.enqueue(request);

       Log.i(TAG, "start download remote js bundle file");
   }

   private void initDownloadManager() {
       mDownloadCompleteReceiver = new CompleteReceiver();
       registerReceiver(mDownloadCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
   }

   private class CompleteReceiver extends BroadcastReceiver {

       @Override
       public void onReceive(Context context, Intent intent) {
           long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
           if (completeDownloadId == mDownloadId) {
               // 1.解压
               RefreshUpdateUtils.decompression();
               zipfile.delete();
               //通过监听下载成功事件, 然后调用onJSBundleLoadedFromServer接口就可以看到立即更新的效果.
               onJSBundleLoadedFromServer();
           }
       }
   }

   //通过监听下载成功事件, 然后调用onJSBundleLoadedFromServer接口就可以看到立即更新的效果.
   private void onJSBundleLoadedFromServer() {
       final File file = new File(FileConstant.path);
       if (file == null || !file.exists()) {
           Log.i(TAG, "js bundle file download error, check URL or network state");
           return;
       }

       Log.i(TAG, "js bundle file file success, reload js bundle");

       Toast.makeText(UpdateReactActivity.this, "download bundle complete", Toast.LENGTH_SHORT).show();

       //为了在运行中重新加载bundle文件,查看ReactInstanceManager的源码,找到如下方法:
       mReactInstanceManager.recreateReactContextInBackground();
   }


   @Override
   public void invokeDefaultOnBackPressed() {
       super.onBackPressed();
   }
   @Override
   public void onBackPressed() {
       if (mReactInstanceManager != null) {
           mReactInstanceManager.onBackPressed();
       } else {
           super.onBackPressed();
       }
   }
   @Override
   public boolean onKeyUp(int keyCode, KeyEvent event) {
       if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
           mReactInstanceManager.showDevOptionsDialog();
           return true;
       }
       return super.onKeyUp(keyCode, event);
   }
   @Override
   protected void onPause() {
       super.onPause();

       if (mReactInstanceManager != null) {
           mReactInstanceManager.onHostPause(this);
       }
   }

   @Override
   protected void onResume() {
       super.onResume();

       if (mReactInstanceManager != null) {
           mReactInstanceManager.onHostResume(this, this);
       }
   }

   @Override
   protected void onDestroy() {
       super.onDestroy();

       if (mReactInstanceManager != null) {
           mReactInstanceManager.onHostDestroy();
       }
   }
}

Copyright © 2019- yule263.com 版权所有 湘ICP备2023023988号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务