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命令提示“不是內部或外部的命令,也不是可執行的程式”,可參考
或是直接將下面網址
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