From e8f648e17c6ece3dc30e00a90d25a5f24cb763c2 Mon Sep 17 00:00:00 2001 From: Ali Najafizadeh Date: Tue, 27 Sep 2016 23:48:39 -0400 Subject: [PATCH] got basic to work --- examples/rpc/index.ios.js | 45 ++++++++++++++----- .../rpc/ios/rpc.xcodeproj/project.pbxproj | 12 +++-- ios/RCTWebViewBridge.h | 1 + ios/RCTWebViewBridge.m | 14 +++++- ios/RCTWebViewBridgeManager.m | 1 + lib/WebViewBridge/index.ios.js | 4 +- lib/WebViewBridgeRPC/index.js | 23 ++++++---- lib/core/rpc.js | 3 +- lib/index.js | 9 +--- 9 files changed, 77 insertions(+), 35 deletions(-) diff --git a/examples/rpc/index.ios.js b/examples/rpc/index.ios.js index 8576a28..ba75ff7 100644 --- a/examples/rpc/index.ios.js +++ b/examples/rpc/index.ios.js @@ -12,38 +12,59 @@ import { View } from 'react-native'; -import WebView from 'react-native-webview-bridge' +import { WebViewBridge, WebViewBridgeRPC } from 'react-native-webview-bridge' const injectScript = ` (function () { if (window.WebViewBridge) { - WebViewBridge.addMessageListener(function (payload) { - alert(payload.message) - }); + WebViewBridge.rpc.invoke('onNativeCall', null, function (resp) { + alert(resp) + }) - WebViewBridge.send({ message: 'This is working' }); + WebViewBridge.rpc.register('onWebViewCall', function (args, resolve) { + resolve('this is web call') + }) + + // WebViewBridge.addMessageListener(function (payload) { + // alert(payload.message) + // }); + // + // WebViewBridge.send({ message: 'This is working' }); } }()); `; class rpc extends Component { - onMessage = (payload) => { - if (this.bridgeRef) { - console.log(payload.message) - this.bridgeRef.sendToBridge({ message: 'This is working too' }) - } + constructor(props, context) { + super(props, context) + + this.bridgeRef = null + } + + componentDidMount() { + this.bridgeRef.register('onNativeCall', this.onNativeCall) + } + + onNativeCall = (args, resolve) => { + resolve('native call') + + setTimeout(() => { + console.log('invoking....') + this.bridgeRef.invoke('onWebViewCall', null, function (resp) { + console.log(resp) + }) + }, 3000) } render() { return ( - this.bridgeRef = ref} source={{uri: 'https://github.com/facebook/react-native'}} style={{marginTop: 20}} javaScriptEnabled={true} injectedJavaScript={injectScript} - onBridgeMessage={this.onMessage} /> ); } diff --git a/examples/rpc/ios/rpc.xcodeproj/project.pbxproj b/examples/rpc/ios/rpc.xcodeproj/project.pbxproj index 2020b96..7a3a338 100644 --- a/examples/rpc/ios/rpc.xcodeproj/project.pbxproj +++ b/examples/rpc/ios/rpc.xcodeproj/project.pbxproj @@ -22,8 +22,9 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 41538B161D9B4E41002A1C00 /* WebViewBridge.js in Resources */ = {isa = PBXBuildFile; fileRef = 41538B141D9B4E41002A1C00 /* WebViewBridge.js */; }; + 41538B171D9B4E41002A1C00 /* WebViewBridgeRPC.js in Resources */ = {isa = PBXBuildFile; fileRef = 41538B151D9B4E41002A1C00 /* WebViewBridgeRPC.js */; }; 41B4735E1D98EAD4002C71D7 /* libReact-Native-Webview-Bridge.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 418B30531D98E6EC00716CA2 /* libReact-Native-Webview-Bridge.a */; }; - 41B4736D1D98F18D002C71D7 /* bootstrap.js in Resources */ = {isa = PBXBuildFile; fileRef = 41B4736C1D98F18D002C71D7 /* bootstrap.js */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; /* End PBXBuildFile section */ @@ -134,7 +135,8 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = rpc/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = rpc/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 41B4736C1D98F18D002C71D7 /* bootstrap.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = bootstrap.js; path = "../node_modules/react-native-webview-bridge/scripts/bootstrap.js"; sourceTree = ""; }; + 41538B141D9B4E41002A1C00 /* WebViewBridge.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WebViewBridge.js; path = "../node_modules/react-native-webview-bridge/scripts/WebViewBridge.js"; sourceTree = ""; }; + 41538B151D9B4E41002A1C00 /* WebViewBridgeRPC.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WebViewBridgeRPC.js; path = "../node_modules/react-native-webview-bridge/scripts/WebViewBridgeRPC.js"; sourceTree = ""; }; 41BC38FF1D986EDA00018E84 /* React-Native-Webview-Bridge.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "React-Native-Webview-Bridge.xcodeproj"; path = "../node_modules/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; @@ -246,7 +248,8 @@ 13B07FAE1A68108700A75B9A /* rpc */ = { isa = PBXGroup; children = ( - 41B4736C1D98F18D002C71D7 /* bootstrap.js */, + 41538B141D9B4E41002A1C00 /* WebViewBridge.js */, + 41538B151D9B4E41002A1C00 /* WebViewBridgeRPC.js */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.m */, @@ -540,7 +543,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 41B4736D1D98F18D002C71D7 /* bootstrap.js in Resources */, + 41538B161D9B4E41002A1C00 /* WebViewBridge.js in Resources */, + 41538B171D9B4E41002A1C00 /* WebViewBridgeRPC.js in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, ); diff --git a/ios/RCTWebViewBridge.h b/ios/RCTWebViewBridge.h index caba7be..76af1c4 100644 --- a/ios/RCTWebViewBridge.h +++ b/ios/RCTWebViewBridge.h @@ -36,6 +36,7 @@ shouldStartLoadForRequest:(NSMutableDictionary *)request @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets; @property (nonatomic, copy) NSString *injectedJavaScript; @property (nonatomic, assign) BOOL scalesPageToFit; +@property (nonatomic, assign) BOOL rpc; - (void)goForward; - (void)goBack; diff --git a/ios/RCTWebViewBridge.m b/ios/RCTWebViewBridge.m index 09948fc..0555cb2 100644 --- a/ios/RCTWebViewBridge.m +++ b/ios/RCTWebViewBridge.m @@ -267,6 +267,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) { //injecting WebViewBridge bootstrap [webView stringByEvaluatingJavaScriptFromString:[self webViewBridgeBootrstrap]]; + + //injecting WebViewBridgeRPC bootstrap + if (self.rpc) { + [webView stringByEvaluatingJavaScriptFromString:[self webViewBridgeRPCBootstrap]]; + } if (_injectedJavaScript != nil) { NSString *jsEvaluationValue = [webView stringByEvaluatingJavaScriptFromString:_injectedJavaScript]; @@ -307,7 +312,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - (NSString *)webViewBridgeBootrstrap { - NSString *path = [[NSBundle mainBundle] pathForResource:@"bootstrap" ofType:@"js"]; + NSString *path = [[NSBundle mainBundle] pathForResource:@"WebViewBridge" ofType:@"js"]; + NSString* content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]; + return content; +} + +- (NSString *)webViewBridgeRPCBootstrap +{ + NSString *path = [[NSBundle mainBundle] pathForResource:@"WebViewBridgeRPC" ofType:@"js"]; NSString* content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]; return content; } diff --git a/ios/RCTWebViewBridgeManager.m b/ios/RCTWebViewBridgeManager.m index c09a008..57bffc1 100644 --- a/ios/RCTWebViewBridgeManager.m +++ b/ios/RCTWebViewBridgeManager.m @@ -49,6 +49,7 @@ RCT_EXPORT_VIEW_PROPERTY(onBridgeMessage, RCTDirectEventBlock) RCT_REMAP_VIEW_PROPERTY(allowsInlineMediaPlayback, _webView.allowsInlineMediaPlayback, BOOL) RCT_REMAP_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, _webView.mediaPlaybackRequiresUserAction, BOOL) RCT_REMAP_VIEW_PROPERTY(dataDetectorTypes, _webView.dataDetectorTypes, UIDataDetectorTypes) +RCT_EXPORT_VIEW_PROPERTY(rpc, BOOL) RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag) { diff --git a/lib/WebViewBridge/index.ios.js b/lib/WebViewBridge/index.ios.js index e388e9c..5a0fe2c 100644 --- a/lib/WebViewBridge/index.ios.js +++ b/lib/WebViewBridge/index.ios.js @@ -333,7 +333,8 @@ class WebView extends React.Component { */ mediaPlaybackRequiresUserAction: PropTypes.bool, - onBridgeMessage: PropTypes.func + onBridgeMessage: PropTypes.func, + rpc: PropTypes.bool }; state = { @@ -413,6 +414,7 @@ class WebView extends React.Component { mediaPlaybackRequiresUserAction={this.props.mediaPlaybackRequiresUserAction} dataDetectorTypes={this.props.dataDetectorTypes} onBridgeMessage={this.onBridgeMessage} + rpc={!!this.props.rpc} />; return ( diff --git a/lib/WebViewBridgeRPC/index.js b/lib/WebViewBridgeRPC/index.js index 11d277d..f4a0dcd 100644 --- a/lib/WebViewBridgeRPC/index.js +++ b/lib/WebViewBridgeRPC/index.js @@ -12,25 +12,29 @@ import rpc from '../core/rpc' export default class WebViewBridgeRPC extends Component { constructor(props, context) { + super(props, context) this.bridgeRef = null this.rpc = null } + sender = (payload) => { + this.bridgeRef.sendToBridge(payload) + } + getWebViewRef = () => { return this.bridgeRef } register = (name, fn) => { - this.rpc.register(name, fn) + this.rpc.register(this.sender, name, fn) } - invoke = (name, args) => { - //for now we don't care about reject. - //TODO: reject can be implemeneted by introducing timeout and failer in result. - //for now we don't support it. - return new Promise((resolve, reject) => { - this.rpc.invoke(name, args, resolve) - }) + invoke = (name, args, resolve) => { + this.rpc.invoke(this.sender, name, args, resolve) + } + + onMessage = (payload) => { + this.rpc.onMessage(payload) } componentDidMount() { @@ -46,7 +50,8 @@ export default class WebViewBridgeRPC extends Component { this.bridgeRef = ref} - injectRPC={true}/> + rpc={true} + onBridgeMessage={this.onMessage}/> ) } } diff --git a/lib/core/rpc.js b/lib/core/rpc.js index a922f87..b25e6bc 100644 --- a/lib/core/rpc.js +++ b/lib/core/rpc.js @@ -76,7 +76,8 @@ function rpc() { return { register: register, - invoke: invoke + invoke: invoke, + onMessage: onMessage } } diff --git a/lib/index.js b/lib/index.js index 92f411d..e67da4d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,10 +5,5 @@ * @providesModule WebViewBridgeRPC * @noflow */ -import WebViewBridge from './WebViewBridge' -import WebViewBridgeRPC from './WebViewBridgeRPC' - -export default { - WebViewBridge, - WebViewBridgeRPC -} +export { default as WebViewBridge } from './WebViewBridge' +export { default as WebViewBridgeRPC } from './WebViewBridgeRPC'