ReactNative基於CodePush實現熱更新整合詳解
安裝工具介紹
根據最新的官方文件和實際整合經驗整理 http://www.jianshu.com/p/54cd13ed9e95
工具名稱 | 描述 | 備註 |
---|---|---|
Chocolatey | Windows上的包管理器(需翻牆) | 通常不安裝,使用 npm 即可 |
Python 2 | 注意目前不支援Python 3版本 | 不需安裝 |
NodeJs | Javascript執行環境(runtime) | 自帶 npm |
Yarn | Facebook提供的替代npm的工具,可以加速node模組的下載 | 通常不安裝使用,國內可通過設定設定npm映象達到同樣效果 |
NPM | 包管理工具,主要用於解決NodeJS程式碼部署問題 | NodeJS中已安裝 |
react-native-cli | React Native的命令列工具用於執行建立、初始化、更新專案、執行打包服務(packager)等任務 | 直接使用npm即可安裝 |
Android 開發環境要求
- Android Studio2.0或更高版本
- [JDK] 1.8或更高版本
- 必須安裝Android Support Repository
環境變數相關
ANDROID_HOME制定到本地 \sdk 對應目錄下
至少需配置:%Android_Home%\tools;%Android_Home%\platform-tools;
當前線上專案相關版本資訊
環境搭建如上圖,如有問題及時聯絡
下面是CodePush的Android客戶端整合部分(熱更新暫時使用微軟的遠端服務)
開啟workspace目錄初始化專案
$ react-native init RnApp
在對應的工作空間生成React Native工程目錄
根目錄下的 package.json 包管理配置檔案
注意:使用命令列初始化的RN工程預設使用官網最新的組建版本,可能存在和某些三方組建的相容性問題(如微軟的CodePush);
如果希望指定RN組建版本初始化,可使用:$ react-native init RnApp --version 0.39.2
{
"name": "RnApp",//工程名稱
"version": "0.0.1",//工程版本號
"private" : true,//讀寫許可權
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",//React Native啟動入口
"test": "jest"
},
"dependencies": {
"react": "15.4.2",//依賴的react版本
"react-native": "0.42.3"//依賴的react-native版本
},
"devDependencies": {//開發除錯依賴庫
"babel-jest": "19.0.0",
"babel-preset-react-native": "1.9.1",
"jest": "19.0.2",
"react-test-renderer": "15.4.2"
},
"jest": {
"preset": "react-native"
}
}
在初始化的RN工程的根目錄下根據提示啟動並執行Android專案
會自動啟動一個本地開發伺服器:如圖代表開發伺服器執行正常
使用 React Native 命令列工具啟動專案異常處理
隨著 React Native 版本不斷升級,Android Studio 的版本變更,包括當前系統環境的差異性,導致在執行RN工程時會存在各種奇奇怪怪的問題;
此時需要將RN工程匯入到當前系統環境的 Android studio 中直接執行,可以避免由於各個工具直接版本的差異導致執行失敗的問題。
使用 Android Studio 開啟初始化的 RN 工程
注意需要在 AS 中選擇RN根目錄結構下的
Android
開啟
如圖表示 React Native 工程在 IDE 中編譯成功
RN初始化工程 App 下的 build.gradle 檔案
可以看到RN的最小SDK構建版本是 16 對應的Android系統版本是 V_4.1.2
apply plugin: "com.android.application"
import com.android.build.OutputFile
apply from: "../../node_modules/react-native/react.gradle"
def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.rnapp"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86"
}
}
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
如果將最小構建版本修改至低於 sdk16,則會導致工程構建失敗,如圖所示:
根據錯誤資訊:如果需要使用 React Native 元件,則需要最低的sdk構建版本不低於16,
如果需要向下相容,則需要使用工具重寫“com.facebook.react”原始碼。
在RN專案根目錄下開啟除錯伺服器
$ npm start
使用AS直接執行RnApp,安裝成功後部分手機需要使用者授權懸浮窗許可權
授權成功後重新開啟專案
如果出現不能獲取除錯橋的錯誤提示,請手動設定除錯埠號為:8081 後點擊 RELOAD(R,R)
設定除錯伺服器埠方式一:adb reverse tcp:8081 tcp:8081
等待 JsBundle 檔案解析完成即可渲染出 RN 頁面
設定除錯伺服器埠方式二:在開發模式下搖晃手機調用出開服者選項設定項
設定除錯伺服器主機名和埠號:
按照如下格式輸入主機名和埠號:
注意:所輸入的主機名一定是當前執行開發伺服器計算機的IP地址,並且除錯機和開發伺服器需要要在同一個區域網環境下;
方式二優點:如果設定成功,在除錯過程中就不需使用USB資料線和計算機連線了。
至此,一個RN工程的 hello world 工程就完成了...
備註:初始化後的RN工程啟動檔案和啟動頁原始碼
程式啟動入口: Application.java
檔案:
package com.rnapp;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
RN頁面入口: ReactActivity.java
檔案子類:
package com.rnapp;
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "RnApp";
}
}
下面是 CodePush 整合詳解
CodePush 簡介
CodePush 是微軟提供的一套用於熱更新 React Native 和 Cordova 應用的服務。
CodePush 是提供給 React Native 和 Cordova 開發者直接部署移動應用更新給使用者裝置的雲服務。CodePush 作為一箇中央倉庫,開發者可以推送更新 (JS, HTML, CSS and images),應用可以從客戶端 SDK 裡面查詢更新。CodePush 可以讓應用有更多的可確定性,也可以讓你直接接觸使用者群。在修復一些小問題和新增新特性的時候,不需要經過二進位制打包,可以直接推送程式碼進行實時更新。
安裝 CodePush CLI
引數 -g 表示安裝位置為全域性,請不要安裝在當前專案目錄下
建立CodePush賬號
涉及到公司開發者賬號,此處省略截圖
- 在終端輸入
$ code-push register
,會開啟如下注冊頁面讓你選擇授權賬號。 - 授權通過之後,CodePush會告訴你
access key
,複製此key到終端即可完成註冊。 - 然後終端輸入
$ code-push login
進行登陸,登陸成功後,你的session檔案將會寫在 /Users/你的使用者名稱/.code-push.config。
在CodePush伺服器註冊app
終端輸入:$ code-push app add RnApp
完成註冊並獲取部署鍵值
Production 表示生產環境 唯一識別的部署鍵值:K1pkiaHC2-w-0M3iRaABluolNtRL4JHzHx0MG
Staging 表示開發環境 唯一識別的部署鍵值:_lvQXBDZ0m_2rFdBlnZ5pkd0fa-n4JHzHx0MG
建議:Android和IOS使用單獨的專案部署獲取兩套 Deployment Key
安裝 react-native-code-push外掛
切換到RN工程根目錄 終端輸入命令:$ npm install react-native-code-push --save
注意:--save 引數表示是否將當前依賴寫入 package.json 檔案
將會在 package.json 檔案中寫入依賴配置
注意:切換到RN工程根目錄 終端輸入命令:$ rnpm link react-native-code-push
將會自動幫我們進行code-push外掛在原生中的gradle配置,
但是不建議使用,我們可以手動的進行 CodePush 的 gradle 配置以達到同樣的效果。
這是引入RN官網的文件:
安裝完node後建議設定npm映象以加速後面的過程(或使用科學上網工具)。注意:不要使用cnpm!cnpm安裝的模組路徑比較奇怪,packager不能正常識別!
即:不建議使用類似 cnpm 活著 rnpm 進行相關模組的操作。
在原生專案中手動整合 CodePush
1. 在 android/app/build.gradle檔案裡面添如下程式碼:
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
2. 在/android/settings.gradle中新增如下程式碼:
include ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
3. 在 android/app/build.gradle檔案裡面添如下程式碼將CodePush新增專案編譯:
compile project(':react-native-code-push')
4. 執行 $ code-push deployment ls RnApp -k
命令獲取
部署祕鑰.
5. 在 MainApplication.java 中新增如下程式碼:
//注意需要將部署鍵值替換成自己的專案的唯一鍵值
new CodePush("deployment-key-here", MainApplication.this, BuildConfig.DEBUG)
6. 在index.Android.js
中呼叫更新服務
相應程式碼可直接複製使用
componentDidMount(){
codePushUpdate();
}
//遠端服務檢測更新
codePushUpdate(){
codePush.sync({
installMode: codePush.InstallMode.IMMEDIATE,
updateDialog: true
},
(status) => {
switch (status) {
case codePush.SyncStatus.CHECKING_FOR_UPDATE:
console.log('codePush.SyncStatus.CHECKING_FOR_UPDATE');
break;
case codePush.SyncStatus.AWAITING_USER_ACTION:
console.log('codePush.SyncStatus.AWAITING_USER_ACTION');
break;
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
console.log('codePush.SyncStatus.DOWNLOADING_PACKAGE');
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
console.log('codePush.SyncStatus.INSTALLING_UPDATE');
break;
case codePush.SyncStatus.UP_TO_DATE:
console.log('codePush.SyncStatus.UP_TO_DATE');
break;
case codePush.SyncStatus.UPDATE_IGNORED:
console.log('codePush.SyncStatus.UPDATE_IGNORED');
break;
case codePush.SyncStatus.UPDATE_INSTALLED:
console.log('codePush.SyncStatus.UPDATE_INSTALLED');
break;
case codePush.SyncStatus.SYNC_IN_PROGRESS:
console.log('codePush.SyncStatus.SYNC_IN_PROGRESS');
break;
case codePush.SyncStatus.UNKNOWN_ERROR:
console.log('codePush.SyncStatus.UNKNOWN_ERROR');
break;
}
},
({ receivedBytes, totalBytes, }) => {
console.log('receivedBytes / totalBytes: ------------ ' + receivedBytes+'/'+totalBytes);
}
);
}
8. 在RN更目錄下新建兩個資料夾
注意:將專案的VersionName修改為三位數!
9. CodePush命令列打JsBundle包(存於本地)
$ react-native bundle --platform android --entry-file index.android.js --bundle-output ./bundles/index.android.bundle --assets-dest ./bundles --dev false
10. 執行如下命令部署到微軟伺服器
$ code-push release PatientMRB ./bundles 1.0.0 --deploymentName Staging --description “RN熱更新測試“ --mandatory true
11. 執行專案日誌輸出如下
至此:一個簡單的RN整合CodePush實現熱更新已經完成...
後續期待和大家一起爬坑...
附錄:CodePush 常用命令總結
- code-push login
- code-push logout
- code-push access-key ls 列出登陸的token
- code—push access-key rm <accessKey> 刪除某個access-key
- code-push app ls
- code-push app add <appName>
- code-push app rm <appName>
- code-push app rename <appName>
- code-push app transfer 轉移app所有權到另一個賬號
- code-push deployment add <appName> 部署
- code-push deployment rename <appName> 重新命名
- code-push deployment ls <appName>
- code-push deployment ls <appName> -k
- code-push deployment history <appName> <deploymentName>(Production||Staging)
- code-push rollback <appName> <deploymentName> “appName”中的測試||生產環境的部署執行回滾
- code-push rollback <appName> <deploymentName> —targetRelease v6 回滾到指定的部署標籤
簡書處女座,如有書寫不妥的地方請留言更正,同時歡迎拍磚吐槽...
最後有一個願望:希望藉此愛上技術寫作...