話說原生Android app嵌入reactnative頁面的網上資料也不少了,而且也不錯,但是自己照着做的時候還是問題多多,難道真的是坑太多嗎?摸索着最終還是實現了,唉,眼淚嘩嘩的,先記錄一下吧。
第一步讓我暈的就是目錄結構,看了官方文檔一直說項目根目錄,結果百度了一下根目錄,一哥們說是src的上級目錄就是app所在的目錄,感覺也是,結果就做下去了,結果就悲催了,折騰了一下午也沒搞定,然後看了江清清的文章,這把知道目錄了,要在項目的同級目錄裏面,也就是app的上級目錄,src的上上級目錄做。這把做下去歷經不知道多少劫難,成功啦,開心!但是。。。爲毛項目名稱一定要是Android啊,這不坑嗎,難道我以後的項目名字都有叫這個啊,這顯然不行,結果我新建了一個項目,名字隨便起的叫ReactNativeOne,結果就報錯了:Android project not found. Maybe run react-native android first?,這時候看了網上一哥們的解答,試了一下,確實可以,就是先用android stdio先運行app,首先我們的app是一個原生的,as啓動自然沒問題。點擊綠色小三角運行app啓動了,然後運行命令react-native start或者npm start,就可以了,然後跳轉RN頁面,設置ip和端口,重新加載一下就ok了。下面是demo的主要實現不步驟,和網上有很多雷同,就不一一給出鏈接了。
1、E:盤下新建目錄ReactNativeProject目錄,as新建工程ReactNativeOne,一個原生android就出來了,目錄如下:
然後cmd進入到ReactNativeProject目錄下面,執行npm init命令,提示輸入name的時候就輸入reactnativeproject,要小寫。其他的一路enter鍵下去就好了。然後再執行命令npm install --save react react-native,等待一會執行成功,目錄結構如下:
npm install --save react react-native運行完我這提示[email protected] requires a peer of [email protected] but none was installed,打開package.json看看,裏面react版本不是16這個,這時候是react-native和react版本不一致問題,一定要解決,否則packager服務起不來,解決辦法是輸入命令npm i -S [email protected]。再看看package裏面react版本就變了。接下來修改package.json文件,package.json裏面scripts替換"start": "node node_modules/react-native/local-cli/cli.js start"。然後上圖目錄裏面加入index.android.js文件,代碼如下:
import React, { Component } from 'react';
import { AppRegistry,StyleSheet, Text, View } from 'react-native';
class Blink extends Component {
constructor(props) {
super(props);
this.state = { showText: true };
// 每50毫秒對showText狀態做一次取反操作
setInterval(() => {
this.setState({ showText: !this.state.showText });
}, 50);
}
render() {
// 根據當前showText的值決定是否顯示text內容
let display = this.state.showText ? this.props.text : ' ';
return (
<Text style={styles.bigblue,styles.red}>{display}</Text>
);
}
}
class BlinkApp extends Component {
render() {
return (
<View>
<Blink text='I love to blink' />
<Blink text='Yes blinking is so great' />
<Blink text='Why did they ever take this out of HTML' />
<Blink text='Look at me look at me look at me' />
</View>
);
}
}
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
AppRegistry.registerComponent('ReactNativeProject', () => BlinkApp);
目錄如下:
接下來修改as工程,打開MainActivity頁面,加入一個按鈕,然後新建一個ReactNativeActivity頁面,按鈕跳轉到該頁面。然後再建立工程,app裏面的build.gradle裏面導入compile "com.facebook.react:react-native:+" ,這個要在npm install --save react react-native命令後執行,如果順序反了就在as裏面無法正確導入react-native包,可能導入的是老版本的而不是你本地安裝的,這個地方要注意一下,否則as就報錯了。
gradle裏面最低sdk版本要改爲至少16,即minSdkVersion16,否則報錯。
然後還是在app裏面的build.gradle裏面的build.gradle裏面android{}加入如下代碼:
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
我這最終代碼如下:
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.example.user.reactnativeone"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
}
不然會報如下錯誤:Conflict with dependency 'com.google.code.findbugs:jsr305'.
Resolved versions for app (3.0.0) and test app (2.0.1) differ.
See http://g.co/androidstudio/app-test-app-conflict for details.
接下來AndroidManifest裏面加入權限:
<uses-permissionandroid:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />和DevSettingsActivity聲明,不然到時候點擊Dev Setting就崩啦
<activityandroid:name="com.facebook.react.devsupport.DevSettingsActivity"/>
最後就是修改DevSettingsActivity裏面的代碼了:
public class ReactNativeActivity extends Activity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
public static int OVERLAY_PERMISSION_REQ_CODE = 1234;
@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();
mReactRootView.startReactApplication(mReactInstanceManager, "ReactNativeProject", null);
setContentView(mReactRootView);
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...
}
}
}
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this,this);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
}
好了,這下基本上工作完事,準備跑起來吧。
但是...記得開篇說的注意事項了嗎,先跑as,模擬器運行處app後,然後在命令行下執行react-native start或者npm start命令。
模擬器跑出來app後進入android原生頁面
點擊按鈕進入react-native頁面,ctrl+M調出菜單,點擊Dev Setting設置ip和端口
最後as重新運行app就好了,這之前可能要重新運行nmp start命令,最終RN頁面如下,是一個帶有閃啊閃啊字的頁面,截圖個靜態的頁面:
結束啦。。。並沒有。。。
參考網上一個哥們文章,說的有道理,我們爲啥要把js和json文件放在工程外面呢,這不合理啊,他們屬於工程內部文件啊,那咱把他們移到工程裏面,目錄如下:
然後開啓packager服務的命令要修改成如下樣子了:
其他的都一樣了,至於node_modules文件夾爲啥不一起移過去,那樣據說會很卡...