React Native學習<四> 把ReactNative 嵌入到原生代碼中

核心概念

如果你正準備從頭開始制作一個新的應用,那么React Native會是個非常好的選擇。但如果你只想給現有的原生應用中添加一兩個視圖或是業務流程,React Native也同樣不在話下。只需簡單幾步,你就可以給原有應用加上新的基于React Native的特性、畫面和視圖等。

把React Native組件植入到Android應用中有如下幾個主要步驟:

  1. 首先當然要了解你要植入的React Native組件。
  2. 在Android項目根目錄中使用npm來安裝react-native ,這樣同時會創建一個node_modules/的目錄。
  3. 創建js文件,編寫React Native組件的js代碼。
  4. build.gradle文件中添加com.facebook.react:react-native:+,以及一個指向node_nodules/目錄中的react-native預編譯庫的maven路徑。
  5. 創建一個React Native專屬的Activity,在其中再創建ReactRootView
  6. 啟動React Native的Packager服務,運行應用。
  7. 根據需要添加更多React Native的組件。
  8. 在真機上運行調試
  9. 打包
  10. 發布應用,升職加薪,走向人生巔峰!??

開發環境準備

首先按照開發環境搭建教程來安裝React Native在安卓平臺上所需的一切依賴軟件(比如npm)。

在應用中添加JS代碼

在項目的根目錄中運行:

npm init
npm install --save react react-native
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
  • 1.npm init`創建了一個空的node模塊(過程需要填寫其實就是創建了一個package.json描述文件)。
流程
  • 2.npm install`則創建了node_modules目錄并把react和react-native下載到了其中。
新增的部分
  • 3.這一步非必需,可跳過,curl命令,其實質是下載.flowconfig配置文件,這個文件用于約束js代碼的寫法。

下面我們打開新創建的package.json文件,去除:

    "test": "echo \"Error: no test specified\" && exit 1"

然后在其scripts字段中加入:

"start": "node node_modules/react-native/local-cli/cli.js start"

現在你的package.json內容應該類似這樣:

{
  "name": "myreact",
  "version": "1.0.0",
  "description": "test",
  "main": "index.js",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"

  },
  "author": "AFinalStone",
  "license": "ISC",
  "dependencies": {
    "react": "^15.4.2",
    "react-native": "^0.41.2",
    "react-native-storage": "^0.2.1"
  }
}

示例中的version字段沒有太大意義(除非你要把你的項目發布到npm倉庫)。scripts中是用于啟動packager服務的命令。dependencies中的react和react-native的版本取決于你的具體需求。一般來說我們推薦使用最新版本。你可以使用npm info reactnpm info react-native來查看當前的最新版本。另外,react-native對react的版本有嚴格要求,高于或低于某個范圍都不可以。本文無法在這里列出所有react native和對應的react版本要求,只能提醒讀者先嘗試執行npm install,然后注意觀察安裝過程中的報錯信息,例如require react@某.某.某版本, but none was installed,然后根據這樣的提示,執行npm i -S react@某.某.某版本

接下來在項目根目錄中創建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}>Congratulations on your success</Text>
      </View>
    )
  }
}
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

AppRegistry.registerComponent('myreact', () => HelloWorld);
  • 注意,AppRegistry.registerComponent('myreact', () => HelloWorld)的第一個參數要和package.json中的name一致

準備工作

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

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

如果想要指定特定的React Native版本,可以用具體的版本號替換 +,當然前提是你從npm里下載的是這個版本 。

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

allprojects {
    repositories {
        jcenter()
        maven { url 'https://maven.google.com' }
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/node_modules/react-native/android"
        }
    }
}

確保依賴路徑的正確!以免在 Android Studio 運行Gradle同步構建時拋出 “Failed to resolve: com.facebook.react:react-native:0.x.x" 異常。

接著,在 AndroidManifest.xml 清單文件中聲明網絡權限:

<uses-permission android:name="android.permission.INTERNET" />

如果需要訪問 DevSettingsActivity 界面,也需要在 AndroidManifest.xml 中聲明:

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

