【发布时间】:2017-04-17 07:21:21
【问题描述】:
我在 Ignite 项目中有一个自定义原生视图。我正在尝试建立从Objective-C 到React Native 的通信。从React Native 到iOS 的通信与HTML 注入一起工作,但反之则不行。我尝试过同时使用RCTBubblingEventBlock 和RCTDirectEventBlock,但都不起作用。这是我的全部实现。当然,我已经更改了组件的名称,只留下了基本的实现,以便您了解到目前为止所做的工作:
Objective-C代码:
// CustomViewManager.h
#import "RCTViewManager.h"
@interface CustomViewManager : RCTViewManager
@end
// CustomViewManager.m
#import "CustomViewManager.h"
#import "CustomView.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "UIView+React.h"
@implementation CustomViewManager
RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(htmlInjection, NSString)
RCT_EXPORT_VIEW_PROPERTY(onEventA, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onEventB, RCTDirectEventBlock)
- (UIView *) view {
return [CustomView new];
}
@end
// CustomView.h
#import "RCTView.h"
@interface CustomView : RCTView
@property (nonatomic, assign) NSString *htmlInjection;
@property (nonatomic, copy) RCTDirectEventBlock onEventA;
@property (nonatomic, copy) RCTDirectEventBlock onEventB;
@end
// CustomView.m
#import "CustomView.h"
#import "RCTUtils.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "UIView+React.h"
#import "MyExternalComponent.h"
@interface CustomView () <UIWebViewDelegate>
@property (nonatomic, strong) UIWebView* webView;
@end
- (void) setUpWebView {
if (!_webView) {
[self setWebView: [UIWebView new]];
_webView.delegate = self;
[self addSubview:_webView];
}
}
- (instancetype)init
{
self = [super init];
[self setUpWebView];
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUpWebView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self setUpWebView];
}
return self;
}
- (void) layoutSubviews {
[super layoutSubviews];
CGRect frame = self.frame;
self.webView.frame = frame;
}
#pragma mark - External methods.
- (void) setHtmlInjection:(NSString *)html {
[_webView loadHTMLString:html baseURL:nil];
}
#pragma mark - Non-React component methods.
- (void) fetchData {
[MyExternalComponent getData:^(NSString *dataA, NSError *error){
if(error) {
NSLog(@"Here be errors: %@", error);
_onEventB(@{@"myError": error.localizedDescription});
} else {
_onEventA(@{@"myData": dataA});
}
}]
}
@end
React NativeJavaScript代码:
// MyCustomView.js
import React from 'react';
import { requireNativeComponent } from 'react-native';
class MyCustomView extends React.Component {
constructor(props) {
super(props);
this._onEventA= this._onEventA.bind(this);
this._onEventB= this._onEventB.bind(this);
}
_onEventA(event: Event) {
if (!this.props.onEventA) {
return;
}
this.props.onEventA(event.nativeEvent.myData);
}
_onEventB(event: Event) {
if (!this.props.onEventA) {
return;
}
this.props._onEventB(event.nativeEvent.myError);
}
render() {
return (
<CustomView
{...this.props}
onEventA={this._onEventA}
onEventB={this._onEventB}
/>
);
}
}
MyCustomView.propTypes = {
htmlInjection: React.PropTypes.string,
onEventA: React.PropTypes.func,
onEventB: React.PropTypes.func,
};
var CustomView = requireNativeComponent('CustomView', MyCustomView);
module.exports = MyCustomView;
// CustomWrapperContainer.js
class CustomWrapperContainer extends React.Component {
api: Object;
constructor (props: Object) {
super(props);
this.state = {
htmlInjection: '',
myDataA: 'Some placeholder text'
};
this.api = RestApi.create();
}
render () {
return (
<View style={styles.container}>
<KeyboardAvoidingView behavior='position'>
<Text>{this.state.myDataA}</Text>
<MyCustomView
style={styles.myStyle}
htmlInjection={this.state.htmlInjection}
onEventA={this.handleEventA.bind(this)}
onEventB={this.handleEventB.bind(this)}
/>
</KeyboardAvoidingView>
</View>
)
}
handleEventA = (data) => {
console.log('on Event A', data);
this.setState({myDataA: data})
};
handleEventB = (error) => {
console.log('On Event B', error);
};
}
const mapStateToProps = (state) => {
return {
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CustomWrapperContainer)
我已经从React Native 本身以及其他几个关注example,但到目前为止我还没有运气将事件从iOS 传递到React Native。我也无法从现有文章中找到这方面的重要帮助。
Ignite 使用 react 版本 15.3.2。也许这就是问题所在?或者那里的其他依赖项的版本?我不知道。非常感谢任何帮助或线索。
P.S.:我一直在运行 iOS 9.2 到 10.0 的设备和模拟器上运行它,我没有看到行为有任何变化,所以这不是问题。
【问题讨论】:
-
看到这个我首先想到的是,一定要考虑尝试 RNWebview 桥的 v2。这将很快登陆 RN Master:github.com/alinz/react-native-webview-bridge/tree/v2
-
谢谢。但我不明白这与我遇到的问题有什么关系。我确实有一个 webView,我可以在其中加载 HTML 内容,并且工作正常。只有当我尝试通过回调传回数据时,通信才不起作用。
-
是的,抱歉,我没有发现这段代码有任何问题,所以我希望能提供一些额外的信息。你在我可以访问的仓库中有这个代码吗?
-
啊,恐怕代码有访问限制。但我计划在纯反应本机项目中运行相同的代码,以确认这不是一件容易的事。关于我可以做些什么来调试这个,你有什么其他的理论或建议吗?
-
@GantMan 我已经发布了一个答案并且该方法有效。有cmets吗?
标签: javascript ios objective-c reactjs react-native