浅谈React原生APP更新

App更新流程

1.在 App 打开时请求接口或文件, 获取远程版本/版本更新说明/地址等等重用信息

2.通过库或者原生方案, 获取 App 的当前版本

3.比较远程版本和当前版本的区别(可以使用库,也可以自己写一个比较方案)

4.通过获取到的链接进行操作(可以跳转到对应网站下载,类似蒲公英这种,可以是 apk 链接, 通过安卓原生方法下载, 也可以是 App Store 链接)

大致的流程图

详细说明:

1.这些远程信息,可以是接口, 这样可以有一个中台来控制, 当然也可以是一个文件, 让运维来控制
关于信息,不止于远程版本, 在项目里还可以添加其他属性,如: versionCode, versionCodeSwitch , notUpdate , deleteApp

  • 1.1 versionCode 通过 code 来升级版本,一般是一个数字(在 ios 里提交 App Store 的时候有需要用到的地方), 这样 versionName 并不会增加, 但是如果添加了 versionCode, 如果要升级 versionName, versionCode 也需要增加
  • 1.2 versionCodeSwitch 用来控制是否要根据versionCode来更新, 一般我都是在测试和其他环境开启,生产环境关闭的
  • 1.3 notUpdate 是否要根据远程信息来更新, 一般都是开启状态
  • 1.4 deleteApp 安卓 app 需要卸载重新安装, 因为直接安装可能存在某些问题, 将会使用此信息,先删除 APP, 再重新下载

2.获取当前手机的信息,方案较多, 我使用的是 react-native-device-info 这个库, 这个库里面提供的信息较全, 当然也可以使用原生方法, 来获取APP的信息

3.关于本地版本号和原生版本号之间的对比也是可以使用库,也可以自己写, 这边推荐两个库,下载量都是百万以上的: semver-compare 和 compare-versions, 这边附上我的 versionName 比较方案, 较为简陋:

/**
 * 比较两版本号
 * @param currentVersion
 * @return boolean
 * true=需要更新 false=不需要
 */
compareVersion = (currentVersion: string): boolean => {
    const {versionName: remoteVersion} = this.remoteInfo || {}
    if (!remoteVersion) {
        return false
    }
    if (currentVersion === remoteVersion) {
        return false
    }
    const currentVersionArr = currentVersion.split('.')
    const remoteVersionArr = remoteVersion.split('.')
    for (let i = 0; i < 3; i++) {
        if (Number(currentVersionArr[i]) < Number(remoteVersionArr[i])) {
            return true
        }
    }
    return false
}

关于下载 app 有很多方案, 最简单的就是跳转链接到第三方平台, 像蒲公英这样的, 使用 RN 提供的 Linking 方法来直接跳转
当然安卓是可以直接通过自己提供的地址下载的, 这里提供一个方法(此方法来源于网络):

@ReactMethod
public void installApk(String filePath, String fileProviderAuthority) {
    File file = new File(filePath);
    if (!file.exists()) {
        Log.e("RNUpdater", "installApk: file doe snot exist '" + filePath + "'");
        // FIXME this should take a promise and fail it
 return;
    }
    if (Build.VERSION.SDK_INT >= 24) {
        // API24 and up has a package installer that can handle FileProvider content:// URIs
 Uri contentUri;
        try {
            contentUri = FileProvider.getUriForFile(getReactApplicationContext(), fileProviderAuthority, file);
        } catch (Exception e) {
            // FIXME should be a Promise.reject really
 Log.e("RNUpdater", "installApk exception with authority name '" + fileProviderAuthority + "'", e);
            throw e;
        }
        Intent installApp = new Intent(Intent.ACTION_INSTALL_PACKAGE);
        installApp.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        installApp.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        installApp.setData(contentUri);
        installApp.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, reactContext.getApplicationInfo().packageName);
        reactContext.startActivity(installApp);
    } else {
        // Old APIs do not handle content:// URIs, so use an old file:// style
 String cmd = "chmod 777 " + file;
        try {
            Runtime.getRuntime().exec(cmd);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + file), "application/vnd.android.package-archive");
        reactContext.startActivity(intent);
    }
}

