1、iOS与RN的互调
相对于Android来说,iOS的两端互调比较简单。先看iOS里 ShowAlert的配置:
// .h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
NS_ASSUME_NONNULL_BEGIN
@interface ShowAlert : RCTEventEmitter<RCTBridgeModule>
@end
NS_ASSUME_NONNULL_END
// .m
#import "ShowAlert.h"
@interface ShowAlert ()
@property (nonatomic, assign) BOOL hasListener;
@end
static NSString * const EVENT_NAME = @"AlertDismiss";
@implementation ShowAlert
// 如果 RCT_EXPORT_MODULE 里有传参, 则按照传参作为模块名, 否则是类名
RCT_EXPORT_MODULE(Alert)
// 原生调用RN
- (NSArray<NSString *> *)supportedEvents {
return @[EVENT_NAME];
}
// 在添加第一个监听函数时触发
- (void)startObserving {
self.hasListener = YES;
}
// 当该模块的最后一个监听者被移除, 或者释放的时候 调用
- (void)stopObserving {
self.hasListener = NO;
}
- (void)sendToRNWithInfo:(NSString *)info {
// 只有在有监听的情况下才发射事件, 防止资源浪费和警告
if (self.hasListener) {
[self sendEventWithName:EVENT_NAME body:info];
}
}
- (void)in_showAlert:(NSString *)title content:(NSString *) content done:(RCTResponseSenderBlock)done {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:content preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self sendToRNWithInfo: @"确定"];
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self sendToRNWithInfo: @"取消"];
}];
[alertVC addAction:defaultAction];
[alertVC addAction:cancelAction];
[[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:alertVC animated:true completion:^{
!done ?: done(@[@"已经展示了"]);
}];
}
// 暴露的方法名
RCT_EXPORT_METHOD(showAlert:(NSString *)title content:(NSString *) content done:(RCTResponseSenderBlock)done) {
[self in_showAlert:title content:content done:done];
}
// 导出的常量, 取值方式: 模块.key
- (NSDictionary *)constantsToExport {
return @{
@"one": @"大写的一",
@"two": @"大写的二"
};
}
// 重写constantsToExport, 必须重写此方法
+ (BOOL)requiresMainQueueSetup {
return true;
}
// 涉及UI的, 表明初始化的线程, 默认为background线程
- (dispatch_queue_t)methodQueue{
return dispatch_get_main_queue();
}
@end
在 RN 里使用:
import { Button } from '@ant-design/react-native'
import { memo, useEffect } from 'react'
import { NativeEventEmitter, NativeModules, View } from 'react-native'
// 获取模块名
const { Alert } = NativeModules
// 原生事件发射器
const alertEmitter = new NativeEventEmitter(Alert)
export default memo(function HomePage() {
useEffect(() => {
// 添加监听, 用于被原生模块调用
const subscription = alertEmitter.addListener('AlertDismiss', info => {
console.log('选择的状态info :>> ', info)
})
return () => {
// 在组件卸载的时候移除监听
subscription.remove()
}
}, [])
return (
<View>
<Button
onPress={() => {
// RN调用原生方法
NativeModules.Alert.showAlert('这是标题', '这是内容', info => {
console.log('error, events :>> ', info)
})
}}>
调用原生模块
</Button>
</View>
)
})
2、Android与RN的互调
a. 编写Module CalendarModule
package com.zxmall;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.HashMap;
import java.util.Map;
public class CalendarModule extends ReactContextBaseJavaModule {
CalendarModule(ReactApplicationContext context) {
super(context);
}
/**
* 模块名称
*/
@NonNull
@Override
public String getName() {
return "CalendarModule";
}
/**
* 导出常量, 取值: 模块名.key 的方式
* @return 暴露给RN的常量
*/
@Nullable
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("one", "大写的一");
constants.put("two", "大写的二");
return constants;
}
/**
* 给RN调用的原生方法
* @param name RN传过来的值
* @param location RN传过来的值
* @param cb 回调给RN
*/
@ReactMethod
public void createCalendarEvent(String name, String location, Callback cb) {
Log.i("calendar", name + location);
cb.invoke("已经完成了打印");
}
}
b. 编写ReactPackage:CalendarPackage
在React native中注册原生模块: 将原生模块添加到一个ReactPackage中,并在React native中注册这个ReactPackage。
在初始化过程中,React Native将遍历所有包,并为每个ReactPackage注册其中的每个原生模块。
package com.zxmall;
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CalendarPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactApplicationContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new CalendarModule(reactApplicationContext));
return modules;
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
return Collections.emptyList();
}
}
c. 在 MainApplication 里注册。
在 RN 里使用:
import { Button } from '@ant-design/react-native'
import { memo } from 'react'
import { NativeModules, View } from 'react-native'
export default memo(function HomePage() {
return (
<View>
<Button
onPress={() => {
NativeModules.CalendarModule.createCalendarEvent(
'这是标题',
'这是地点',
info => {
console.log('安卓原生回调信息 :>> ', info)
}
)
}}>
调用原生模块
</Button>
</View>
)
})
网友评论