React Native入門及一些踩過的坑

 

集成步驟也可以參考react-native中文網,但是中間還是會遇到特殊情況,上面沒有說明

一、安裝node(不然npm的時候會報“不是內部命令”)

  npm是nodejs的一個子內容,所以要使用npm,就一定要先安裝nodejs。安裝方法其實沒啥好說的,完全傻瓜化的,官網上下載安裝包,一路next就完了。

  安裝完了如何判斷自己是否安裝成功呢?

  你只需要在命令行窗口中輸入命令:  

node -v    //查看node 的版本號

npm -v   //查看npm的版本號

二、安裝react-native

執行以下命令,進行安裝

npm install -g react-native-cli

三、創建package.json

在項目根目錄下創建一個名爲package.json。可以直接創建,也可以使用npm init創建

{
  "name": "MyRNTest",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "jest"
  },
  "dependencies": {
    "babel-preset-react-native": "^4.0.0",
    "react": "^16.0.0-alpha.6",
    "react-native": "^0.55.0",
    "react-native-update": "^4.0.6"
  },
  "devDependencies": {
    "babel-jest": "21.2.0",
    "jest": "21.2.1",
    "react-test-renderer": "16.0.0-alpha.6"
  },
  "jest": {
    "preset": "react-native"
  }
}

四、配置 maven

在項目的 build.gradle 文件中爲 React Native 添加一個 maven 依賴的入口,必須寫在 "allprojects" 代碼塊中:

allprojects {
    repositories {
        maven {
            //url "$rootDir/node_modules/react-native/android"如果路徑這樣寫,會下載最新版本RN
            url "$rootDir/../node_modules/react-native/android"
        }
        ...
    }
    ...
}

在你的 app 中 build.gradle 文件中添加 React Native 依賴

dependencies {
    implementation 'com.android.support:appcompat-v7:27.1.1'
    ...
    //如果要限制版本:implementation("com.facebook.react:react-native:0.55.0") { force = true }
    implementation "com.facebook.react:react-native:+" 
}
defaultConfig {
        ...

        ndk {
            abiFilters "armeabi-v7a", "x86"
        }

    }
    packagingOptions {
        exclude "lib/arm64-v8a/librealm-jni.so"
    }

    //解決jsr302與jsr305版本衝突
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
    }

五、配置權限

在 AndroidManifest.xml 清單文件中聲明權限:

//網絡權限
<uses-permission android:name="android.permission.INTERNET" />
//彈框權限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

 

如果需要訪問 DevSettingsActivity 界面(即開發者菜單),則還需要在 AndroidManifest.xml 中聲明:

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

六、RN組件

1.首先在項目根目錄中創建一個空的index.js文件。(注意在 0.49 版本之前是 index.android.js 文件)

index.js是 React Native 應用在 Android 上的入口文件。而且它是不可或缺的!

2. 添加你自己的 React Native 代碼,簡單例子,網上都有,我這裏舉一個多入口引用的例子

import React, { Component } from 'react';
import {
  AppRegistry,
  Text,
    View
} from 'react-native';

import MyFirstRN from './myfirstrn'//填寫對應myfirstrn.js路徑,我這裏在根目錄下
import MySecondRN from './mysecondrn'//填寫對應mysecondrn.js路徑,我這裏在根目錄下

//註冊:第一個字段可以認爲是爲RN中的頁面添加映射,需要和你Activity中註冊的名稱一致
AppRegistry.registerComponent('MyRNActivity', () => MyFirstRN);
AppRegistry.registerComponent('MyRNActivity2', () => MySecondRN);

注意,一個RN頁面只能對應註冊一個名稱,不然會被覆蓋,例如:

AppRegistry.registerComponent('MyRNActivity', () => MyFirstRN);
AppRegistry.registerComponent('MyRNActivity2', () => MyFirstRN);
//此時,MyRNActivity2會對應MyFirstRN,MyRNActivity不會對應,你的Activity中如果註冊MyRNActivity
//則會報紅屏MyRNActivity未註冊

myfirstrn.js和mysecondrn.js簡單寫了下,需要注意裏面的class需要用export default修飾,不然import時會報錯

import React, { Component } from 'react';
import {
  AppRegistry,
  Text,
  View
} from 'react-native';

export default class MyFirstRN extends Component {
  render() {
      return (
        <View >
          <Text >
            我是 MyFirstRN ReactNative//例子裏MySecondRN就這裏改了下
          </Text>
        </View>
      );
    }
  }

七、懸浮框權限(僅開發時用於看紅屏報錯)

