Fork me on GitHub

ReactNative之封装iOS原生组件以及通信机制

ReactNative的中文网中已经给出了原生UI组件的使用指南,我们知道了如何封装原生UI组件供ReactNative使用,如何设置属性、事件回调和样式等,但是当你成功按照官网集成成功后我们会发现,官方给出的例子中,没有涉及到ReactNative如何调用原生UI的公共方法,因为难免一些原生UI会有自己的一些公共方法。下面我们主要从以下几个方面介绍ReactNative如何与iOS组件的调用和通信:

  • ReactNative调用iOS原生UI组件
  • ReactNative调用iOS原生UI组件的方法


ReactNative调用iOS原生UI组件的方法

  • Native-iOS

创建一个继承自UIView的“LJNCustomView”供ReactNative使用

1
2
3
4
5
6
7
8
9
10
11
12
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface LJNCustomView : UIView

// 测试方法
- (void)testNativeFuc;

@end

NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
11
#import "LJNCustomView.h"

@implementation LJNCustomView

// 测试方法
- (void)testNativeFuc
{
NSLog(@"%s",__FUNCTION__);
}

@end

再创建一个继承自RCTViewManager的文件,命名为“LJNCustomViewManager”

1
2
3
4
5
6
7
8
9
#import <React/RCTViewManager.h>

NS_ASSUME_NONNULL_BEGIN

@interface LJNCustomViewManager : RCTViewManager

@end

NS_ASSUME_NONNULL_END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#import "LJNCustomViewManager.h"
#import "LJNCustomView.h"
#import <React/RCTUIManager.h>

@interface LJNCustomViewManager()
@end

@implementation LJNCustomViewManager

// 导出原生组件
RCT_EXPORT_MODULE(LJNCustomViewComponent);

// 导出方法
RCT_EXPORT_METHOD(testNativeFuc:(nonnull NSNumber *)reactTag) {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
UIView *view = viewRegistry[reactTag];
if(![view isKindOfClass:[LJNCustomView class]]){
RCTLogError(@"Invalid view returned from registry, expecting LJNCustomView, got: %@", view);
}else{
dispatch_async(dispatch_get_main_queue(), ^{
LJNCustomView *customView = (LJNCustomView *)viewRegistry[reactTag];
// 调用原生方法
[customView testNativeFuc];
});
}
}];
}

// 重写view方法:- (UIView *)view;
- (UIView *)view
{
LJNCustomView *customView = [[LJNCustomView alloc] initWithFrame:CGRectZero];
return customView;
}

@end
  • JS

创建一个js文件,命名为“LJNCustomViewIOS”,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React from 'react'
import {
requireNativeComponent,
UIManager,
findNodeHandle
} from 'react-native';

// 导入原生iOS组件
/**
* 注意:requireNativeComponent(第一个参数,第二个参数)
* 参数分析:
* 第一个参数:如果Native的RCT_EXPORT_MODUEL(js_name);如果js_name为空,默认为类名,但是注意了:这里有坑点,如果类名为'LJNButtonManager',
* 那么我们在requireNativeComponent()中第一个参数要去掉Manager,应该为LJNButton,否则提示找不到
* 第二个参数:和ReactNative导出的组件名一致,这是因为ReactNative的底层框架会检查原生属性和包装类的属性是否一致,来减少错误的发生。
*/
const LJNCustomView = requireNativeComponent('LJNCustomViewComponent', LJNCustomViewIOS);

export default class LJNCustomViewIOS extends React.Component {
render() {
return (
<LJNCustomView {...this.props}/>
);
}

testNativeFunc = () => {
UIManager.dispatchViewManagerCommand(
findNodeHandle(this),
UIManager.getViewManagerConfig('LJNCustomViewComponent').Commands.testNativeFuc,
null
);
}
}
注意事项:

调用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
Button
} from 'react-native';
import LJNCustomViewIOS from './js/iOSNativeComponent/LJNCustomViewIOS';


export default class App extends Component{

render() {
return (
<View style={styles.container}>
<View style={styles.module_container}>
<Text>LJNCustomView原生iOS组件,js调用Native方法</Text>
<LJNCustomViewIOS
ref={(ref) => this.customViewRef = ref}
/>
<Button
title='调用原生LJNCustomView的方法'
onPress={() => {
this.customViewRef && this.customViewRef.testNativeFunc();
}}
/>
</View>
</View>
);
}
}