集成 React Native 到現有的 Android 項目( Mac, Windows 通用版 )

原文連接:
motalks.cn/2016/10/26/…
轉載請註明來源。javascript

因爲公司的 Win 7 系統的臺式機性能比較好,因此我又在 Windows 系統上又走了一遍 React Native 開發環境搭建和集成 React Native 到現有的 Android 項目的過程。在集成 React Native 這塊 Mac 和 Windows 系統的差別卻是很小,坑比較可能是環境搭建那塊,回頭在把 Windows 下的 React Native 環境搭建寫寫。最後還有一個忠告,買 Mac Book Pro 請直接上頂配,都是淚。html

在已有項目中初始化 React Native

在項目根目錄下執行下面三行命令,進行初始化 React Native 的流程。java

npm init
npm install --save react react-native
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig複製代碼

下面分步講解每一個命令的做用:node

關於 npm init 命令

這步操做會在項目根目錄生成 package.json 文件。主要是些項目信息,這裏會生成以後步驟須要的 」scripts「 字段,本身的過程忘記截圖了,用了 天空oo7 的圖。react

img

接下來,將 package.json 文件中 scripts 字段下添加下面這句,同時也能夠將 」test「:"no" 這句刪去。下面這句的做用應該是配置 」start「 命令的路徑的。android

"start": "node node_modules/react-native/local-cli/cli.js start"複製代碼

關於 install --save react react-native 命令

用於初始化 React 和 React Native 相關文件,安裝完成後會在項目的根目錄下看到 node_modules 文件夾。git

圖片來自 天空007

關於 curl 命令

curl是利用URL語法在命令行方式下工做的開源文件傳輸工具。它被普遍應用在Unix、多種Linux發行版中,而且有DOS和Win3二、Win64下的移植版本。github

因爲 Mac OS 是基於Unix 內核,因此 Mac 在網絡暢通的狀況下,這條命令很愉快的就執行完畢了,然後會在你項目根目錄下生成一個 .flowconfig 文件。web

在 Windows 上你會絕望的看到命令行窗口顯示 「 ' curl' 不是內部或外部命令,也不是可運行的程序或批處理文件" 的提示。你能夠按照《 Windows 下安裝使用 curl 命令》教程去使用該命令,也能夠直接在項目的根目錄下新建個 .flowconfig 文件,再將 raw.githubusercontent.com/facebook/re… 的內容複製到該文件中。方便網絡不順暢的同窗,已將該網頁配置信息複製在下面(該配置信息隨時會更新,建議仍是到網站獲取實時配置信息)。shell

[ignore]

# We fork some components by platform.
.*/*[.]android.js

# Ignore templates with `@flow` in header
.*/local-cli/generator.*

# Ignore malformed json
.*/node_modules/y18n/test/.*\.json

# Ignore the website subdir
<PROJECT_ROOT>/website/.*

# Ignore BUCK generated dirs
<PROJECT_ROOT>/\.buckd/

# Ignore unexpected extra @providesModule
.*/node_modules/commoner/test/source/widget/share.js

# Ignore duplicate module providers
# For RN Apps installed via npm, "Libraries" folder is inside node_modules/react-native but in the source repo it is in the root
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js
.*/node_modules/jest-runtime/build/__tests__/.*

[include]

[libs]
Libraries/react-native/react-native-interface.js
flow/

[options]
module.system=haste

esproposal.class_static_fields=enable
esproposal.class_instance_fields=enable

experimental.strict_type_args=true

munge_underscores=true

module.name_mapper='^image![a-zA-Z0-9$_-]+複製代碼
-> 'GlobalImageStub' module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\) -> 'RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FixMe suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy unsafe.enable_getters_and_setters=true [version] ^0.33.0

添加 index.android.js 文件到項目根目錄

在根目錄下新建 index.android.js 文件,複製下面這段內容進去便可。

'use strict';

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('HelloWorld', () => HelloWorld);複製代碼

已有項目的相關配置

module 級別的 build.gradle 配置修改

在你 app 文件夾下的 build.gradle 文件(module級別的gradle)添加 React Native 的依賴。

dependencies {
    compile "com.facebook.react:react-native:+" // From node_modules.
}複製代碼

這裏的 "+" 號表示跟隨最新的 React Native 版本,也能夠指定具體的版本號。

project 級別的 build.gradle 配置修改

