1. 程式人生 > >Android原生專案整合React Native踩坑記

Android原生專案整合React Native踩坑記

最近在學習React Native,將Android原生專案整合React Native實現混合開發。參考官網和其他一些相關資料,自己動手一步一步操作,發現真的是一步步踩坑再填坑的過程,此文章記錄整合React Native的步驟和出現的問題,方便以後查閱。
我這裡使用的環境是AndroidStudio
react-native為0.48.3
npm為3.10.10

建立Android原生專案

使用AndroidStudio建立Android原生專案ReactNativeLearnApp。

在原生專案中初始化React Native

在專案根目錄(ReactNativeLearnApp)下執行下面三條命令,初始化React Native。執行命令可以在Windows命令列下或是AndroidStudio的Terminal下,我這裡使用AndroidStudio的Terminal:
1.npm init:生成package.json檔案,即RN的配置檔案


根據需要進行填寫,如下圖所示:
這裡寫圖片描述

這裡寫圖片描述
此時在 package.json 檔案中 scripts 欄位下新增
“start”: “node node_modules/react-native/local-cli/cli.js start”配置start命令的路徑,如下圖所示:
這裡寫圖片描述
2.npm install –save react react-native:用於安裝 React、React Native 相關檔案,安裝完成後會在專案的根目錄下看到 node_modules 資料夾。
如下圖所示:
這裡寫圖片描述

對於windows直接直接curl命令提示“不是內部或外部的命令,也不是可執行的程式”,可參考

http://9410445.blog.51cto.com/9400445/1763891進行配置。
或是直接將下面網址
https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig裡的內容存為.flowconfig檔案。

在檔案根目錄下新建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);

我這裡只是顯示”Hello, World”,可根據需要進行修改。

在Android原生專案中整合React Native程式

1.在App的build.gradle檔案下新增facebook react 依賴包:
如下所示:

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

sync發現錯誤”com.google.code.findbugs:jsr305”,錯誤資訊如下所示:
這裡寫圖片描述
解決方法:
在App的build.gradle中新增如下程式碼:

android {
    ...
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
    }
}

注意:最新版本中支援的是23,即編譯版本改為23,以及appcompat-v7:23.0.1,同時將minSDK改為16,否則會提示錯誤。
2.在project的build.gradle檔案下新增配置
如下所示:

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

3.新增原生程式碼:
兩種方法:
第一種:寫法簡單。但是無法區域性使用React Native來佈局:
只需要自定義一個Activity,並繼承ReactActivity,實現getMainComponentName方法,在getMainComponentName方法中返回RN註冊的名稱即可,名稱需要與index.android.js中AppRegister的名稱相同。然後建立Application,去初始化ReactNativeHost。自定義Application需要繼承ReactApplication。
具體實現:

public class MyReactActivity extends ReactActivity{
    @Nullable
    @Override
    protected String getMainComponentName() {
        return "HelloWorld";
    }
}
public class MyApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

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

第二種:官網給出的方法:
可以利用React Native來寫我們介面中的某一塊區域,利用原生布局的addView()方法把mReactRootView加入到佈局中,下面舉例說明:
佈局檔案為:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.liuwei.reactnativelearnapp.MainActivity"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="測試"/>

    <LinearLayout
        android:id="@+id/main_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    </LinearLayout>

</LinearLayout>

MyReactActivity.java:

public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {

    private LinearLayout mReactLayout;
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        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, 100);
            }
        }
        setContentView(R.layout.react_activity);
        mReactLayout = (LinearLayout)this.findViewById(R.id.main_layout);
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")//對應index.android.js
                .addPackage(new MainReactPackage())
                //.setUseDeveloperSupport(BuildConfig.DEBUG) //開發者支援,BuildConfig.DEBUG的值預設是false,無法使用開發者選單
                .setUseDeveloperSupport(true) //開發者支援,開發的時候要設定為true,不然無法使用開發者選單
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        //這裡的ReactNativeView對應index.android.js中AppRegistry.registerComponent('HelloWorld', () => HelloWorld);的HelloWorld
        mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);
        mReactLayout.addView(mReactRootView);
    }

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

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

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 100) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(this)) {
                    // SYSTEM_ALERT_WINDOW permission not granted...
                }
            }
        }
    }

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

