热更新解决方案
采用 微软react-native-code-push + 自建code-push-server服务 进行RN热更新管理
1、本地安装code-push-server与code-push-cli
npm install code-push-server -g
npm install code-push-cli -g
2、初始化mysql数据库(先自行安装mysql,建议版本5.6)
- 先启动MySQL服务
- code-push-server-db init --dbhost localhost --dbname codepush --dbuser root --dbpassword xxxxxx
- 如果MySql版本为8.0,先执行 alter user 'root'@'localhost' identified with mysql_native_password by 'xxxxxx';
3、启动code-push-server服务
- 先配置config.js (C:\Users\Administrator\AppData\Local\Yarn\Data\global\node_modules\code-push-server\config\config.js)
-
var os = require('os'); var config = {}; config.development = { // Config for database, only support mysql. db: { username: process.env.RDS_USERNAME || "root", password: process.env.RDS_PASSWORD || "xxxxx", database: process.env.DATA_BASE || "codepush", host: process.env.RDS_HOST || "127.0.0.1", port: process.env.RDS_PORT || 3306, dialect: "mysql", logging: false, operatorsAliases: false, }, // Config for qiniu (http://www.qiniu.com/) cloud storage when storageType value is "qiniu". qiniu: { accessKey: "", secretKey: "", bucketName: "", downloadUrl: "" // Binary files download host address. }, // Config for Amazon s3 (https://aws.amazon.com/cn/s3/) storage when storageType value is "s3". s3: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, sessionToken: process.env.AWS_SESSION_TOKEN, //(optional) bucketName: process.env.BUCKET_NAME, region: process.env.REGION, downloadUrl: process.env.DOWNLOAD_URL, // binary files download host address. }, // Config for Aliyun OSS (https://www.aliyun.com/product/oss) when storageType value is "oss". oss: { accessKeyId: "", secretAccessKey: "", endpoint: "", bucketName: "", prefix: "", // Key prefix in object key downloadUrl: "", // binary files download host address. }, // Config for tencentyun COS (https://cloud.tencent.com/product/cos) when storageType value is "oss". tencentcloud: { accessKeyId: "", secretAccessKey: "", bucketName: "", region: "", downloadUrl: "", // binary files download host address. }, // Config for local storage when storageType value is "local". local: { // Binary files storage dir, Do not use tmpdir and it's public download dir. // 需要配置bundle包本地存储位置 storageDir: process.env.STORAGE_DIR || "/Users/captain/workspaces/storage", // Binary files download host address which Code Push Server listen to. the files storage in storageDir. // 配置服务器下载地址 downloadUrl: process.env.LOCAL_DOWNLOAD_URL || "http://10.180.51.237:3000/download", // public static download spacename. public: '/download' }, jwt: { // Recommended: 63 random alpha-numeric characters // Generate using: https://www.grc.com/passwords.htm tokenSecret: process.env.TOKEN_SECRET ||'CeSCpLaHcbOujnQPTQp0FFDYL9YNxjsxBptL58kGShe4Y3Mds1PQPu84UbktZyg' }, common: { /* * tryLoginTimes is control login error times to avoid force attack. * if value is 0, no limit for login auth, it may not safe for account. when it's a number, it means you can * try that times today. but it need config redis server. */ tryLoginTimes: 0, // CodePush Web(https://github.com/lisong/code-push-web) login address. //codePushWebUrl: "http://127.0.0.1:3001/login", // create patch updates's number. default value is 3 diffNums: 3, // data dir for caclulate diff files. it's optimization. dataDir: process.env.DATA_DIR || os.tmpdir(), // storageType which is your binary package files store. options value is ("local" | "qiniu" | "s3"| "oss" || "tencentcloud") storageType: process.env.STORAGE_TYPE || "local", // options value is (true | false), when it's true, it will cache updateCheck results in redis. updateCheckCache: false, // options value is (true | false), when it's true, it will cache rollout results in redis rolloutClientUniqueIdCache: false, }, // Config for smtp email,register module need validate user email project source https://github.com/nodemailer/nodemailer smtpConfig:{ host: "smtp.aliyun.com", port: 465, secure: true, auth: { user: "", pass: "" } }, // Config for redis (register module, tryLoginTimes module) redis: { default: { host: "127.0.0.1", port: 6379, retry_strategy: function (options) { if (options.error.code === 'ECONNREFUSED') { // End reconnecting on a specific error and flush all commands with a individual error return new Error('The server refused the connection'); } if (options.total_retry_time > 1000 * 60 * 60) { // End reconnecting after a specific timeout and flush all commands with a individual error return new Error('Retry time exhausted'); } if (options.times_connected > 10) { // End reconnecting with built in error return undefined; } // reconnect after return Math.max(options.attempt * 100, 3000); } } } } config.development.log4js = { appenders: {console: { type: 'console'}}, categories : { "default": { appenders: ['console'], level:'error'}, "startup": { appenders: ['console'], level:'info'}, "http": { appenders: ['console'], level:'info'} } } config.production = Object.assign({}, config.development); module.exports = config;
- 配置好config.js文件后,终端输入code-push-server启动服务,在浏览器中打开 http://127.0.0.1:3000,登录(用户名: admin 密码: 123456) ,然后获取token
- 终端输入 code-push login http://127.0.0.1:3000,填入刚刚获取到的token
- 至此code-push-server配置已经完成
4、向服务器中添加app
code-push app add test-ios ios react-native
code-push app add test-android android react-native
5、项目中配置
- 集成react-native-code-push到项目中
- npm install --save react-native-code-push@latest
IOS配置
1、AppDelegate.m配置
#import <CodePush/CodePush.h>
...
NSURL *jsCodeLocation;
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
jsCodeLocation = [CodePush bundleURL];
// 如果bundle包名不是默认的main.bundle,需要以下配置
jsCodeLocation = [CodePush bundleURLForResource:@"bundle/index.ios" withExtension:@"jsbundle"];
#endif
...
CodePushDeploymentKey
值设置为test-ios的Production DeploymentKey值。CodePushServerURL
值设置为code-push-server服务地址 http://YOUR_CODE_PUSH_SERVER_IP:3000/ 不在同一台机器的时候,请将YOUR_CODE_PUSH_SERVER_IP改成外网ip或者域名地址。- 将默认版本号1.0改成三位1.0.0
安卓配置
1、In your android/settings.gradle
file, make the following additions at the end of the file:
...
include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
2、In your android/app/build.gradle
file, add the codepush.gradle
file as an additional build task definition underneath react.gradle
...
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
...
3、Update the MainApplication.java
file to use CodePush via the following changes:
...
// 1. Import the plugin class.
import com.microsoft.codepush.react.CodePush;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
...
@Override
protected List<ReactPackage> getPackages() {
...
CodePush.getJSBundleFile();
new CodePush(getResources().getString(com.test.ts.R.string.CodePushDeploymentKey),MainApplication.this,BuildConfig.DEBUG,"http://127.0.0.1:3000");
return packages;
}
};
}
4、Add the Deployment key to android\app\src\main\res\values\strings.xml
:
<resources>
<string name="app_name">AppName</string>
<string moduleConfig="true" name="CodePushDeploymentKey">DeploymentKey</string>
</resources>
React-native
import CodePush from "react-native-code-push";
class App extends Component {
...
componentDidMount() {
CodePush.allowRestart();
CodePush.sync(
{ installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: {
appendReleaseDescription:true,//是否显示更新description,默认为false
descriptionPrefix:"更新内容:",//更新说明的前缀。 默认是” Description:
mandatoryContinueButtonLabel:"立即更新",//强制更新的按钮文字,默认为continue
mandatoryUpdateMessage:"",//- 强制更新时,更新通知. Defaults to “An update is available that must be installed.”.
optionalIgnoreButtonLabel: '稍后',//非强制更新时,取消按钮文字,默认是ignore
optionalInstallButtonLabel: '后台更新',//非强制更新时,确认文字. Defaults to “Install”
optionalUpdateMessage: '有新版本了,是否更新?',//非强制更新时,更新通知. Defaults to “An update is available. Would you like to install it?”.
title: '更新提示'//要显示的更新通知的标题. Defaults to “Update available”.
}, },
);
}
...
App = CodePush(App);
export default App;
6、发布更新
1、生成资源并发布
- code-push release-react test-ios ios -d Production (--t <x.x.x针对哪个版本号更新> --m true 是否强更 --des <本次更新说明> --dev <是否测试包,默认false> --plistFile <指定plist路径>)
2、生成资源再发布
发布更新之前,需要先把 js打包成 bundle,如:
第一步: 在 工程目录里面新增 bundles文件
第二步: 运行命令打包 npx react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试
。
eg:npx react-native bundle --platform android --entry-file index.js --bundle-output ./android/bundles/index.android.bundle --dev false
打包bundle结束后,就可以通过CodePush发布更新了。在终端输入code-push release <应用名称> <Bundles所在目录> <对应的应用版本> --d: 更新环境 --description: 更新描述 --m: 是否强制更新
eg:code-push release GitHubPopular ./android/bundles/index.android.bundle 1.0.6 --d Production --des "支持缓存。" --m true
- 进入app检查更新
7、版本回滚
code-push rollback <appName> <deploymentName> -r <backVersion>
e.g: code-push rollback MyApp Production -r v1
8、版本清除
code-push deployment clear <appName> <deploymentName>
e.g: code-push deployment clear MyApp Production
9、code-push相关命令(code-push --help)
- app相关:code-push app --help
- 添加app:code-push app add <app名称> <platform> react-native
- 删除app:code-push app rm <app名称>
- 查看app列表:code-push app ls
- 版本相关:code-push deployment --help
- 查看当前版本状态:code-push deployment ls test-ios -k
- 查看版本更新历史:code-push deployment history test-ios Production
- 发布相关:code-push release-react --help
- code-push release-react test-ios ios -d Production (-t <x.x.x针对哪个版本号更新> -m true 是否强更 --des <本次更新说明> --dev <是否测试包,默认false> --plistFile <指定plist路径>)