React Native和Android整合詳解
前言
按照React Native的迭代速度,使用官網的文件,已經不能很順利的實現React Native和Android的有效整合。React Native最新版本 已經是0.39。為了更好的講解React Native和Android的整合我這裡列出我本地的環境:
- Android Stuidio 2.2穩定版
- 64位win7作業系統
- 紅米note3雙網通普配版
- React Native 0.39
具體實踐
建立專案
這一步按照AS新建專案嚮導一步步完成即可,完成後。
- 在app module下的build.gradle檔案的dependencies中新增React Native 依賴:compile
“com.facebook.react:react-native:+” - 修改Manifest檔案:
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
注:compile SDK 和target SDK都是24(網上有文章講,使用的appcompat-v7支援包版本必須是23.0.1,compile SDK和target SDK也必須是23 。不過最新的也支援的)
compile 'com.android.support:appcompat-v7:24.2.1'
如果你出現下面的錯誤,可以降低版本到23.
Caused by: java.lang.IllegalAccessError: Method 'void
android.support.v4.net.ConnectivityManagerCompat.<init>()'
is inaccessible to class
'com.facebook.react.modules.netinfo.NetInfoModule'
(declaration of 'com.facebook.react.modules.netinfo.NetInfoModule'
appears in /data/app/com.milter.www.awesomeproject2-2/base.apk)
將Android專案變成React Native專案
其實整合的過程就是將一個原生的Android專案,轉換為滿足React Native結構格式的專案React Native專案結構。
- 建立並修改package.json檔案
進入Android專案的根目錄,使用命令:
npm init
這個命令會引導你在ReactNativeWithNativeApp目錄下建立一個package.json檔案。如圖所示:
接下來我們對package.json檔案進行修改,修改部分如下:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
修改為:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
,"start": "node node_modules/react-native/local-cli/cli.js start"
}
修改後,我們在專案根目錄的命令列視窗中輸入命令:
npm start
就相當於執行如下命令:
node node_modules/react-native/local-cli/cli.js start
隨著package.json檔案的建立,我們的專案也變成了一個Node專案。
引入React Native 模組
在專案根目錄下輸入如下的命令:
npm install --save react react-native
執行完後我們發現專案多了一個node_modules檔案,react native依賴的庫都會在這裡看到。
- 建立.flowconfig檔案
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
這一命令的作用是將命令中url指向的.flowconfig檔案下載到專案的根目錄。在上面的圖packagejson中可以看到這個下載後的檔案。關於curl的講解請看curl詳解
注:如果你不想使用curl命令,你可以可以https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig拷貝里的內容存為.flowconfig檔案。
建立RN程式
在根目錄下建立index.android.js檔案,如果你是直接用react-native init demo(專案名),也可以拷貝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);
將React Native程式整合進Android專案
在專案根目錄的build.gradle中(注意:不是app模組中的build.gradle檔案)新增依賴。
allprojects {
repositories {
jcenter()
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$projectDir/../node_modules/react-native/android"
}
}
修改MainActivity內容,完整程式碼如下:
public class MainActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
private LifecycleState mLifecycleState
= LifecycleState.BEFORE_RESUME;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* 下面的版本判斷程式碼官方文件中沒有,
如果不新增,在6.0以上的Android版本中會報錯 */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent serviceIntent = new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(serviceIntent);
}
}
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(mLifecycleState)
.build();
//下面程式碼中的"HelloWorld"來自index.android.js檔案中最後一行程式碼
mReactRootView.startReactApplication(mReactInstanceManager,
"HelloWorld", null);
setContentView(mReactRootView);
}
@Override
protected void onPause() {
super.onPause();
mLifecycleState = LifecycleState.BEFORE_RESUME;
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause();
}
}
@Override
protected void onResume() {
super.onResume();
mLifecycleState = LifecycleState.RESUMED;
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mReactRootView.unmountReactApplication();
mReactRootView = null;
if (mReactInstanceManager != null) {
mReactInstanceManager.destroy();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (mReactInstanceManager != null) {
mReactInstanceManager.onActivityResult(this,requestCode,
resultCode, data);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
}
else {
super.onBackPressed();
}
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
執行配置
使用npm start命令執行專案,然後使用
react-native run-android
如果報錯,請往下看。如果出現如下錯誤:
java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so
這個錯誤的原因是React Native提供的libreactnativejni.so檔案是32位,而我們的專案中用了一些不相容的64位so檔案,二者混在一起產生的。解決的辦法就是禁止使用那些64位的so檔案。
第一,在專案根目錄下的gradle.properties檔案最後加上這樣一句:
android.useDeprecatedNdk=true
第二、在app module下的build.gradle檔案中新增如下內容:
android {
...
defaultConfig {
...
ndk{
abiFilters "armeabi-v7a", "x86"
}
...
}
...
}
第三、找出不相容的64位so檔案並禁止它們
在目錄…\ReactNativeWithNativeApp\app\build\outputs\apk下找到app-debug.apk,並把它解壓,檢視一下,解壓後的檔案的lib目錄下有沒有這個目錄:
arm64-v8a
如果有這個目錄,看看裡面的so檔案,都是我們要禁止的,禁止的方法如下:假設裡面有一個 1.so檔案,我們要在app module下的build.gradle檔案中做如下修改:
android {
...
defaultConfig {
...
ndk{
abiFilters "armeabi-v7a", "x86"
}
packagingOptions {
exclude "lib/arm64-v8a/1.so"
}
...
}
...
}
好了,整合就說完了,請大家持續關注哦,現在出專案實戰了。