如果是我们自己提供下载服务,需要注意的是带宽, 如果网速过慢则用户体验过差, 还有就会带来更多的流量消耗, 其中的取舍,需要开发者决定

更新APP信息

在打包时, 通过脚本更新接口或者文件信息, 当然这个得看具体的打包方案
比如我现在的方案是使用 Jenkins 打包, 在打包时使用 shell 脚本更新对应信息(有需要也可以使用其他语言脚本):

1.首先定义需要获取的文件地址

androidVersionFilePath="$WORKSPACE/android/app/build.gradle"  // 通过此文件获取安卓的版本信息
iosVersionFilePath="$WORKSPACE/ios/veronica/Info.plist" // 通过此文件获取iOS的版本信息
changeLogPath="$WORKSPACE/change.log" // 将版本更新信息存储在此文件中

2.通过文件地址, 获取打完包后的版本信息

getAndroidVersion(){
  androidVersion=$(cat $androidVersionFilePath  | grep "versionName" | awk '{print $2}' | sed 's/\"//g')
  androidCode=$(cat $androidVersionFilePath  | grep "versionCode " | awk '{print $2}' | sed 's/\"//g')
  androidDelete=$(cat $androidVersionFilePath  | grep "deleteApp" | awk '{print $4}' | sed 's/\"//g')
  return 0
}

getIOSVersion(){
  rows=$(awk '/CFBundleShortVersionString/ {getline; print}' $iosVersionFilePath)
  iosVersion=$(echo "$rows" | sed -ne 's/<string>\(.*\)<\/string>/\1/p')
  iosVersion=$(echo "$iosVersion" | sed 's/^[[:space:]]*//')

  rows2=$(awk '/VersionCode/ {getline; print}' $iosVersionFilePath)
  iosCode=$(echo "$rows2" | sed -ne 's/<string>\(.*\)<\/string>/\1/p')
  iosCode=$(echo "$iosCode" | sed 's/^[[:space:]]*//')
  return 0
}

desc=$(cat $changeLogPath | tr "\n" "#")

3.替换现有文件中的信息

sed -i '' "s/\"releaseInfo\":.*$/\"releaseInfo\": \"$desc\"/"  $JsonPath/$fileName
sed -i '' "s/\"versionName\":.*$/\"versionName\": \"$versionName\",/"  $JsonPath/$fileName
sed -i '' "s/\"versionCode\":.*$/\"versionCode\": \"$versionCode\",/"  $JsonPath/$fileName
sed -i '' "s/\"deleteApp\":.*$/\"deleteApp\": \"$deleteApp\",/"  $JsonPath/$fileName

我的文件是以 json 作为格式的,说明文字是可以任意填写的,会触发一些解析问题:

  • 不允许出现会造成 JSON.parse 解析失败的符号, 如 \ , ````, \n ,\r, \" 等等
  • 因为说明文字的换行我是通过 # 切割的, 所以也不允许出现这个符号

大致流程图

总结

关于 APP 原生版本的更新流程基本就是这样,当然这个流程不光适用 APP, 也可以用于 PC 软件的更新
除了原生版本的更新,还有热更新, 也是非常重要的,

以上就是浅谈React原生APP更新的详细内容,更多关于React原生APP更新的资料请关注我们其它相关文章!

(0)

