RN入門---環境搭建和第一個RN項目

一、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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章