一、原理

RN的热更新需要更换本地js文件,根据MainAppliction中new ReactNativeHost下的getJSBundleFile方法,它默认返回index.android.bundle.js的文件路径,我们需要做的就是去替换它。所以它的步骤就是: 判断是否热更新 -> 下载zip包(zip包减少带宽) -> 解压 -> 更新覆盖

   @Nullable@Overrideprotected String getJSBundleFile() {// 判断权限if (!new RuntimePermissions(context).check(Manifest.permission.WRITE_EXTERNAL_STORAGE))return super.getJSBundleFile();File file = new File (FilePath.BUNDLE_PATH);if(file != null && file.exists()) {return FilePath.BUNDLE_PATH;} else {return super.getJSBundleFile();}}

二、热更新条件

判断热更新的条件有两个:

  • 本地原生版本大于或等于网络请求的原生版本
  • 本地热更新版本小于网络请求的热更新版本

这两个条件同时成立则进行热更新下载,第一个条件是为了限制不让原生和热更新同时触发,事实上原生更新是包括热更新的。本地的原生版本可以通过AndroidManifest.xml的android:versionCode来判断。而本地的热更新版本是不能这样的,可以在bundle.zip中加入一个version.txt控制热更新版本,每次热更新后version.txt都加一,在android中读取这个文件来获取本地热更新版本,然后再去和网络请求的比对就能判断是否需要热更新了。

 三、下载bundle.zip

    public static void downloadFile(final Context mContext, String url) throws Exception {AsyncHttpClient client = new AsyncHttpClient(getSchemeRegistry());client.get(mContext, url, new AsyncHttpResponseHandler() {@Overridepublic void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {BufferedOutputStream bos = null;FileOutputStream fos = null;File file = null;try {file = new File(FilePath.ZIP_LOCAL_PATH);fos = new FileOutputStream(file);bos = new BufferedOutputStream(fos);bos.write(responseBody);} catch (IOException e) {e.printStackTrace();}File zipFile = new File(FilePath.ZIP_LOCAL_PATH);File file_unzip_path = new File(FilePath.LOCAL_PATH);if (!file_unzip_path.exists()) {file_unzip_path.mkdir();}try {UnZipFolder(zipFile, FilePath.LOCAL_PATH);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {Toast.makeText(mContext, "下载失败", Toast.LENGTH_LONG).show();}});
}

四、解压zip包

public static void UnZipFolder(File f, String outPathString) throws Exception {ZipInputStream inZip = new ZipInputStream(new FileInputStream(f));ZipEntry zipEntry;String  szName = "";while ((zipEntry = inZip.getNextEntry()) != null) {szName = zipEntry.getName();if (zipEntry.isDirectory()) {//获取部件的文件夹名szName = szName.substring(0, szName.length() - 1);File folder = new File(outPathString + File.separator + szName);folder.mkdirs();} else {Log.e(TAG,outPathString + File.separator + szName);File file = new File(outPathString + File.separator + szName);if (!file.exists()){Log.e(TAG, "Create the file:" + outPathString + File.separator + szName);file.getParentFile().mkdirs();file.createNewFile();}// 获取文件的输出流FileOutputStream out = new FileOutputStream(file);int len;byte[] buffer = new byte[1024];// 读取(字节)字节到缓冲区while ((len = inZip.read(buffer)) != -1) {// 从缓冲区(0)位置写入(字节)字节out.write(buffer, 0, len);out.flush();}out.close();}}inZip.close();
}

五、注意点

1、热更新需要两个权限,高版本需做权限申请适配

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2、当安装完app后,此时没有给app授权,但已检测到需要热更新,下载完后解压就需要android.permission.WRITE_EXTERNAL_STORAGE这个权限,没有的话会报异常,所以需要判断的是没有这个权限就不下载

// 判断是否有权限
if (permission.check(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {new UpdateChecker().check(this);
}

3、app已经热更新过,现在把它卸载掉,再重新装的时候,虽然不会触发热更新,但是此时手机上已经有热更新过的文件夹,这时app会直接去访问热更新的文件夹,又会因为没有授权报异常,所以需要做是否有权限的判断

   @Nullable@Overrideprotected String getJSBundleFile() {// 判断权限if (!new RuntimePermissions(context).check(Manifest.permission.WRITE_EXTERNAL_STORAGE))return super.getJSBundleFile();File file = new File (FilePath.BUNDLE_PATH);if(file != null && file.exists()) {return FilePath.BUNDLE_PATH;} else {return super.getJSBundleFile();}}

4、热更新的过程需要开子线程处理

5、增量更新,不需要每次都去下载一个完整的bundle.zip

6、每热更新完后,bundle.zip中的version.txt自动加一

RN-原生混合开发之热更新相关推荐

  1. uni-app结合原生混合开发

    uni-app混合开发 uni-app混合开发主要为扩展接入一些第三方的SDK或其他uni-app无法实现的功能,项目结构有两种: 主体采用uni-app,部分功能的实现使用原生开发. 主体采用原生, ...

  2. 推荐用于学习RN原生模块开发的开源库—react-native-ble-manager

    如题RN的原生模块/Native Modules的开发是一项很重要的技能,但RN官网的示例又比较简单,然后最近我接触与使用.还有阅读了react-native-ble-manager的部份源码,发现里 ...

  3. iOS开发-苹果热更新禁止-JSpatch禁止-热更新上线被拒绝

    今天一大早看各个iOS开发群炸锅了,原来是苹果大佬禁止了热更新和JSpatch.导致很多人的项目上线和更新被拒,目前还没有解决方案,也要等着业界大佬们尽快出方案,哈哈. 那么来说说JSpatch有什么 ...

  4. android调用flutter aar_Flutter原生混合开发

    混合开发简介 使用Flutter从零开始开发App是一件轻松惬意的事情,但对于一些成熟的产品来说,完全摒弃原有App的历史沉淀,全面转向Flutter是不现实的.因此使用Flutter去统一Andro ...

  5. flutter打包的app有多大_Flutter原生混合开发

    使用 Flutter 从头开始写一个 App是一件轻松惬意的事情.但是对于成熟产品来说,完全摒弃原有 App 的历史沉淀,全面转向 Flutter 并不现实.用 Flutter 去统一 iOS/And ...

  6. iOS开发-苹果热更新方案简介

    以下是iOS app热更新的几种方案. 一.动态库 可以做demo用,真实使用的时候会被苹果禁止. 因为 打包发到AppStore的ipa安装包 里的每个动态库 都有唯一的编码,iOS系统会进行验证, ...

  7. Parcel React 开发服务器热更新实战

    parcel Parcel 是 Web 应用打包工具,适用于经验不同的开发者.它利用多核处理提供了极快的速度,并且不需要任何配置. 内容 官网教程没有实现devSever和动态更新相结合具体部署步骤. ...

  8. Unity游戏开发-游戏热更新以及登录流程

    本篇主要分享基于热更新的游戏初始化方案. 整体初始化的流程大致为:检查是否需要解压资需要则解压,之后再检查是否存在需要热更新的资源文件需要则更新,更新完成后则初始化结束可进入登录界面. 关于登录这块的 ...

  9. 《江湖X》开发笔谈 - 热更新框架

    前言 大家好,我们这期继续借着我们工作室正在运营的在线游戏<江湖X>来谈一下热更新机制以及我们的理解和解决方案.这里先简单的介绍一下热更新的概念,熟悉这部分的朋友可以跳过,直接看我们的方案 ...

最新文章

  1. 扩展LLVM:添加指令、内部函数、类型等
  2. Mysql高级调优篇——前言简介
  3. 【社工】NodeJS 应用仓库钓鱼
  4. goto VS longjmp setjmp
  5. 疯狂捕鱼之路径解决方案的思考
  6. Android 四大组件之——Acitivity(一)
  7. conda重命名环境env
  8. python与正则表达式(part5)--re模块使用
  9. python 包和模块的区别_3分钟带你搞懂Python模块、包的区别和使用
  10. 苏宁大数据怎么运营_数据驱动经营 苏宁大数据用户标签入选2019TOP100全球软件案例...
  11. tomcat不停机部署_Tomcat中的零停机部署(和回滚); 演练和清单
  12. 前端:CSS/10/伪类选择器,CSS列表属性,CSS边框属性,CSS内边距属性,CSS背景属性
  13. 【深度优先搜索】计蒜客:正方形
  14. Seven Kinds of Testers - 七种类型的测试
  15. 在希望的田野上--生物柴油(Biodiesel)光明的未来
  16. 手写一个识别旺旺/千牛,手机在线/电脑在线状态的小工具
  17. ML/DL学习笔记2——偏差和方差模型好坏
  18. w ndows7怎么设置打印机,Windows7系统如何添加打印机
  19. JSON和全局异常处理
  20. Python删除字符串中的空格和特殊字符

热门文章

  1. pageHelper与PageInfo联合进行分页查询原理
  2. [原创] 在MFC中大家都习惯用CStdioFile来处理文本文件,可是为什么CStdioFile不叫CTextFile?
  3. C++ 多个指针指向同一个对象
  4. mysql报错1357_mysql8 参考手册--错误代码1343-1367
  5. 多智能体中的图论——图论中的定义(一)
  6. 利用OPC技术实现双网冗余系统的通讯驱动
  7. Jupyter lab add kernel Python+Julia+R 【jupyter Notebook 切换Python环境】and【在jupyter Notebook中安装第三方库】
  8. 下载配置安装MySql---超详细教程
  9. Docker容器回顾之运维篇
  10. 3 万字 + 100 张图带你彻底搞懂 TCP 面试题(强烈建议收藏)