diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index c9db749a8b944b..026b8a31500dc8 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -128,6 +128,21 @@ var WebView = React.createClass({ */ domStorageEnabled: PropTypes.bool, + /** + * A callback that will be executed once the webview + * sends a message to RN. + * @platform android + */ + onMessage: PropTypes.func, + + /** + * A protocol that the webview can use to communicate with RN. + * When the WebView triggers requests to myProtocol://something + * the 'onMessage' callback passed to the webview will be called. + * @platform android + */ + messageProtocol: PropTypes.string, + /** * Sets the JS to be injected when the webpage loads. */ @@ -226,6 +241,8 @@ var WebView = React.createClass({ contentInset={this.props.contentInset} automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets} onLoadingStart={this.onLoadingStart} + onMessage={this.props.onMessage} + messageProtocol={this.props.messageProtocol} onLoadingFinish={this.onLoadingFinish} onLoadingError={this.onLoadingError} testID={this.props.testID} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java index 586b071d545975..b431e616f363cc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java @@ -21,7 +21,10 @@ import android.webkit.WebView; import android.webkit.WebViewClient; import android.webkit.WebChromeClient; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import com.facebook.react.views.webview.events.MessageEvent; import com.facebook.react.views.webview.events.TopLoadingErrorEvent; import com.facebook.react.views.webview.events.TopLoadingFinishEvent; import com.facebook.react.views.webview.events.TopLoadingStartEvent; @@ -87,6 +90,21 @@ private static class ReactWebViewClient extends WebViewClient { private boolean mLastLoadFailed = false; + @Override + public WebResourceResponse shouldInterceptRequest (final WebView webView, WebResourceRequest request) { + ReactWebView reactWebView = (ReactWebView) webView; + + if (reactWebView.getMessageProtocol().equals(request.getUrl().getScheme())) { + WritableMap eventData = Arguments.createMap(); + eventData.putString("url", request.getUrl().toString()); + eventData.putString("method", request.getMethod().toString()); + + dispatchEvent(webView, new MessageEvent(webView.getId(), SystemClock.nanoTime(), eventData)); + } + + return super.shouldInterceptRequest(webView, request); + } + @Override public void onPageFinished(WebView webView, String url) { super.onPageFinished(webView, url); @@ -181,6 +199,7 @@ private WritableMap createWebViewEvent(WebView webView, String url) { */ private static class ReactWebView extends WebView implements LifecycleEventListener { private @Nullable String injectedJS; + private @Nullable String messageProtocol; /** * WebView must be created with an context of the current activity @@ -212,6 +231,14 @@ public void setInjectedJavaScript(@Nullable String js) { injectedJS = js; } + public String getMessageProtocol() { + return messageProtocol; + } + + public void setMessageProtocol(@Nullable String mp) { + messageProtocol = mp; + } + public void callInjectedJavaScript() { if (getSettings().getJavaScriptEnabled() && injectedJS != null && @@ -271,7 +298,6 @@ public void setDomStorageEnabled(WebView view, boolean enabled) { view.getSettings().setDomStorageEnabled(enabled); } - @ReactProp(name = "userAgent") public void setUserAgent(WebView view, @Nullable String userAgent) { if (userAgent != null) { @@ -290,6 +316,11 @@ public void setInjectedJavaScript(WebView view, @Nullable String injectedJavaScr ((ReactWebView) view).setInjectedJavaScript(injectedJavaScript); } + @ReactProp(name = "messageProtocol") + public void setMessageProtocol(WebView view, @Nullable String messageProtocol) { + ((ReactWebView) view).setMessageProtocol(messageProtocol); + } + @ReactProp(name = "source") public void setSource(WebView view, @Nullable ReadableMap source) { if (source != null) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/MessageEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/MessageEvent.java new file mode 100644 index 00000000000000..3843087ca364e3 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/MessageEvent.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.react.views.webview.events; + +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.uimanager.events.Event; +import com.facebook.react.uimanager.events.RCTEventEmitter; + +/** + * Event emitted when there is an error in loading. + */ +public class MessageEvent extends Event { + + public static final String EVENT_NAME = "message"; + private WritableMap mEventData; + + public MessageEvent(int viewId, long timestampMs, WritableMap eventData) { + super(viewId, timestampMs); + mEventData = eventData; + } + + @Override + public String getEventName() { + return EVENT_NAME; + } + + @Override + public boolean canCoalesce() { + return false; + } + + @Override + public short getCoalescingKey() { + // All events for a given view can be coalesced. + return 0; + } + + @Override + public void dispatch(RCTEventEmitter rctEventEmitter) { + rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData); + } +}