采用 微软react-native-code-push + 自建code-push-server服务 进行RN热更新管理
npm install code-push-server -g
npm install code-push-cli -g
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;
code-push app add test-ios ios react-native
code-push app add test-android android react-native
1、AppDelegate.m配置
#import
...
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、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 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
:
AppName
DeploymentKey
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;
1、生成资源并发布
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 <应用名称>
eg:code-push release GitHubPopular ./android/bundles/index.android.bundle 1.0.6 --d Production --des "支持缓存。" --m true
code-push rollback
e.g: code-push rollback MyApp Production -r v1
code-push deployment clear
e.g: code-push deployment clear MyApp Production