注意:在清單檔案中宣告建立的Activity和許可權:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.liuwei.reactnativelearnapp">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

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

</manifest>

其中DevSettingsActivity是為了在執行時顯示裝置選項。

執行專案

1.執行npm start命令:
如下圖所示:
這裡寫圖片描述
2.執行AndroidStudio的run:
第一:出現”java.lang.UnsatisfiedLinkError”錯誤,如下圖所示:
這裡寫圖片描述
解決方法:
在App下的build.gradle檔案中新增NDK支援,如下所示:

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

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

第二:再次run,執行出現錯誤”Unable to load script from assets index.android.bundle”:
這裡寫圖片描述
日誌顯示:
這裡寫圖片描述
原因:
需要手動建立 React Native bundle 存放到本地 asserts 目錄。
解決方法:
先在android/app/src/main/目錄下建立assets資料夾;
再執行命令:

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/

其中:
–platform:平臺
–dev:開發模式
–entry-file:條目檔案
–bundle-output:bundle檔案生成的目錄
–assets-dest:資原始檔生成的目錄
這裡寫圖片描述
命令成功執行後會看到asserts 目錄裡生成了 index.android.bundle 和 index.android.bundle.meta 兩個檔案。
第三:執行run,出現“undefined is not an object (evaluating ‘nr.ReactCurrentOwner’)”錯誤:
這裡寫圖片描述
日誌顯示:
這裡寫圖片描述
解決方法:
在專案根目錄下執行
yarn add [email protected]
或是
npm i [email protected] –save命令
第四:執行時注意:
先執行以下幾條命令
npm start
adb devices
adb reverse tcp:8081 tcp:8081
之後點選run執行專案,淚奔啊,終於成功了!!!
這裡寫圖片描述
其中測試為原生,Hello,World為react native。。。

總結

以上是我的Android原生專案整合React Native的步驟,遇到的問題和相關解決方案,如有問題,歡迎大家指教!
如有需求,請點選下載Demo

相關推薦

Android原生專案整合React Native

最近在學習React Native,將Android原生專案整合React Native實現混合開發。參考官網和其他一些相關資料,自己動手一步一步操作,發現真的是一步步踩坑再填坑的過程,此文章記錄整合React Native的步驟和出現的問題,方便以後查閱。

Android原生專案整合React Native

剛建立的React Native 微信公眾號,歡迎微信掃描關注訂閱號,每天定期會分享react native 技術文章,移動技術乾貨,精彩文章技術推送。同時可以掃描我的微信加入react-native技術交流微信群。歡迎各位大牛,React Native技術愛好者加入

最新iOS原生專案整合React-Native

       大樓不是一天所建成,是時間慢慢積累起來滴,原先用原生寫的專案,沒辦法將專案中所有的程式碼都換成RN,而且我也不認為全換成RN就是好的,所以準備先將專案中的一些頁面改成RN開發。由於我們並沒有使用Cocoapods,因為Cocoapods管理第三方依賴的時候會

react native

react native 碰到的幾個坑。記錄如下。 1.com.facebook.react.common.JavascriptException: undefined is not an object (evaluating 'n.internals.offset[e]'), stack:

react native(建立指定的React-Native版本)

建立指定的React-Native版本 剛剛開始學習React Native,很多都不懂,搭建環境的時候遇到了挺多問題的,一直在折騰。 我是按照React Native文件來搭建環境的,安裝react-native-cli使用的是下面的命令。 npm in

React Native

一、遇到過的坑 1.1 執行Downloading https://services.gradle.org/distributions/gradle-2.4-all.zip時報錯 解決方法:複製報錯的下載連結,用迅雷下載, 將專案地址中的AwesomeP