如果你的應用會運行在 Android 6.0(API level 23)或更高版本,請確保你在開發版本中有打開懸浮窗(overlay)權限。你可以在代碼中使用Settings.canDrawOverlays(this);來檢查。之所以需要這一權限,是因爲我們會把開發中的報錯顯示在懸浮窗中(僅在開發階段需要)。在 Android 6.0(API level 23)中用戶需要手動同意授權。具體請求授權的做法是在onCreate()中添加如下代碼。其中OVERLAY_PERMISSION_REQ_CODE是用於回傳授權結果的字段。

private final int OVERLAY_PERMISSION_REQ_CODE = 1;  // 任寫一個值

...

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);
    }
}
@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
            }
        }
    }
    mReactInstanceManager.onActivityResult( this, requestCode, resultCode, data );
}

八、調用RN頁面

有兩種方法:

1.你的Activity繼承ReactActivity

public class MyRNActivity2 extends ReactActivity {
//public class MyRNActivity2 extends BaseReactActivity {
    @Nullable
    @Override
    protected String getMainComponentName() {
        return "MyRNActivity2";
    }
}

2.你的Activity實現 DefaultHardwareBackBtnHandler 接口

public class MyRNActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {

    private ReactRootView mReactRootView;

    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()

                .setApplication(getApplication())

                .setCurrentActivity(this)

                .setBundleAssetName("index.android.bundle")

                .setJSMainModulePath("index.android")//xxx.js
                .addPackage(new MainReactPackage())

                .setUseDeveloperSupport(true)

                .setInitialLifecycleState(LifecycleState.RESUMED)

                .build();

        // 注意這裏的MyReactNativeApp必須對應“index.android.js”中的
        // “AppRegistry.registerComponent()”的第一個參數
        mReactRootView.startReactApplication(mReactInstanceManager, "MyRNActivity", null);
        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        if(mReactInstanceManager!=null){
            mReactInstanceManager.onBackPressed();
        }else{
            super.onBackPressed();
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        if(mReactInstanceManager!=null){
            mReactInstanceManager.onHostResume(this,this);
        }

    }


    @Override
    protected void onPause() {
        super.onPause();

        if(mReactInstanceManager!=null){
            mReactInstanceManager.onHostPause(this);
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();

        if(mReactInstanceManager!=null){
            mReactInstanceManager.onHostDestroy(this);
        }
    }

}

另外:如果是原生和RN混合頁面,可以在佈局中添加RN控件,在activity中findview出來

<com.facebook.react.ReactRootView
    android:id="@+id/test_js2"
    ....
/>
public class MyRNActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {

    private ReactRootView mReactRootView,mReactRootView2;

    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_rn);

        mReactRootView = findViewById(R.id.test_js);
        mReactInstanceManager = ReactInstanceManager.builder()

                .setApplication(getApplication())

                .setCurrentActivity(this)//可以不需要此代碼

                .setBundleAssetName("index.android.bundle")

                .setJSMainModulePath("index.android")//xxx.js
                .addPackage(new MainReactPackage())

                .setUseDeveloperSupport(true)

                .setInitialLifecycleState(LifecycleState.RESUMED)

                .build();

        // 注意這裏的MyReactNativeApp必須對應“index.android.js”中的
        // “AppRegistry.registerComponent()”的第一個參數
        mReactRootView.startReactApplication(mReactInstanceManager, "MyRNActivity", null);

    }

    @Override
    public void invokeDefaultOnBackPressed() {
        if(mReactInstanceManager!=null){
            mReactInstanceManager.onBackPressed();
        }else{
            super.onBackPressed();
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        if(mReactInstanceManager!=null){
            mReactInstanceManager.onHostResume(this,this);
        }

    }


    @Override
    protected void onPause() {
        super.onPause();

        if(mReactInstanceManager!=null){
            mReactInstanceManager.onHostPause(this);
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();

        if(mReactInstanceManager!=null){
            mReactInstanceManager.onHostDestroy(this);
        }
    }

}

九、Application繼承ReactApplication

public class MyApp extends Application implements ReactApplication {

    private ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

        @Override
        public boolean getUseDeveloperSupport() {
            return true;
        }

        @Override
        protected String getJSMainModuleName() {
            return "index.android";
        }

        @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,false);
        }
}

十、生成.bundle和.map文件

在app/main下創建assets文件夾,然後Android Studio Terminal在執行。0.49之後的版本index.android.js用index.js

$ react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.b
undle --assets-dest app/src/main/res/
>npm start

十一、一些坑

1.RN頁面首次加載時,會白屏一下,可以採用 預加載 的方法

2.調試時請確保電腦和手機在同一WiFi環境下,不要使用WiFi共享類的軟件,那可能導致APP紅屏報404

3.紅屏報錯調用不到.so文件,app目錄下的build.gradle中沒有添加ndk {abiFilters "armeabi-v7a", "x86"}

4.

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