从RN向Android端发送消息
- 创建一个类继承ReactContextBaseJavaModule
public class RNTest extends ReactContextBaseJavaModule {
private Context reactContext;
public RNTest(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext= reactContext;
}
@Override
public String getName() {
return "RNTest"; // 不一定是类名,要和NativeModules.RNTest对应
}
// 自定义一个方法 处理消息
// 通过注解 表示可以被RN侧调用
@ReactMethod
public void handleMsg(String msg){
Toast.makeText(reactContext,msg,Toast.LENGTH_SHORT).show();
// 自己创建一个普通的Activity
Intent intent = new Intent(reactContext,MyActivity.class);
// 一定要加 否则报错
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
reactContext.startActivity(intent);
}
}
- 创建一个包管理器继承ReactPackage
public class TestReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new RNTest(reactContext)); // 添加上面定义的类
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
- 在默认生成的MainApplication的getPackage方法中添加代码
public class MainApplication 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(),new TestReactPackage()
);
}
... 下略
- 在App.js中添加一个方法,关联到某个button上调用即可
sendMsgToAndroid() {
var { NativeModules } = require('react-native');
let test = NativeModules.RNTest;
test.handleMsg('this is a rn msg');
}
- 正常应该就可以运行了,直接从AS运行可能会导致服务关闭,建议从rn端运行,或者先AS再rn。
Android发送消息到RN端
- 从手机读取联系人,先添加权限
<!--读取联系人相关权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
- RNTest修改如下
import static android.app.Activity.RESULT_OK;
/**
* Created by shakespace on 2018/3/15.
*/
public class RNTest extends ReactContextBaseJavaModule {
private static final String TAG = "RNTest";
private ReactContext reactContext;
// 创建一个mActivityEventListener
private ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
@SuppressWarnings("deprecation")
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
super.onActivityResult(activity, requestCode, resultCode, data);
if (requestCode == 1 && resultCode == RESULT_OK && data != null) {
Uri uri = data.getData(); // 获取地址
// CursorLoader loader = new CursorLoader(activity, uri, null, null, null, null);
// Cursor cursor = loader.loadInBackground();
Log.e(TAG, uri.toString());
Cursor cursor = activity.managedQuery(uri, null, null, null, null);
cursor.moveToFirst(); //
String msg = getInfo(cursor);
sendMsgToRN(msg);
}
}
};
public RNTest(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
reactContext.addActivityEventListener(mActivityEventListener);
}
// 发送消息到RN端
private void sendMsgToRN(String msg) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("AndroidToRNMessage", msg);
}
private String getInfo(Cursor cursor) {
String name = "";
String phone = "";
//取得联系人姓名
int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
name = cursor.getString(nameFieldColumnIndex);
// 联系人和电话数据库不在一起 获取字段 拼接查询条件
int id = cursor.getColumnIndex(ContactsContract.Contacts._ID);
String contactID = cursor.getString(id);
String queryString = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactID;
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Cursor phoneCursor = reactContext.getContentResolver().query(uri, null, queryString, null, null);
String phoneNumber = ContactsContract.CommonDataKinds.Phone.NUMBER;
if (phoneCursor != null && phoneCursor.moveToFirst()) {
phone = phoneCursor.getString(phoneCursor.getColumnIndex(phoneNumber));
}
phoneCursor.close();
// cursor.close();// 使用managedQuery 不用手动关
String result = "{\"msgType\": \"pickContactResult\",\"name\":\"" + name + "\", \"number\":\"" + phone + "\"}";
Log.e(TAG, result);
return result;
}
@Override
public String getName() {
return "RNTest"; // 要和NativeModules.RNTest对应
}
// 自定义一个方法 处理消息
// 通过注解 表示可以被RN侧调用
@ReactMethod
public void handleMsg(String msg) {
Toast.makeText(reactContext, msg, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(reactContext, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
reactContext.startActivity(intent);
}
@ReactMethod
public void pickContact() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
reactContext.startActivityForResult(intent, 1, null);
}
}
主要步骤
添加监听 reactContext.addActivityEventListener
RN调用的方法中使用startActivityForResult调起原生页面
在onActivityResult处理回传的数据
使用reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("AndroidToRNMessage", msg);向RN端发送消息
- RN端处理
import RCTDeviceEventEmitter组件,添加方法
getContactFromAndroid(){
// 监听安卓消息
DeviceEventEmitter.addListener('AndroidToRNMessage',this.handleAndroidMsg.bind(this));
var { NativeModules } = require('react-native');
let test = NativeModules.RNTest;
test.pickContact();
}
handleAndroidMsg(msg){
console.log(msg);
let aObj = JSON.parse(msg);
this.updateName(aObj.name);
this.updateNum(aObj.number);
// this.setState({name:aObj.name,num:aObj.number})
DeviceEventEmitter.removeAllListeners();
}
完整案例查看:Demo
案例实现了从安卓端读取联系人并返回
在魅族手机上可能无法申请联系人权限,没有做更多适配,需要安装后自己手动在设置里打开权限。否则报错。
书中建议,如果是原生需要主动通信RN端,使用消息回调方式,如果是RN想原生请求操作并希望原生返回一个结果时,建议使用Promise方式。
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("AndroidToRNMessage", msg);属于消息机制
下例属于回调函数方式,因为桥接是异步的,所以不会立即执行
@ReactMethod
public void handleMsg(String msg, Callback callback) {
...
callback.invoke(msg); // 回调函数方式
...
}
- Promise方式
- 创建一个promise成员变量,在ReactMethod中初始化
Promise mPromise;
@ReactMethod
public void pickContact(String msg,Promise promise) {
this.mPromise = promise; // 使用Promise方式时添加,在这里初始化
...
}
- 返回结果时使用resolve函数
mPromise.resolve(msg);
发生异常时使用reject相关函数
- RN不用注册函数,调用方式如下
getContactFromAndroid(){
// 监听安卓消息
// DeviceEventEmitter.addListener('AndroidToRNMessage',this.handleAndroidMsg.bind(this));
var { NativeModules } = require('react-native');
let test = NativeModules.RNTest;
// test.pickContact('testMsg');
// 使用promise方式时,上面不用再注册回调
test.pickContact('testMsg').then(
// 表示处理结果的回调
(result)=>{
this.handleAndroidMsg(result);
}
).catch(
// 异常的处理
(error)=>{
console.log(error+"msg = "+ error.message + "code = "+ error.code);
}
);
}
-
监听生命周期
通过implements LifecycleEventListener可以监听原生的生命周期 -
跨语言常量
@Nullable
@Override
public Map<String, Object> getConstants() {
Map<String,Object> cons = new HashMap<>();
cons.put("consName","tom");
return cons;
}
在RN侧使用 模块名.consName 来访问被导出的常量
- 类型对应
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array
网友评论