This is only really used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to.

添加原生代碼

想要通過原生代碼調用 React Native ,就像這樣,我們需要在一個 Activity 中創建一個 ReactRootView 對象,將它關聯一個 React application 并設為界面的主視圖。

如果你想在安卓5.0以下的系統上運行,請用 com.android.support:appcompat 包中的 AppCompatActivity 代替 Activity

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;

public class MyReactActivity 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())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();

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

        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
}

如果你的項目名字不是叫“myreact”,則需要將“index.android.js”中的“AppRegistry.registerComponent()”方法中的第一個參數替換為對應的名字。

如果你使用的是 Android Studio , 可以使用Alt + Enter快捷鍵來自動為MyReactActivity類補上缺失的import語句。注意引入的BuildConfig應該是在你自己的包中,而不是在...facebook...的包中。

我們需要把 MyReactActivity 的主題設定為 Theme.AppCompat.Light.NoActionBar ,因為里面有許多組件都使用了這一主題。

<activity
  android:name=".MyReactActivity"
  android:label="@string/app_name"
  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>

現在activity已就緒,可以運行一些JavaScript代碼了。

配置權限以便開發中的紅屏錯誤能正確顯示,或者你直接把targetSdkVersion設置為22也行

如果你的應用會運行在Android 6.0(API level 23)或更高版本,請確保你在開發版本中有打開懸浮窗(overlay)權限。If your app is targeting the Android API level 23 or greater, make sure you have the overlay permission enabled for the development build. You can check it with Settings.canDrawOverlays(this);. This is required in dev builds because react native development errors must be displayed above all the other windows. Due to the new permissions system introduced in the API level 23, the user needs to approve it. This can be acheived by adding the following code to the Activity file in the onCreate() method. OVERLAY_PERMISSION_REQ_CODE is a field of the class which would be responsible for passing the result back to the Activity.

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);
    }
}

Finally, the onActivityResult() method (as shown in the code below) has to be overridden to handle the permission Accepted or Denied cases for consistent UX.

@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...
            }
        }
    }
}

運行你的應用

運行應用首先需要啟動開發服務器(Packager)。你只需在項目根目錄中執行以下命令即可:

npm install
npm start

保持packager的窗口運行不要關閉,然后像往常一樣編譯運行你的Android應用(在命令行中執行./gradlew installDebug或是在Android Studio中編譯運行)。

如果你是使用Android Studio來編譯運行,有可能會導致packger報錯退出。先把packager服務窗口關掉,然后再使用AndroidStudio編譯運行Android應用,
這個時候只保持在MainActivity頁面,然后重新在項目根目錄執行npm start命令,然后操作APP進入MyReactActivity的頁面

編譯執行一切順利進行之后,在進入到MyReactActivity時應該就能立刻從packager中讀取JavaScript代碼并執行和顯示:

結果

在Android Studio中打包

你也可以使用Android Studio來打release包!其步驟基本和原生應用一樣,只是在每次編譯打包之前需要先執行js文件的打包(即生成離線的jsbundle文件,這樣APP進入RN編寫的頁面會直接調用本身的JS代碼,不需要去服務器請求)。
具體的js打包命令如下:

    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

其中--bundle-output后面的兩個參數指出assets和res文件夾的具體路徑,注意把上述命令中的路徑替換為你實際項目的路徑。如果assets目錄不存在,需要提前自己創建一個。

然后在Android Studio中正常生成release版本即可!

打包好的release版本app運行在許多X64CPU的手機上,打開RN頁面直接閃退

錯誤:

java.lang.UnsatisfiedLinkError: dlopen failed: "xxx/libgnustl_shared.so" is 32-bit instead of 64-bit

解決方案:

1、在項目的根目錄的 gradle.properties里面添加一行代碼

android.useDeprecatedNdk=true.

2、在project的root目錄下的build.gradle中添加如下代碼。

defaultConfig {
    ···
    ndk{
        abiFilters "armeabi-v7a","x86"
    }
    packagingOptions {
        exclude "lib/arm64-v8a/librealm-jni.so"
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容