相关推荐

  • iOS端React Native差异化增量更新的实现方法

    前言 作为一名iOS原生开发工程师,通过一个礼拜的面试之后发现,原来并不想学的react-native真的是火的一塌糊涂,坐标:杭州,很多公司招聘iOS开发除了原来的OC和Swift,多了一门新语言:react-native,真的是要人老命啊,Swift4.0刚刚看完,又得花时间学RN.入职之后也开始学react-native,算是小白一枚,下面是我的个人总结,有大神看出错误,请不要打我或者骂我,联系我邮箱dadadoubi@qq.com. RN具有的优势有很多,跨平台开发,一套代码Androi

  • 浅谈react-native热更新react-native-pushy集成遇到的问题

    主要步骤按官方文档实现,这里只记录遇到的一些小坑 官方文档 run-android时NDK报错 前提是NDK已安装并且环境变量已设置 根据报错提示在 android/local.properties 文件里加入 ndk.dir=~/Library/Android/android-ndk-r10e //这里改成你自己的ndk路径 以上这篇浅谈react-native热更新react-native-pushy集成遇到的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 原理深度解析Vue的响应式更新比React快

    前言 我们都知道 Vue 对于响应式属性的更新,只会精确更新依赖收集的当前组件,而不会递归的去更新子组件,这也是它性能强大的原因之一. 例子 举例来说 这样的一个组件: <template> <div> {{ msg }} <ChildComponent /> </div> </template> 我们在触发 this.msg = 'Hello, Changed~'的时候,会触发组件的更新,视图的重新渲染. 但是 <ChildCompone

  • React Native 实现热更新并自动签名打包功能

    项目背景:手动link的安卓App 1.下载 react-native-code-push npm install --save react-native-code-push 2.在android/settings.gradle文件下新增: include ':app', ':react-native-code-push' project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../no

  • React 组件渲染和更新的实现代码示例

    最近一直写React,慢慢就对里面的一些实现很好奇.最好奇的就是自定义标签的实现和this.setState的实现.这里不分析JSX是如何解析的,所有组件都用ES5方式编写. 组件渲染 渲染时候,我们会调用render方法.类似下面这样: var SayHi = React.createClass({ getInitialState: function() { return {verb: 'say:'}; }, componentWillMount: function() { console.l

  • 详解React setState数据更新机制

    为什么使用setState 在React 的开发过程中,难免会与组件的state打交道.使用过React 的都知道,想要修改state中的值,必须使用内部提供的setState 方法.为什么不能直接使用赋值的方式修改state的值呢?我们就分析一下,先看一个demo. class Index extends React.Component { this.state = { count: 0 } onClick = () => { this.setState({ count: 10 }) } re

  • 详解React中传入组件的props改变时更新组件的几种实现方法

    我们使用react的时候常常需要在一个组件传入的props更新时重新渲染该组件,常用的方法是在componentWillReceiveProps中将新的props更新到组件的state中(这种state被成为派生状态(Derived State)),从而实现重新渲染.React 16.3中还引入了一个新的钩子函数getDerivedStateFromProps来专门实现这一需求.但无论是用componentWillReceiveProps还是getDerivedStateFromProps都不是

  • 浅谈React原生APP更新

    App更新流程 1.在 App 打开时请求接口或文件, 获取远程版本/版本更新说明/地址等等重用信息 2.通过库或者原生方案, 获取 App 的当前版本 3.比较远程版本和当前版本的区别(可以使用库,也可以自己写一个比较方案) 4.通过获取到的链接进行操作(可以跳转到对应网站下载,类似蒲公英这种,可以是 apk 链接, 通过安卓原生方法下载, 也可以是 App Store 链接) 大致的流程图 详细说明: 1.这些远程信息,可以是接口, 这样可以有一个中台来控制, 当然也可以是一个文件, 让运维

  • 浅谈React Router关于history的那些事

    如果你想理解React Router,那么应该先理解history.更确切地说,是history这个为React Router提供核心功能的包.它能轻松地在客户端为项目添加基于location的导航,这种对于单页应用至关重要的功能. npm install --save history 存在三类history,分别时browser,hash,与 memory.history包提供每种history的创建方法. import { createBrowserHistory, createHashHi

  • 浅谈react+es6+webpack的基础配置

    这是模块化开发.主流框架和最新版的ECMAScript语法规范的一个小demo 准备工作 安装 nodeJs 首先进入node官网,去下载最新版的nodeJs webpack 安装webpack npm install webpack -g 参数-g表示全局安装webpack,你在cmd命令中哪个文件夹下都可以使用webpack的命令,如果不加-g的话,是只可以在你安装webpack的目录下使用webpack这个命令 webpack 也有一个 web 服务器 npm install webpac

  • 浅谈React中组件逻辑复用的那些事儿

    基本每个开发者都需要考虑逻辑复用的问题,否则你的项目中将充斥着大量的重复代码.那么 React 是怎么复用组件逻辑的呢?本文将一一介绍 React 复用组件逻辑的几种方法,希望你读完之后能够有所收获.如果你对这些内容已经非常清楚,那么略过本文即可. 我已尽量对文中的代码和内容进行了校验,但是因为自身知识水平限制,难免有错误,欢迎在评论区指正. 1. Mixins Mixins 事实上是 React.createClass 的产物了.当然,如果你曾经在低版本的 react 中使用过 Mixins,

  • 浅谈react 16.8版本新特性以及对react开发的影响

    目录 react16.8版本更新 useEffect react16.8版本更新解决了什么问题 组件复用更便捷 hooks和reactdiff算法 总结 Facebook团队对社区上的MVC框架都不太满意的情况下,开发了一套开源的前端框架react,于2013年发布第一个版本. react最开始倡导函数式编程,使用function以及内部方法React.creactClass创建组件,之后在ES6推出之后,使用类组件Class构建包含生命周期的组件. react 16.8版本更新 react16

  • 浅谈React Refs 使用场景及核心要点

    目录 什么是 Refs? 使用方式 Refs 核心要点 避免重复创建 ref 内容 ref.current 存储的内容修改是突变 ref 作为数据存储时内容的变化不会引起 re-render ref 的读写只能在 useEffect 或者回调函数中进行 跨组件传递ref 获取dom时需要借助 forwardRef 包裹组件 ref 绑定的dom在离屏或者未挂载时ref.current 值会被修改为null 最佳实践 dom 操作相关 用于在两次 render 之间传递数据 在使用 React 进

  • 浅谈React底层实现原理

    目录 1. props,state与render函数关系,数据和页面如何实现互相联动? 2. React中的虚拟DOM 常规思路 改良思路(仍使用DOM) React的思路 深入理解虚拟DOM 3. 虚拟DOM的diff算法 4. React中ref的使用 5. React中的生命周期函数 6. 生命周期函数的使用场景 1. props,state与render函数关系,数据和页面如何实现互相联动? 当组件的state或者props发生改变的时候,自己的render函数就会重新执行.注意:当父组

  • 浅谈React 属性和状态的一些总结

    一.属性 1.第一种使用方法:键值对 <ClaaNameA name = "Tom" /> <ClaaNameA name = {Tom} /> <ClaaNameA name = {"Tom"} /> <ClaaNameA name = {[1,2,3]} />//数组 <ClaaNameA name = {FunctionNAme} /> //定义一个函数 2.第二种方法:三个点的展开对象形式 var

  • 浅谈React Native打包apk的坑

    RN的打包,大家可以根据官网一步一步来,但这里有几个地方注意,一下简单介绍: 生成一个签名密钥 在项目的目录下打开cmd命令窗口输入一下命令运行: keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000 这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息.最后它会生成一个叫做my-re

  • 浅谈react受控组件与非受控组件(小结)

    我们都知道,有许多的web组件可以被用户的交互发生改变,比如:<input>,<select>,或者是我现在正在使用的富文本编辑器.这些组件在日常的开发中很不显眼,我们可以很轻易的通过输入一些内容或者设置元素的value属性来改变组件的值.但是,因为React是单向数据流绑定的,这些组件可能会变得失控: 1.一个维护它自己state里的value值的<Input>组件无法从外部被修改: 2.一个通过props来设置value值的<Input>组件只能通过外部

随机推荐