假如你的Android原生项目已经写了很多,接下来想使用RN实现一些页面功能,那么该怎么接入呢,其实React Native中文网也有参考,但是我当时按照那篇文章来操作还是有些问题的,感觉不适合初学者来使用,接下来我打算记录一些我自己的接入过程。希望能给一些正在搞这个的朋友作出一些参考
步骤一: 用android studio打开已经创建好的Android工程,然后在Terminal中执行一下命令:
说明,在创建 npm init的时候,需要输入name、version等值,这里可以随意先输入一下,貌似在输入name的值只能用英文的小写字母表示,其实这个无所谓的,可以将其他的React Native工程中的package.json文件Copy过来,将里面的name等值改一下就ok了,还省事。 其他3个命令,依次敲回车执行即可。然后再从React Native工程中Copy一份index.android.js,注意的是,需要将
AppRegistry.registerComponent('RNComponent', () => RNComponent);
第二个参数与package.json的name值保持一致(我这里改的是RNComponent,这个名字可以起别的也行)
步骤二:这样React Native的工作差不多完成了,然后Android端需要创建一个Activity来装载所有的RN页面,这里我创建了MyReactActivity。在创建之前,需要在Android中添加一些依赖,否则用到一些类找不到,下面先开始配置Android工程
step1. 在整个工程的build.gradle中添加 :
allprojects {
repositories {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/node_modules/react-native/android"
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
step2. 在moudle的build.gradle中添加
compile "com.facebook.react:react-native:+"
具体参考我的builde.gradle配置,如下所示
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.reactnative"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
splits {
abi {
reset()
enable true
universalApk true // If true, also generate a universal APK
include "armeabi-v7a", "x86"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.1'
testCompile 'junit:junit:4.12'
compile "com.facebook.react:react-native:+" // From node_modules
}
紧接着上面的步骤二,开始创建MyReactActivity,代码如下;
import com.facebook.react.ReactActivity;
public class MyReactActivity extends ReactActivity{
@Override
protected String getMainComponentName() {
return "RNComponent";
}
}
还有一种创建方式,就是下面这样的,其中这两种创建的MyReactActivity都是可以的,因为ReactActivity也是实现DefaultHardwareBackBtnHandler接口。
public class MyReactActivity extends Activity 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();
mReactRootView.startReactApplication(mReactInstanceManager, "RNComponent", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage()
//将我们创建的包管理器给添加进来
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.reactnative">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
<application
android:name=".MainApplication"
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"
android:configChanges="orientation|screenSize"
android:theme="@style/NoActionBar"
/>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
application>
manifest>
这里需要说明一下,在声明MyReactActivity的时候,需要给它指定一个没有ActionBar的样式,在styles.xml中作修改:
package com.reactnative;
import android.content.Context;
import android.text.TextUtils;
import android.widget.Toast;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.uimanager.IllegalViewOperationException;
public class MyNativeModule extends ReactContextBaseJavaModule {
private Context mContext;
public MyNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
mContext = reactContext;
}
@Override
public String getName() {
//返回的这个名字是必须的,在rn代码中需要这个名字来调用该类的方法。
return "MyNativeModule";
}
//函数不能有返回值,因为被调用的原生代码是异步的,原生代码执行结束之后只能通过回调函数或者发送信息给rn那边。
@ReactMethod
public void rnCallNative(String msg) {
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
/**
* 创建给js调用的方法 将网络请求的结果以回调的方式传递给js
*
* @param url
* @param callback
*/
@ReactMethod
public void getResult(String url, final Callback callback) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 模拟网络请求数据的操作
String result = "我是请求结果";
callback.invoke(true, result);
} catch (Exception e) {
}
}
}).start();
}
@ReactMethod
public void tryCallBack(String name, String psw, Callback errorCallback, Callback successCallback) {
try {
if (TextUtils.isEmpty(name) && TextUtils.isEmpty(psw)) {
// 失败时回调
errorCallback.invoke("user or psw is empty");
}
// 成功时回调
successCallback.invoke("add user success");
} catch (IllegalViewOperationException e) {
// 失败时回调
errorCallback.invoke(e.getMessage());
}
}
/**
* 回调给android端的数据
*
* @param callback
*/
@ReactMethod
public void renderAndroidData(Callback callback) {
callback.invoke("android data");
}
}
说明,这里第一个需要注意的地方是getName()方法,返回的这个别名,将来在RN的js中需要用到这个别名来调原生的方法。第二个地方,凡是需要RN调用的方法,都需要加
@ReactMethod
注解。第三个地方,原生提供的方法的返回值类型都是void类型,比较简单的如rnCallNative(String msg)
, RN那边调用,就是吐司一下。如果需要返回结果就需要回调,如renderAndroidData(Callback callback)
public class MyReactPackage implements ReactPackage {
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
//将我们创建的类添加进原生模块列表中
modules.add(new MyNativeModule(reactContext));
return modules;
}
@Override
public List> createJSModules() {
//返回值需要修改
return Collections.emptyList();
}
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
//返回值需要修改
return Collections.emptyList();
}
}
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage(),
//将我们创建的包管理器给添加进来
new MyReactPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
这样的话,原生模块算是写好了,接下来RN来调用Native方法,将index.android.js中可以这样调用:
首先 import { NativeModules} from ‘react-native’;
调用原生方法可以这么去写NativeModules.MyNativeModule.rnCallNative('调用原生方法的Demo');
export default class RNComponent extends Component {
// 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
title: '',
};
}
render() {
tryCall = () => {
var rnToastAndroid = NativeModules.MyNativeModule;
rnToastAndroid.tryCallBack("luo", "131", (errorCallback) => {
alert(errorCallback)
},
(successCallback) => {
alert(successCallback);
});
};
androidback = () => {
var ANdroidNative = NativeModules.MyNativeModule;
ANdroidNative.renderAndroidData((Callback) => {
alert(Callback);
});
};
return (
this .call_button.bind(this)}
>
React Native 调用原生方法!
androidback()}
>
获得android回调的数据
{NativeModules.MyNativeModule.rnCallNative(this.state.title)}
tryCall()}>
trycallAndroid
);
}
call_button() {
NativeModules.MyNativeModule.rnCallNative('调用原生方法的Demo');
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('RNComponent', () => RNComponent);