一、RN環境的搭建,參照RN中文網,有以下概念
Chocolatey:Chocolatey是一個Windows上的包管理器,用於安裝windows程序
Python 2:
NodeJS:NodeJS是基於javascript的服務端。將本地的js文件(RN裏,將返回的js文件通過依賴React翻譯成React格式,再通過依賴react-native,翻譯爲react-native格式)返回客戶端(即android端)。
bundle文件:react-native格式的js文件(react-native格式的js代碼可以說是一個轉換器,在nodejs端可以依賴react-native插件對應js代碼,在android可以依賴react-native插件對應java代碼,react-native插件是翻譯官)是放在bundle文件內的,android端是和它交互的。當android端和nodejs端離線時,放在assets目錄下;服務端啓動時,直接返回bundle文件。android端一個RN界面從bundle中拿取當前界面需要的內容(如下圖),並依賴react-native插件將這些內容映射爲原生視圖和事件處理。
android端一個RN頁面需要的內容如下,需要和NodeJS端的主js文件導出的組件名一致(可以理解爲將此頁面的所有內容打包到這個名字下了):
android:
Js:
react-native-cli:相當於node.js的一個插件,相當於nodejs的一個入口。兩個作用:1.初始化出一個帶有支持RN組件的android Demo工程,2.該插件的作用還有當node.js服務啓動後,當native端的APP發起JS請求時,檢查服務端的js信息是否有更新,並將它們轉化爲react-native格式傳給native端。
npm:node packege manage,node包管理器,負責nodejs的模塊安裝。裝nodejs時,npm就已經自動安裝好了。
二、當直接initRN項目時
很簡單,直接調用”react-native init”命令即可。會從相關的遠程copy配置好的工程目錄層次到本地。
三、當將原生集成RN時:
NodeJS端環境:
1、將原生工程放入android文件夾內
2、在根目錄下新建packege.json文件,填入以下內容(也可通過“npm init”命令實現),類似gradle配置文件:
version字段沒有太大意義(除非你要把你的項目發佈到npm倉庫)。scripts中是用於啓動packager服務的命令。dependencies中的react和react-native的版本取決於你的具體需求。一般來說我們推薦使用最新版本。你可以使用npm info react和npm info react-native來查看當前的最新版本。另外,react-native對react的版本有嚴格要求,高於或低於某個範圍都不可以。
3、執行“npm install”命令安裝後,就會生成”node_moudles”文件夾。
Android端環境:
1、在你的app中 build.gradle 文件中添加 React Native 依賴:
2、爲確保android端和nodejs端react-native版本一致,在項目的 build.gradle 文件中爲 React Native 添加一個 maven 依賴的入口,必須寫在 “allprojects” 代碼塊中:
3、因爲要和nodejs端交互,添加網絡權限
4、如果需要訪問 DevSettingsActivity 界面(即開發者菜單),則還需要在 AndroidManifest.xml 中聲明,開發者菜單一般僅用於在開發時從Packager服務器刷新JavaScript代碼,所以在正式發佈時你可以去掉這一權限。
android端代碼:
一個rn界面:
//該Activity不用直接繼承ReactActivity,但是實現DefaultHardwareBackBtnHandler接口,以處理相關的手機按鍵事件
public class RNSceActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private static final int OVERLAY_PERMISSION_REQ_CODE = 102;
private static final String TAG = "---";
private ReactRootView mReactRootView;//JS對應的Native的根佈局
private ReactInstanceManager mReactInstanceManager;//Instance 管理器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main); //RN中不需要此處填充view 使用解析到的JS端的view填充
initRNRootView();//初始化RN的rootView,所有解析到的view都按規則添加到該View上
//打開懸浮窗(overlay)權限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
}
private void initRNRootView() {
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder().setApplication(getApplication())
.setBundleAssetName("index.android.jsbundle")//main.jsbundle
.setJSMainModuleName("index.android")//index.android
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)//BuildConfig.DEBUG 直接用debug 出現crash ---http://blog.csdn.net/guxiao1201/article/details/50899136
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "RNFirstComponent", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (mReactInstanceManager != null && keyCode == KeyEvent.KEYCODE_MENU) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
//打開懸浮窗(overlay)權限
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
Log.d(TAG, "onActivityResult: ");
}
}
}
}
}
需要把其中一段代碼拿出來說:
js端代碼:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class HelloWorld extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.hello}>Hello, World</Text>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('RNFirstComponent', () => HelloWorld);//名字必須和上圖android端請求的一致
四、另:
1、當nodejs服務端啓動不起來時,停留在下圖所示:
此時需要通過命令行生成離線bundle。
2、 手動生成bundle文件,需要我們執行如下命令:
react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/
3、React Native項目在64位Android手機上運行,會提示
“/data/data/com.xxx.xxx/lib-main/libgnustl_shared.so” is 32-bit instead of 64-bit 這個錯誤。
解決方法就是取消掉所有的64位的.so文件,全部加載32位的就可以了,下面是步驟
a、在項目的根目錄的 gradle.properties 裏面添加一行代碼 android.useDeprecatedNdk=true.
b、在 build.gradle 文件裏添加以下代碼
android {
...
defaultConfig {
...
ndk {
abiFilters "armeabi-v7a", "x86"
}
packagingOptions {
exclude "lib/arm64-v8a/librealm-jni.so"
}
}
}
4、可以通過數據線和服務端連接即時拿取bundle文件;也可通過wifi和服務端連接即時拿取bundle文件(要求手機和電腦在同一個wifi下);也可以通過命令直接生成離線bundle。
5、服務端執行npm start 窗口會顯示打包bundle的進度如下
五、參考:
http://reactnative.cn/docs/0.50/integration-with-existing-apps.html#content
http://blog.csdn.net/chichengjunma/article/details/53815299
http://m.blog.csdn.net/M075097/article/details/76551415