在你項目根目錄 的 build.gradle 文件(project級別的gradle)添加

allprojects {
    repositories {
        jcenter()
        maven {
              // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
    }
}複製代碼

這裏要注意的是在 allprojects 節點下添加。這是由於Android項目默認的依賴包的源 jcenter() 並不包含最新版的 React Native(它只到0.20.1)。新版的 React Native 都只在 npm 裏發佈,所以你須要增長一下依賴包的源。在編譯完後,檢查 External Libraries 的 react-native 版本,若爲 0.20.1 則說明 maven 的依賴源沒有添加成功。能夠更改 url 路徑爲 "$rootDir/node_modules/react-native/android" 試試。目前獲取到的最新版本應該是0.35.0。

圖片來自 天空007

添加原生代碼

須要注意點:從0.29.0版本開始,在生命週期方法 onResume(), onPause() 中mReactInstanceManager調用的方法改成 onHostResume(), onHostPause() 。可是如今0.35.0的官方文檔 mReactInstanceManager 仍是調用 onResume(), 然而 ReactInstanceManager 已經改成 onHostResume() 了,因此還調用 onResume() 會報紅。其餘須要注意的都寫在註釋裏了。

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.facebook.react.BuildConfig;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
/** * Created by silencelin on 2016/10/24. */
public class MyReactActivity extends Activity 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())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
          // startReactApplication 方法中的 moduleName 參數必須和你在index.android.js 文件中 // AppRegistry.registerComponent 註冊的項目名稱保持一致
        mReactRootView.startReactApplication(mReactInstanceManager, "AwesomeProject", null);
        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        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();
        }
    }   

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy();
        }
    }

      @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }
}複製代碼

接下來別忘記在 AndroidManifest.xml 中註冊。

<activity android:name=".MyReactActivity" android:label="@string/app_name" android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />複製代碼

其中 DevSettingsActivity 是下面這個設置頁面,也是開發過程當中必需要使用到的頁面。

DevSettingActivity

還有網絡權限,通常項目都會有這個權限了。

<uses-permission android:name="android.permission.INTERNET" />複製代碼

還有個權限,官方文檔和其餘不少文章都沒提到,老司機要發車了,你們坐穩了。就是懸浮窗權限,沒有申請這個權限你胳膊搖出麒麟臂都沒辦法調出上圖這個設置菜單的。

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>複製代碼

真機搖一搖調出設置菜單

Run your App !

終於到這個激動人心的時刻了,在你項目根目錄輸入以下命令

npm start複製代碼

關於 npm start 命令

該命令會執行 package.json 文件中 「 scripts 」 下的「 start 」 的值。

"scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  }複製代碼

看了下這個 cli.js 文件,最後執行的是 cliEntry.js 裏面的腳本,一堆配置參數,簡單的說就是在本地配置一個 web 服務器環境吧。(nodeJs 真的不懂,如有錯誤,煩請指正。)

成功的樣子如圖:

npm_start_success

Run your app 的注意事項

接下來就像往常同樣,點擊 Android Run 按鈕,將項目部署到虛擬機或者真機上了。注意 build 模式要選擇debug 。若是不當心選擇了 release 模式,你會遇到這個報錯:

Could not get BatchedBridge, make sure your bundle is packaged correctly

由於正式版須要你建立 React Native bundle 存放到本地 asserts 目錄。運行以下命令:

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/複製代碼

注意將 android/com/your-company-name/app-package-name/src/main 替換成你項目的實際路徑。最後看到asserts 目錄裏生成了 index.android.bundle 和 index.android.bundle.meta 兩個文件就說明上面命令執行成功,能夠愉快的去 run 你的項目了。

debug build 和 release build 方式 React Native 代碼調試的區別

debug build : 修改完 js 代碼能夠直接搖一搖 選擇 Reload Js 就能夠看到更新後的效果。

release build : 修改完 js 代碼須要從新生成 index.android.bundle 文件,才能看到更新後的效果。由於正式版發佈後是沒法依賴本地服務器去更新index.android.bundle 。因此這個催生了一個 React Native 怎麼熱更新的問題。

接下來的安排

React Native Android 開發環境搭建 (已出)

React Native 集成到現有的 Android 項目(本篇)

React Native 項目熱更新(待更新)

React Native 優化(包大小優化,預加載解決首次加載白屏等)(待更新)

相關文章
相關標籤/搜索