react native

react native 碰到的幾個坑。記錄如下。 1.com.facebook.react.common.JavascriptException: undefined is not an object (evaluating 'n.internals.offset[e]'

React Native之路 — 執行Android專案的各種(Windows)

之前我們已經初始化了一個Raect Native 專案,驗證了Android環境的正確性,接下來就執行起來吧! 執行命令:        ① react-native start        ② react-native run-android 執行步驟: 1.

React-Native開發二 Android 已有專案整合React-Native

1 前言 之前寫過一篇RN的環境搭建教程和新建一個新的RN專案的文章 https://blog.csdn.net/qiyei2009/article/details/78820207 但是其實在實際開發中,在已有的android專案中整合RN情況更普遍,這篇文章就是一個怎麼在已有

window下Android專案整合React Native的正確姿勢

      React Native的專案中分為Android與IOS,但是若在現有的Android專案中,整合RN,不能按照那個包結構來,我們統一在app資料夾下處理。 一、整合步驟:    1.新增js檔案   &n

Android 原生應用嵌入React-Native模組開發-環境配置及填

1.Can't find variable: __fbBatchedBridge 還是在專案的根資料夾下,命令列執行如下命令,啟動測試伺服器。$ npm start 但是部分Android 6.0的機

android 架構之整合react native框架js混編APP

本篇文章主要總結一下現在APP當中使用的js、webView混編架構和技術。 什麼是 js 混編? js混編簡單說就是使用JavaScript開發APP程式。 android應用使用的是java,Kotlin 、c/c++ 為主的語言開發,ios使用的ob

react-native日記

1、在IOS11.3版本中scrollView下的用Text包裹的文字不顯示內容,解決方式:將文字用多個Text分開包裹。 以上會出現閃退的情況,最好是將文字單獨建立HTML檔案然後將其用WebView引入。 android的HTML檔案需要放在android\app\src\main\as

React-native日記(一)

建立頁面跳轉時報錯 undefined is not an object (this.props.navigation.navigate 學習 React-native 的第一個心得就是要做好踩坑的準備,之前剛入手的時候瘋狂紅屏,於是各種百度, 終於可以正常

react-native 紀實(1)- 安裝環境

一、安裝環境 開發rn得裝個nodejs,我機器有,這一步就免了。然後開啟rn的官網 瞄了一下,官網的get start使用的是expo 來進行開發,這個東西我體會了一下就是能快速進入開發狀態。不用裝android-studio,手機裝一個Expo客戶端就直接能用,省

React Native 日記

一、TabBarIOS 出現react.children.only expected to receive a single react element child 問題程式碼於示圖: findP

react-native 適用於新學者 ide:visual studio

用書《react native 跨平臺移動應用開發》(第二版)作者:闕喜濤 1.在試執行第一個程式碼時,用VS進行了程式碼編輯,輸入Dimensions時,VS自動添加了如下程式碼 import { Dimensions } from './C:/Users/HP/App

create-react-app

tcs onf class working zip als mpi iconfont hat 前言 哇,不的不說這個react 這個腳手架create-react-app腳確實有很多問題,哈哈,下面來看看吧有哪些坑: 引用sass或者less 記得16

vue專案部署至nginx&

1.  前言         在本地吭哧吭哧的寫了兩個星期,終於到了需要部署到伺服器供測試的時候了!!         初始的設想是部署到tomcat,放在ROOT目錄下,即可以使用 域名:埠/ 訪問,但是涉及到後臺請求跨域了,百度+諮詢前同事,得出了結論:通過nginx

React Native ----- react-navigation_標題居中

很少寫blog,尤其是技術類的,今天看了下RN已經升級到55了,記得之前用的還是在43版本,新功能就不多說了,自己去看React Nativ官網。剛剛用了下react-navigation,發現很玩,但是也遇到了一些坑,以下是填坑。1,標題文字設定react-navigati