From f6e406f969d0e6bf8b54fe148a45268f8eb8f4dc Mon Sep 17 00:00:00 2001 From: Vitaliy Vlasov Date: Tue, 11 Feb 2020 15:06:06 +0200 Subject: [PATCH 1/5] Add Android support for beforeContentLoaded --- .../webview/RNCWebViewManager.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java index 0a57f4f..568558e 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -400,6 +400,11 @@ public class RNCWebViewManager extends SimpleViewManager { ((RNCWebView) view).setInjectedJavaScript(injectedJavaScript); } + @ReactProp(name = "injectedJavaScriptBeforeContentLoaded") + public void setInjectedJavaScriptBeforeContentLoaded(WebView view, @Nullable String injectedJavaScriptBeforeContentLoaded) { + ((RNCWebView) view).setInjectedJavaScriptBeforeContentLoaded(injectedJavaScriptBeforeContentLoaded); + } + @ReactProp(name = "messagingEnabled") public void setMessagingEnabled(WebView view, boolean enabled) { ((RNCWebView) view).setMessagingEnabled(enabled); @@ -753,6 +758,9 @@ public class RNCWebViewManager extends SimpleViewManager { super.onPageStarted(webView, url, favicon); mLastLoadFailed = false; + RNCWebView reactWebView = (RNCWebView) webView; + reactWebView.callInjectedJavaScriptBeforeContentLoaded(); + dispatchEvent( webView, new TopLoadingStartEvent( @@ -1011,6 +1019,8 @@ public class RNCWebViewManager extends SimpleViewManager { protected static class RNCWebView extends WebView implements LifecycleEventListener { protected @Nullable String injectedJS; + protected @Nullable + String injectedJSBeforeContentLoaded; protected boolean messagingEnabled = false; protected @Nullable String messagingModuleName; @@ -1105,6 +1115,10 @@ public class RNCWebViewManager extends SimpleViewManager { injectedJS = js; } + public void setInjectedJavaScriptBeforeContentLoaded(@Nullable String js) { + injectedJSBeforeContentLoaded = js; + } + protected RNCWebViewBridge createRNCWebViewBridge(RNCWebView webView) { return new RNCWebViewBridge(webView); } @@ -1156,9 +1170,19 @@ public class RNCWebViewManager extends SimpleViewManager { injectedJS != null && !TextUtils.isEmpty(injectedJS)) { evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();"); + //evaluateJavascriptWithFallback(injectedJS); } } + public void callInjectedJavaScriptBeforeContentLoaded() { + if (getSettings().getJavaScriptEnabled() && + injectedJSBeforeContentLoaded != null && + !TextUtils.isEmpty(injectedJSBeforeContentLoaded)) { + evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();"); + //evaluateJavascriptWithFallback(injectedJSBeforeContentLoaded); + } + } + public void onMessage(String message) { ReactContext reactContext = (ReactContext) this.getContext(); RNCWebView mContext = this; From edd50aa4aaad689267e71c6cd3274a0ff7de0e4b Mon Sep 17 00:00:00 2001 From: Vitaliy Vlasov Date: Sat, 4 Apr 2020 16:54:36 +0300 Subject: [PATCH 2/5] Replace onPageStarted with shouldInterceptRequest --- .../webview/RNCWebViewManager.java | 287 ++++++++++++++++-- 1 file changed, 265 insertions(+), 22 deletions(-) diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java index 568558e..394cb60 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -1,5 +1,27 @@ package com.reactnativecommunity.webview; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; + +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.OkHttpClient.Builder; +import okhttp3.Request; +import okhttp3.Response; +import org.json.JSONException; +import org.json.JSONObject; +import java.net.HttpURLConnection; + + +import static okhttp3.internal.Util.UTF_8; + + +import android.util.Log; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.DownloadManager; @@ -28,6 +50,8 @@ import android.webkit.GeolocationPermissions; import android.webkit.JavascriptInterface; import android.webkit.PermissionRequest; import android.webkit.URLUtil; +import android.webkit.ServiceWorkerController; +import android.webkit.ServiceWorkerClient; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; @@ -124,8 +148,10 @@ public class RNCWebViewManager extends SimpleViewManager { public static final int COMMAND_CLEAR_HISTORY = 1002; protected static final String REACT_CLASS = "RNCWebView"; + protected static final String HEADER_CONTENT_TYPE = "content-type"; protected static final String HTML_ENCODING = "UTF-8"; protected static final String HTML_MIME_TYPE = "text/html"; + protected static final String UNKNOWN_MIME_TYPE = "application/octet-stream"; protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView"; protected static final String HTTP_METHOD_POST = "POST"; // Use `webView.loadUrl("about:blank")` to reliably reset the view @@ -137,12 +163,22 @@ public class RNCWebViewManager extends SimpleViewManager { protected boolean mAllowsFullscreenVideo = false; protected @Nullable String mUserAgent = null; protected @Nullable String mUserAgentWithApplicationName = null; + protected static String userAgent; + + protected static OkHttpClient httpClient; public RNCWebViewManager() { mWebViewConfig = new WebViewConfig() { public void configWebView(WebView webView) { } }; + + + httpClient = new Builder() + .followRedirects(false) + .followSslRedirects(false) + .build(); + } public RNCWebViewManager(WebViewConfig webViewConfig) { @@ -169,6 +205,7 @@ public class RNCWebViewManager extends SimpleViewManager { @TargetApi(Build.VERSION_CODES.LOLLIPOP) protected WebView createViewInstance(ThemedReactContext reactContext) { RNCWebView webView = createRNCWebViewInstance(reactContext); + userAgent = webView.getSettings().getUserAgentString(); setupWebChromeClient(reactContext, webView); reactContext.addLifecycleEventListener(webView); mWebViewConfig.configWebView(webView); @@ -233,9 +270,102 @@ public class RNCWebViewManager extends SimpleViewManager { } }); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + ServiceWorkerController swController = ServiceWorkerController.getInstance(); + swController.setServiceWorkerClient(new ServiceWorkerClient() { + @Override + public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) { + Log.d(REACT_CLASS, "shouldInterceptRequest / ServiceWorkerClient"); + WebResourceResponse response = RNCWebViewManager.this.shouldInterceptRequest(request, false, webView); + if (response != null) { + Log.d(REACT_CLASS, "shouldInterceptRequest / ServiceWorkerClient -> return intersept response"); + return response; + } + + Log.d(REACT_CLASS, "shouldInterceptRequest / ServiceWorkerClient -> intercept response is nil, delegating up"); + return super.shouldInterceptRequest(request); + } + }); + } + return webView; } + private Boolean urlStringLooksInvalid(String urlString) { + return urlString == null || + urlString.trim().equals("") || + !(urlString.startsWith("http") && !urlString.startsWith("www")) || + urlString.contains("|"); + } + + private Boolean responseRequiresJSInjection(Response response) { + // we don't want to inject JS into redirects + if (response.isRedirect()) { + return false; + } + + // ...okhttp appends charset to content type sometimes, like "text/html; charset=UTF8" + final String contentTypeAndCharset = response.header(HEADER_CONTENT_TYPE, UNKNOWN_MIME_TYPE); + // ...and we only want to inject it in to HTML, really + return contentTypeAndCharset.startsWith(HTML_MIME_TYPE); + } + + + public WebResourceResponse shouldInterceptRequest(WebResourceRequest request, Boolean onlyMainFrame, RNCWebView webView) { + Uri url = request.getUrl(); + String urlStr = url.toString(); + + Log.i("StatusNativeLogs", "###shouldInterceptRequest 1"); + Log.d(REACT_CLASS, "new request "); + Log.d(REACT_CLASS, "url " + urlStr); + Log.d(REACT_CLASS, "host " + request.getUrl().getHost()); + Log.d(REACT_CLASS, "path " + request.getUrl().getPath()); + Log.d(REACT_CLASS, "main " + request.isForMainFrame()); + Log.d(REACT_CLASS, "headers " + request.getRequestHeaders().toString()); + Log.d(REACT_CLASS, "method " + request.getMethod()); + + Log.i("StatusNativeLogs", "###shouldInterceptRequest 2"); + if (onlyMainFrame && !request.isForMainFrame() || + urlStringLooksInvalid(urlStr)) { + return null;//super.shouldInterceptRequest(webView, request); + } + + Log.i("StatusNativeLogs", "###shouldInterceptRequest 3"); + try { + Log.i("StatusNativeLogs", "###shouldInterceptRequest 4"); + Request req = new Request.Builder() + .url(urlStr) + .header("User-Agent", userAgent) + .build(); + + Log.i("StatusNativeLogs", "### httpCall " + new Boolean(httpClient != null).toString()); + Response response = httpClient.newCall(req).execute(); + + Log.d(REACT_CLASS, "response headers " + response.headers().toString()); + Log.d(REACT_CLASS, "response code " + response.code()); + Log.d(REACT_CLASS, "response suc " + response.isSuccessful()); + + if (!responseRequiresJSInjection(response)) { + return null; + } + + InputStream is = response.body().byteStream(); + MediaType contentType = response.body().contentType(); + Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8; + + RNCWebView reactWebView = (RNCWebView) webView; + if (response.code() == HttpURLConnection.HTTP_OK) { + is = new InputStreamWithInjectedJS(is, reactWebView.injectedJSBeforeContentLoaded, charset); + } + + Log.d(REACT_CLASS, "inject our custom JS to this request"); + return new WebResourceResponse("text/html", charset.name(), is); + } catch (IOException e) { + return null; + } + } + @ReactProp(name = "javaScriptEnabled") public void setJavaScriptEnabled(WebView view, boolean enabled) { view.getSettings().setJavaScriptEnabled(enabled); @@ -728,8 +858,95 @@ public class RNCWebViewManager extends SimpleViewManager { } } - protected static class RNCWebViewClient extends WebViewClient { + public static class InputStreamWithInjectedJS extends InputStream { + private InputStream pageIS; + private InputStream scriptIS; + private Charset charset; + private static final String REACT_CLASS = "InputStreamWithInjectedJS"; + private static Map script = new HashMap<>(); + private boolean hasJS = false; + private boolean headWasFound = false; + private boolean scriptWasInjected = false; + private StringBuffer contentBuffer = new StringBuffer(); + + private static Charset getCharset(String charsetName) { + Charset cs = StandardCharsets.UTF_8; + try { + if (charsetName != null) { + cs = Charset.forName(charsetName); + } + } catch (UnsupportedCharsetException e) { + Log.d(REACT_CLASS, "wrong charset: " + charsetName); + } + + return cs; + } + + private static InputStream getScript(Charset charset) { + String js = script.get(charset); + if (js == null) { + String defaultJs = script.get(StandardCharsets.UTF_8); + js = new String(defaultJs.getBytes(StandardCharsets.UTF_8), charset); + script.put(charset, js); + } + + return new ByteArrayInputStream(js.getBytes(charset)); + } + + InputStreamWithInjectedJS(InputStream is, String js, Charset charset) { + if (js == null) { + this.pageIS = is; + } else { + this.hasJS = true; + this.charset = charset; + Charset cs = StandardCharsets.UTF_8; + String jsScript = ""; + script.put(cs, jsScript); + this.pageIS = is; + } + } + + @Override + public int read() throws IOException { + if (scriptWasInjected || !hasJS) { + return pageIS.read(); + } + + if (!scriptWasInjected && headWasFound) { + int nextByte = scriptIS.read(); + if (nextByte == -1) { + scriptIS.close(); + scriptWasInjected = true; + return pageIS.read(); + } else { + return nextByte; + } + } + + if (!headWasFound) { + int nextByte = pageIS.read(); + contentBuffer.append((char) nextByte); + int bufferLength = contentBuffer.length(); + if (nextByte == 62 && bufferLength >= 6) { + if (contentBuffer.substring(bufferLength - 6).equals("")) { + this.scriptIS = getScript(this.charset); + headWasFound = true; + } + } + + return nextByte; + } + + return pageIS.read(); + } + + } + + protected class RNCWebViewClient extends WebViewClient { + + + protected static final String REACT_CLASS = "RNCWebViewClient"; protected boolean mLastLoadFailed = false; protected @Nullable ReadableArray mUrlPrefixesForDefaultIntent; @@ -740,6 +957,7 @@ public class RNCWebViewManager extends SimpleViewManager { ignoreErrFailedForThisURL = url; } + @Override public void onPageFinished(WebView webView, String url) { super.onPageFinished(webView, url); @@ -758,9 +976,6 @@ public class RNCWebViewManager extends SimpleViewManager { super.onPageStarted(webView, url, favicon); mLastLoadFailed = false; - RNCWebView reactWebView = (RNCWebView) webView; - reactWebView.callInjectedJavaScriptBeforeContentLoaded(); - dispatchEvent( webView, new TopLoadingStartEvent( @@ -768,6 +983,48 @@ public class RNCWebViewManager extends SimpleViewManager { createWebViewEvent(webView, url))); } + + @Override + public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest request) { + Log.d(REACT_CLASS, "shouldInterceptRequest / WebViewClient"); + WebResourceResponse response = RNCWebViewManager.this.shouldInterceptRequest(request, true, (RNCWebView)webView); + if (response != null) { + Log.d(REACT_CLASS, "shouldInterceptRequest / WebViewClient -> return intercept response"); + return response; + } + + Log.d(REACT_CLASS, "shouldInterceptRequest / WebViewClient -> intercept response is nil, delegating up"); + return super.shouldInterceptRequest(webView, request); + + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + if (request == null || view == null) { + return false; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + + /* + * In order to follow redirects properly, we return null in interceptRequest(). + * Doing this breaks the web3 injection on the resulting page, so we have to reload to + * make sure web3 is available. + * */ + + if (request.isForMainFrame() && request.isRedirect()) { + view.loadUrl(request.getUrl().toString()); + return true; + } + } + + /* + * API < 24: TODO: implement based on https://github.com/toshiapp/toshi-android-client/blob/f4840d3d24ff60223662eddddceca8586a1be8bb/app/src/main/java/com/toshi/view/activity/webView/ToshiWebClient.kt#L99 + * */ + final String url = request.getUrl().toString(); + return this.shouldOverrideUrlLoading(view, url); + } + @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { progressChangedFilter.setWaitingForCommandLoadUrl(true); @@ -780,13 +1037,6 @@ public class RNCWebViewManager extends SimpleViewManager { } - @TargetApi(Build.VERSION_CODES.N) - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - final String url = request.getUrl().toString(); - return this.shouldOverrideUrlLoading(view, url); - } - @Override public void onReceivedError( WebView webView, @@ -901,6 +1151,9 @@ public class RNCWebViewManager extends SimpleViewManager { @Override public boolean onConsoleMessage(ConsoleMessage message) { + Log.i("StatusNativeLogs", "###js " + message.message() + " -- From line " + + message.lineNumber() + " of " + + message.sourceId()); if (ReactBuildConfig.DEBUG) { return super.onConsoleMessage(message); } @@ -1019,8 +1272,7 @@ public class RNCWebViewManager extends SimpleViewManager { protected static class RNCWebView extends WebView implements LifecycleEventListener { protected @Nullable String injectedJS; - protected @Nullable - String injectedJSBeforeContentLoaded; + protected @Nullable String injectedJSBeforeContentLoaded; protected boolean messagingEnabled = false; protected @Nullable String messagingModuleName; @@ -1174,15 +1426,6 @@ public class RNCWebViewManager extends SimpleViewManager { } } - public void callInjectedJavaScriptBeforeContentLoaded() { - if (getSettings().getJavaScriptEnabled() && - injectedJSBeforeContentLoaded != null && - !TextUtils.isEmpty(injectedJSBeforeContentLoaded)) { - evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();"); - //evaluateJavascriptWithFallback(injectedJSBeforeContentLoaded); - } - } - public void onMessage(String message) { ReactContext reactContext = (ReactContext) this.getContext(); RNCWebView mContext = this; From 52bb4d3f35f5a4d35c15b14de6106f6495d0adf6 Mon Sep 17 00:00:00 2001 From: Vitaliy Vlasov Date: Mon, 4 May 2020 18:36:34 +0300 Subject: [PATCH 3/5] Add lib/ folder --- .gitignore | 2 +- lib/WebView.android.d.ts | 73 ++++ lib/WebView.android.d.ts.map | 1 + lib/WebView.android.js | 278 +++++++++++++ lib/WebView.d.ts | 4 + lib/WebView.d.ts.map | 1 + lib/WebView.ios.d.ts | 83 ++++ lib/WebView.ios.d.ts.map | 1 + lib/WebView.ios.js | 282 +++++++++++++ lib/WebView.js | 4 + lib/WebView.macos.d.ts | 83 ++++ lib/WebView.macos.d.ts.map | 1 + lib/WebView.macos.js | 270 ++++++++++++ lib/WebView.styles.d.ts | 12 + lib/WebView.styles.d.ts.map | 1 + lib/WebView.styles.js | 33 ++ lib/WebView.windows.d.ts | 38 ++ lib/WebView.windows.d.ts.map | 1 + lib/WebView.windows.js | 184 ++++++++ lib/WebViewShared.d.ts | 7 + lib/WebViewShared.d.ts.map | 1 + lib/WebViewShared.js | 59 +++ lib/WebViewTypes.d.ts | 785 +++++++++++++++++++++++++++++++++++ lib/WebViewTypes.d.ts.map | 1 + lib/WebViewTypes.js | 55 +++ 25 files changed, 2259 insertions(+), 1 deletion(-) create mode 100644 lib/WebView.android.d.ts create mode 100644 lib/WebView.android.d.ts.map create mode 100644 lib/WebView.android.js create mode 100644 lib/WebView.d.ts create mode 100644 lib/WebView.d.ts.map create mode 100644 lib/WebView.ios.d.ts create mode 100644 lib/WebView.ios.d.ts.map create mode 100644 lib/WebView.ios.js create mode 100644 lib/WebView.js create mode 100644 lib/WebView.macos.d.ts create mode 100644 lib/WebView.macos.d.ts.map create mode 100644 lib/WebView.macos.js create mode 100644 lib/WebView.styles.d.ts create mode 100644 lib/WebView.styles.d.ts.map create mode 100644 lib/WebView.styles.js create mode 100644 lib/WebView.windows.d.ts create mode 100644 lib/WebView.windows.d.ts.map create mode 100644 lib/WebView.windows.js create mode 100644 lib/WebViewShared.d.ts create mode 100644 lib/WebViewShared.d.ts.map create mode 100644 lib/WebViewShared.js create mode 100644 lib/WebViewTypes.d.ts create mode 100644 lib/WebViewTypes.d.ts.map create mode 100644 lib/WebViewTypes.js diff --git a/.gitignore b/.gitignore index 109d94a..356ff9e 100644 --- a/.gitignore +++ b/.gitignore @@ -53,7 +53,7 @@ android/gradle android/gradlew android/gradlew.bat -lib/ +#lib/ .classpath .project .settings/ diff --git a/lib/WebView.android.d.ts b/lib/WebView.android.d.ts new file mode 100644 index 0000000..791260d --- /dev/null +++ b/lib/WebView.android.d.ts @@ -0,0 +1,73 @@ +import React from 'react'; +import { AndroidWebViewProps, NativeWebViewAndroid, State } from './WebViewTypes'; +/** + * Renders a native WebView. + */ +declare class WebView extends React.Component { + static defaultProps: { + overScrollMode: string; + javaScriptEnabled: boolean; + thirdPartyCookiesEnabled: boolean; + scalesPageToFit: boolean; + allowsFullscreenVideo: boolean; + allowFileAccess: boolean; + saveFormDataDisabled: boolean; + cacheEnabled: boolean; + androidHardwareAccelerationDisabled: boolean; + originWhitelist: string[]; + }; + static isFileUploadSupported: () => Promise; + startUrl: string | null; + state: State; + webViewRef: React.RefObject; + messagingModuleName: string; + componentDidMount: () => void; + getCommands: () => { + goForward: number; + goBack: number; + reload: number; + stopLoading: number; + postMessage: number; + injectJavaScript: number; + loadUrl: number; + requestFocus: number; + clearHistory: number; + clearCache: number; + clearFormData: number; + }; + goForward: () => void; + goBack: () => void; + reload: () => void; + stopLoading: () => void; + requestFocus: () => void; + postMessage: (data: string) => void; + clearFormData: () => void; + clearCache: (includeDiskFiles: boolean) => void; + clearHistory: () => void; + /** + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + injectJavaScript: (data: string) => void; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + updateNavigationState: (event: import("react-native").NativeSyntheticEvent) => void; + /** + * Returns the native `WebView` node. + */ + getWebViewHandle: () => number; + onLoadingStart: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingError: (event: import("react-native").NativeSyntheticEvent) => void; + onHttpError: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingFinish: (event: import("react-native").NativeSyntheticEvent) => void; + onMessage: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingProgress: (event: import("react-native").NativeSyntheticEvent) => void; + onShouldStartLoadWithRequestCallback: (shouldStart: boolean, url: string) => void; + render(): JSX.Element; +} +export default WebView; +//# sourceMappingURL=WebView.android.d.ts.map \ No newline at end of file diff --git a/lib/WebView.android.d.ts.map b/lib/WebView.android.d.ts.map new file mode 100644 index 0000000..26d6a4c --- /dev/null +++ b/lib/WebView.android.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebView.android.d.ts","sourceRoot":"","sources":["../src/WebView.android.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAsB1B,OAAO,EAML,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,EAEN,MAAM,gBAAgB,CAAC;AAgBxB;;GAEG;AACH,cAAM,OAAQ,SAAQ,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,CAAC;IAC/D,MAAM,CAAC,YAAY;;;;;;;;;;;MAWjB;IAEF,MAAM,CAAC,qBAAqB,qBAG1B;IAEF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B,KAAK,EAAE,KAAK,CAGV;IAGF,UAAU,wCAA2C;IAErD,mBAAmB,SAA0C;IAE7D,iBAAiB,aAEf;IAEF,WAAW;;;;;;;;;;;;MAA+D;IAE1E,SAAS,aAMP;IAEF,MAAM,aAMJ;IAEF,MAAM,aASJ;IAEF,WAAW,aAMT;IAEF,YAAY,aAMV;IAEF,WAAW,yBAMT;IAEF,aAAa,aAMZ;IAED,UAAU,sCAMR;IAEF,YAAY,aAMV;IAEF;;;;;OAKG;IACH,gBAAgB,yBAMd;IAEF;;;OAGG;IACH,qBAAqB,2GAInB;IAEF;;OAEG;IACH,gBAAgB,eAId;IAEF,cAAc,2GAQZ;IAEF,cAAc,sGAeZ;IAEF,WAAW,0GAKV;IAED,eAAe,2GAeb;IAEF,SAAS,wGAKP;IAEF,iBAAiB,oHAcf;IAEF,oCAAoC,8CAWlC;IAEF,MAAM;CAmFP;AAED,eAAe,OAAO,CAAC"} \ No newline at end of file diff --git a/lib/WebView.android.js b/lib/WebView.android.js new file mode 100644 index 0000000..6d60e27 --- /dev/null +++ b/lib/WebView.android.js @@ -0,0 +1,278 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +import React from 'react'; +import { Image, requireNativeComponent, UIManager as NotTypedUIManager, View, NativeModules, findNodeHandle, } from 'react-native'; +import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge'; +import invariant from 'invariant'; +import { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderError, defaultRenderLoading, } from './WebViewShared'; +import styles from './WebView.styles'; +var UIManager = NotTypedUIManager; +var RNCWebView = requireNativeComponent('RNCWebView'); +var resolveAssetSource = Image.resolveAssetSource; +/** + * A simple counter to uniquely identify WebView instances. Do not use this for anything else. + */ +var uniqueRef = 0; +/** + * Renders a native WebView. + */ +var WebView = /** @class */ (function (_super) { + __extends(WebView, _super); + function WebView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.startUrl = null; + _this.state = { + viewState: _this.props.startInLoadingState ? 'LOADING' : 'IDLE', + lastErrorEvent: null + }; + _this.webViewRef = React.createRef(); + _this.messagingModuleName = "WebViewMessageHandler" + (uniqueRef += 1); + _this.componentDidMount = function () { + BatchedBridge.registerCallableModule(_this.messagingModuleName, _this); + }; + _this.getCommands = function () { return UIManager.getViewManagerConfig('RNCWebView').Commands; }; + _this.goForward = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().goForward, undefined); + }; + _this.goBack = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().goBack, undefined); + }; + _this.reload = function () { + _this.setState({ + viewState: 'LOADING' + }); + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().reload, undefined); + }; + _this.stopLoading = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().stopLoading, undefined); + }; + _this.requestFocus = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().requestFocus, undefined); + }; + _this.postMessage = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().postMessage, [String(data)]); + }; + _this.clearFormData = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().clearFormData, undefined); + }; + _this.clearCache = function (includeDiskFiles) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().clearCache, [includeDiskFiles]); + }; + _this.clearHistory = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().clearHistory, undefined); + }; + /** + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + _this.injectJavaScript = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().injectJavaScript, [data]); + }; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + _this.updateNavigationState = function (event) { + if (_this.props.onNavigationStateChange) { + _this.props.onNavigationStateChange(event.nativeEvent); + } + }; + /** + * Returns the native `WebView` node. + */ + _this.getWebViewHandle = function () { + var nodeHandle = findNodeHandle(_this.webViewRef.current); + invariant(nodeHandle != null, 'nodeHandle expected to be non-null'); + return nodeHandle; + }; + _this.onLoadingStart = function (event) { + var onLoadStart = _this.props.onLoadStart; + var url = event.nativeEvent.url; + _this.startUrl = url; + if (onLoadStart) { + onLoadStart(event); + } + _this.updateNavigationState(event); + }; + _this.onLoadingError = function (event) { + event.persist(); // persist this event because we need to store it + var _a = _this.props, onError = _a.onError, onLoadEnd = _a.onLoadEnd; + if (onError) { + onError(event); + } + if (onLoadEnd) { + onLoadEnd(event); + } + console.warn('Encountered an error loading page', event.nativeEvent); + _this.setState({ + lastErrorEvent: event.nativeEvent, + viewState: 'ERROR' + }); + }; + _this.onHttpError = function (event) { + var onHttpError = _this.props.onHttpError; + if (onHttpError) { + onHttpError(event); + } + }; + _this.onLoadingFinish = function (event) { + var _a = _this.props, onLoad = _a.onLoad, onLoadEnd = _a.onLoadEnd; + var url = event.nativeEvent.url; + if (onLoad) { + onLoad(event); + } + if (onLoadEnd) { + onLoadEnd(event); + } + if (url === _this.startUrl) { + _this.setState({ + viewState: 'IDLE' + }); + } + _this.updateNavigationState(event); + }; + _this.onMessage = function (event) { + var onMessage = _this.props.onMessage; + if (onMessage) { + onMessage(event); + } + }; + _this.onLoadingProgress = function (event) { + var onLoadProgress = _this.props.onLoadProgress; + var progress = event.nativeEvent.progress; + if (progress === 1) { + _this.setState(function (state) { + if (state.viewState === 'LOADING') { + return { viewState: 'IDLE' }; + } + return null; + }); + } + if (onLoadProgress) { + onLoadProgress(event); + } + }; + _this.onShouldStartLoadWithRequestCallback = function (shouldStart, url) { + if (shouldStart) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().loadUrl, [String(url)]); + } + }; + return _this; + } + WebView.prototype.render = function () { + var _a = this.props, onMessage = _a.onMessage, onShouldStartLoadWithRequestProp = _a.onShouldStartLoadWithRequest, originWhitelist = _a.originWhitelist, renderError = _a.renderError, renderLoading = _a.renderLoading, source = _a.source, style = _a.style, containerStyle = _a.containerStyle, _b = _a.nativeConfig, nativeConfig = _b === void 0 ? {} : _b, otherProps = __rest(_a, ["onMessage", "onShouldStartLoadWithRequest", "originWhitelist", "renderError", "renderLoading", "source", "style", "containerStyle", "nativeConfig"]); + var otherView = null; + if (this.state.viewState === 'LOADING') { + otherView = (renderLoading || defaultRenderLoading)(); + } + else if (this.state.viewState === 'ERROR') { + var errorEvent = this.state.lastErrorEvent; + invariant(errorEvent != null, 'lastErrorEvent expected to be non-null'); + otherView = (renderError || defaultRenderError)(errorEvent.domain, errorEvent.code, errorEvent.description); + } + else if (this.state.viewState !== 'IDLE') { + console.error("RNCWebView invalid state encountered: " + this.state.viewState); + } + var webViewStyles = [styles.container, styles.webView, style]; + var webViewContainerStyle = [styles.container, containerStyle]; + if (typeof source !== "number" && source && 'method' in source) { + if (source.method === 'POST' && source.headers) { + console.warn('WebView: `source.headers` is not supported when using POST.'); + } + else if (source.method === 'GET' && source.body) { + console.warn('WebView: `source.body` is not supported when using GET.'); + } + } + var NativeWebView = nativeConfig.component || RNCWebView; + var onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(this.onShouldStartLoadWithRequestCallback, + // casting cause it's in the default props + originWhitelist, onShouldStartLoadWithRequestProp); + var webView = (); + return ( + {webView} + {otherView} + ); + }; + WebView.defaultProps = { + overScrollMode: 'always', + javaScriptEnabled: true, + thirdPartyCookiesEnabled: true, + scalesPageToFit: true, + allowsFullscreenVideo: false, + allowFileAccess: false, + saveFormDataDisabled: false, + cacheEnabled: true, + androidHardwareAccelerationDisabled: false, + originWhitelist: defaultOriginWhitelist + }; + WebView.isFileUploadSupported = function () { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + // native implementation should return "true" only for Android 5+ + return [2 /*return*/, NativeModules.RNCWebView.isFileUploadSupported()]; + }); + }); }; + return WebView; +}(React.Component)); +export default WebView; diff --git a/lib/WebView.d.ts b/lib/WebView.d.ts new file mode 100644 index 0000000..f4551be --- /dev/null +++ b/lib/WebView.d.ts @@ -0,0 +1,4 @@ +import { WebView } from 'react-native'; +export { WebView }; +export default WebView; +//# sourceMappingURL=WebView.d.ts.map \ No newline at end of file diff --git a/lib/WebView.d.ts.map b/lib/WebView.d.ts.map new file mode 100644 index 0000000..887cabe --- /dev/null +++ b/lib/WebView.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebView.d.ts","sourceRoot":"","sources":["../src/WebView.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,CAAC;AACnB,eAAe,OAAO,CAAC"} \ No newline at end of file diff --git a/lib/WebView.ios.d.ts b/lib/WebView.ios.d.ts new file mode 100644 index 0000000..6c109bf --- /dev/null +++ b/lib/WebView.ios.d.ts @@ -0,0 +1,83 @@ +import React from 'react'; +import { IOSWebViewProps, NativeWebViewIOS, State } from './WebViewTypes'; +declare class WebView extends React.Component { + static defaultProps: { + javaScriptEnabled: boolean; + cacheEnabled: boolean; + originWhitelist: string[]; + useSharedProcessPool: boolean; + }; + static isFileUploadSupported: () => Promise; + state: State; + webViewRef: React.RefObject; + getCommands: () => { + goForward: number; + goBack: number; + reload: number; + stopLoading: number; + postMessage: number; + injectJavaScript: number; + loadUrl: number; + requestFocus: number; + }; + /** + * Go forward one page in the web view's history. + */ + goForward: () => void; + /** + * Go back one page in the web view's history. + */ + goBack: () => void; + /** + * Reloads the current page. + */ + reload: () => void; + /** + * Stop loading the current page. + */ + stopLoading: () => void; + /** + * Request focus on WebView rendered page. + */ + requestFocus: () => void; + /** + * Posts a message to the web view, which will emit a `message` event. + * Accepts one argument, `data`, which must be a string. + * + * In your webview, you'll need to something like the following. + * + * ```js + * document.addEventListener('message', e => { document.title = e.data; }); + * ``` + */ + postMessage: (data: string) => void; + /** + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + injectJavaScript: (data: string) => void; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + updateNavigationState: (event: import("react-native").NativeSyntheticEvent) => void; + /** + * Returns the native `WebView` node. + */ + getWebViewHandle: () => number; + onLoadingStart: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingError: (event: import("react-native").NativeSyntheticEvent) => void; + onHttpError: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingFinish: (event: import("react-native").NativeSyntheticEvent) => void; + onMessage: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingProgress: (event: import("react-native").NativeSyntheticEvent) => void; + onShouldStartLoadWithRequestCallback: (shouldStart: boolean, _url: string, lockIdentifier: number) => void; + onContentProcessDidTerminate: (event: import("react-native").NativeSyntheticEvent) => void; + componentDidUpdate(prevProps: IOSWebViewProps): void; + showRedboxOnPropChanges(prevProps: IOSWebViewProps, propName: keyof IOSWebViewProps): void; + render(): JSX.Element; +} +export default WebView; +//# sourceMappingURL=WebView.ios.d.ts.map \ No newline at end of file diff --git a/lib/WebView.ios.d.ts.map b/lib/WebView.ios.d.ts.map new file mode 100644 index 0000000..10da6ca --- /dev/null +++ b/lib/WebView.ios.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebView.ios.d.ts","sourceRoot":"","sources":["../src/WebView.ios.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAkB1B,OAAO,EAOL,eAAe,EAEf,gBAAgB,EAEhB,KAAK,EAEN,MAAM,gBAAgB,CAAC;AAyBxB,cAAM,OAAQ,SAAQ,KAAK,CAAC,SAAS,CAAC,eAAe,EAAE,KAAK,CAAC;IAC3D,MAAM,CAAC,YAAY;;;;;MAKjB;IAEF,MAAM,CAAC,qBAAqB,yBAG1B;IAEF,KAAK,EAAE,KAAK,CAGV;IAEF,UAAU,oCAAuC;IAGjD,WAAW;;;;;;;;;MAA+D;IAE1E;;OAEG;IACH,SAAS,aAMP;IAEF;;OAEG;IACH,MAAM,aAMJ;IAEF;;OAEG;IACH,MAAM,aAOJ;IAEF;;OAEG;IACH,WAAW,aAMT;IAEF;;OAEG;IACH,YAAY,aAMV;IAEF;;;;;;;;;OASG;IACH,WAAW,yBAMT;IAEF;;;;;OAKG;IACH,gBAAgB,yBAMd;IAEF;;;OAGG;IACH,qBAAqB,2GAInB;IAEF;;OAEG;IACH,gBAAgB,eAId;IAEF,cAAc,2GAMZ;IAEF,cAAc,sGAeZ;IAEF,WAAW,0GAKV;IAED,eAAe,2GAYb;IAEF,SAAS,wGAKP;IAEF,iBAAiB,oHAKf;IAEF,oCAAoC,uEAUlC;IAEF,4BAA4B,4GAK1B;IAEF,kBAAkB,CAAC,SAAS,EAAE,eAAe;IAO7C,uBAAuB,CACrB,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,MAAM,eAAe;IASjC,MAAM;CAqFP;AAED,eAAe,OAAO,CAAC"} \ No newline at end of file diff --git a/lib/WebView.ios.js b/lib/WebView.ios.js new file mode 100644 index 0000000..cfc3700 --- /dev/null +++ b/lib/WebView.ios.js @@ -0,0 +1,282 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +import React from 'react'; +import { UIManager as NotTypedUIManager, View, requireNativeComponent, NativeModules, Image, findNodeHandle, } from 'react-native'; +import invariant from 'invariant'; +import { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderError, defaultRenderLoading, } from './WebViewShared'; +import styles from './WebView.styles'; +var UIManager = NotTypedUIManager; +var resolveAssetSource = Image.resolveAssetSource; +var processDecelerationRate = function (decelerationRate) { + var newDecelerationRate = decelerationRate; + if (newDecelerationRate === 'normal') { + newDecelerationRate = 0.998; + } + else if (newDecelerationRate === 'fast') { + newDecelerationRate = 0.99; + } + return newDecelerationRate; +}; +var RNCWebViewManager = NativeModules.RNCWebViewManager; +var RNCWebView = requireNativeComponent('RNCWebView'); +var WebView = /** @class */ (function (_super) { + __extends(WebView, _super); + function WebView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.state = { + viewState: _this.props.startInLoadingState ? 'LOADING' : 'IDLE', + lastErrorEvent: null + }; + _this.webViewRef = React.createRef(); + // eslint-disable-next-line react/sort-comp + _this.getCommands = function () { return UIManager.getViewManagerConfig('RNCWebView').Commands; }; + /** + * Go forward one page in the web view's history. + */ + _this.goForward = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().goForward, undefined); + }; + /** + * Go back one page in the web view's history. + */ + _this.goBack = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().goBack, undefined); + }; + /** + * Reloads the current page. + */ + _this.reload = function () { + _this.setState({ viewState: 'LOADING' }); + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().reload, undefined); + }; + /** + * Stop loading the current page. + */ + _this.stopLoading = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().stopLoading, undefined); + }; + /** + * Request focus on WebView rendered page. + */ + _this.requestFocus = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().requestFocus, undefined); + }; + /** + * Posts a message to the web view, which will emit a `message` event. + * Accepts one argument, `data`, which must be a string. + * + * In your webview, you'll need to something like the following. + * + * ```js + * document.addEventListener('message', e => { document.title = e.data; }); + * ``` + */ + _this.postMessage = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().postMessage, [String(data)]); + }; + /** + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + _this.injectJavaScript = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().injectJavaScript, [data]); + }; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + _this.updateNavigationState = function (event) { + if (_this.props.onNavigationStateChange) { + _this.props.onNavigationStateChange(event.nativeEvent); + } + }; + /** + * Returns the native `WebView` node. + */ + _this.getWebViewHandle = function () { + var nodeHandle = findNodeHandle(_this.webViewRef.current); + invariant(nodeHandle != null, 'nodeHandle expected to be non-null'); + return nodeHandle; + }; + _this.onLoadingStart = function (event) { + var onLoadStart = _this.props.onLoadStart; + if (onLoadStart) { + onLoadStart(event); + } + _this.updateNavigationState(event); + }; + _this.onLoadingError = function (event) { + event.persist(); // persist this event because we need to store it + var _a = _this.props, onError = _a.onError, onLoadEnd = _a.onLoadEnd; + if (onLoadEnd) { + onLoadEnd(event); + } + if (onError) { + onError(event); + } + console.warn('Encountered an error loading page', event.nativeEvent); + _this.setState({ + lastErrorEvent: event.nativeEvent, + viewState: 'ERROR' + }); + }; + _this.onHttpError = function (event) { + var onHttpError = _this.props.onHttpError; + if (onHttpError) { + onHttpError(event); + } + }; + _this.onLoadingFinish = function (event) { + var _a = _this.props, onLoad = _a.onLoad, onLoadEnd = _a.onLoadEnd; + if (onLoad) { + onLoad(event); + } + if (onLoadEnd) { + onLoadEnd(event); + } + _this.setState({ + viewState: 'IDLE' + }); + _this.updateNavigationState(event); + }; + _this.onMessage = function (event) { + var onMessage = _this.props.onMessage; + if (onMessage) { + onMessage(event); + } + }; + _this.onLoadingProgress = function (event) { + var onLoadProgress = _this.props.onLoadProgress; + if (onLoadProgress) { + onLoadProgress(event); + } + }; + _this.onShouldStartLoadWithRequestCallback = function (shouldStart, _url, lockIdentifier) { + var viewManager = (_this.props.nativeConfig && _this.props.nativeConfig.viewManager) + || RNCWebViewManager; + viewManager.startLoadWithResult(!!shouldStart, lockIdentifier); + }; + _this.onContentProcessDidTerminate = function (event) { + var onContentProcessDidTerminate = _this.props.onContentProcessDidTerminate; + if (onContentProcessDidTerminate) { + onContentProcessDidTerminate(event); + } + }; + return _this; + } + WebView.prototype.componentDidUpdate = function (prevProps) { + this.showRedboxOnPropChanges(prevProps, 'allowsInlineMediaPlayback'); + this.showRedboxOnPropChanges(prevProps, 'incognito'); + this.showRedboxOnPropChanges(prevProps, 'mediaPlaybackRequiresUserAction'); + this.showRedboxOnPropChanges(prevProps, 'dataDetectorTypes'); + }; + WebView.prototype.showRedboxOnPropChanges = function (prevProps, propName) { + if (this.props[propName] !== prevProps[propName]) { + console.error("Changes to property " + propName + " do nothing after the initial render."); + } + }; + WebView.prototype.render = function () { + var _a = this.props, decelerationRateProp = _a.decelerationRate, _b = _a.nativeConfig, nativeConfig = _b === void 0 ? {} : _b, onMessage = _a.onMessage, onShouldStartLoadWithRequestProp = _a.onShouldStartLoadWithRequest, originWhitelist = _a.originWhitelist, renderError = _a.renderError, renderLoading = _a.renderLoading, _c = _a.injectedJavaScriptForMainFrameOnly, injectedJavaScriptForMainFrameOnly = _c === void 0 ? true : _c, _d = _a.injectedJavaScriptBeforeContentLoadedForMainFrameOnly, injectedJavaScriptBeforeContentLoadedForMainFrameOnly = _d === void 0 ? true : _d, style = _a.style, containerStyle = _a.containerStyle, otherProps = __rest(_a, ["decelerationRate", "nativeConfig", "onMessage", "onShouldStartLoadWithRequest", "originWhitelist", "renderError", "renderLoading", "injectedJavaScriptForMainFrameOnly", "injectedJavaScriptBeforeContentLoadedForMainFrameOnly", "style", "containerStyle"]); + var otherView = null; + if (this.state.viewState === 'LOADING') { + otherView = (renderLoading || defaultRenderLoading)(); + } + else if (this.state.viewState === 'ERROR') { + var errorEvent = this.state.lastErrorEvent; + invariant(errorEvent != null, 'lastErrorEvent expected to be non-null'); + otherView = (renderError || defaultRenderError)(errorEvent.domain, errorEvent.code, errorEvent.description); + } + else if (this.state.viewState !== 'IDLE') { + console.error("RNCWebView invalid state encountered: " + this.state.viewState); + } + var webViewStyles = [styles.container, styles.webView, style]; + var webViewContainerStyle = [styles.container, containerStyle]; + var onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(this.onShouldStartLoadWithRequestCallback, + // casting cause it's in the default props + originWhitelist, onShouldStartLoadWithRequestProp); + var decelerationRate = processDecelerationRate(decelerationRateProp); + var NativeWebView = nativeConfig.component + || RNCWebView; + var webView = (); + return ( + {webView} + {otherView} + ); + }; + WebView.defaultProps = { + javaScriptEnabled: true, + cacheEnabled: true, + originWhitelist: defaultOriginWhitelist, + useSharedProcessPool: true + }; + WebView.isFileUploadSupported = function () { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + // no native implementation for iOS, depends only on permissions + return [2 /*return*/, true]; + }); + }); }; + return WebView; +}(React.Component)); +export default WebView; diff --git a/lib/WebView.js b/lib/WebView.js new file mode 100644 index 0000000..6352fcd --- /dev/null +++ b/lib/WebView.js @@ -0,0 +1,4 @@ +// This files provides compatibility without tree platform. +import { WebView } from 'react-native'; +export { WebView }; +export default WebView; diff --git a/lib/WebView.macos.d.ts b/lib/WebView.macos.d.ts new file mode 100644 index 0000000..a7534c1 --- /dev/null +++ b/lib/WebView.macos.d.ts @@ -0,0 +1,83 @@ +import React from 'react'; +import { MacOSWebViewProps, NativeWebViewMacOS, State } from './WebViewTypes'; +declare class WebView extends React.Component { + static defaultProps: { + javaScriptEnabled: boolean; + cacheEnabled: boolean; + originWhitelist: string[]; + useSharedProcessPool: boolean; + }; + static isFileUploadSupported: () => Promise; + state: State; + webViewRef: React.RefObject; + getCommands: () => { + goForward: number; + goBack: number; + reload: number; + stopLoading: number; + postMessage: number; + injectJavaScript: number; + loadUrl: number; + requestFocus: number; + }; + /** + * Go forward one page in the web view's history. + */ + goForward: () => void; + /** + * Go back one page in the web view's history. + */ + goBack: () => void; + /** + * Reloads the current page. + */ + reload: () => void; + /** + * Stop loading the current page. + */ + stopLoading: () => void; + /** + * Request focus on WebView rendered page. + */ + requestFocus: () => void; + /** + * Posts a message to the web view, which will emit a `message` event. + * Accepts one argument, `data`, which must be a string. + * + * In your webview, you'll need to something like the following. + * + * ```js + * document.addEventListener('message', e => { document.title = e.data; }); + * ``` + */ + postMessage: (data: string) => void; + /** + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + injectJavaScript: (data: string) => void; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + updateNavigationState: (event: import("react-native").NativeSyntheticEvent) => void; + /** + * Returns the native `WebView` node. + */ + getWebViewHandle: () => number; + onLoadingStart: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingError: (event: import("react-native").NativeSyntheticEvent) => void; + onHttpError: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingFinish: (event: import("react-native").NativeSyntheticEvent) => void; + onMessage: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingProgress: (event: import("react-native").NativeSyntheticEvent) => void; + onShouldStartLoadWithRequestCallback: (shouldStart: boolean, _url: string, lockIdentifier: number) => void; + onContentProcessDidTerminate: (event: import("react-native").NativeSyntheticEvent) => void; + componentDidUpdate(prevProps: MacOSWebViewProps): void; + showRedboxOnPropChanges(prevProps: MacOSWebViewProps, propName: keyof MacOSWebViewProps): void; + render(): JSX.Element; +} +export default WebView; +//# sourceMappingURL=WebView.macos.d.ts.map \ No newline at end of file diff --git a/lib/WebView.macos.d.ts.map b/lib/WebView.macos.d.ts.map new file mode 100644 index 0000000..957ecaf --- /dev/null +++ b/lib/WebView.macos.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebView.macos.d.ts","sourceRoot":"","sources":["../src/WebView.macos.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAkB1B,OAAO,EAOL,iBAAiB,EACjB,kBAAkB,EAElB,KAAK,EAEN,MAAM,gBAAgB,CAAC;AAcxB,cAAM,OAAQ,SAAQ,KAAK,CAAC,SAAS,CAAC,iBAAiB,EAAE,KAAK,CAAC;IAC7D,MAAM,CAAC,YAAY;;;;;MAKjB;IAEF,MAAM,CAAC,qBAAqB,yBAG1B;IAEF,KAAK,EAAE,KAAK,CAGV;IAEF,UAAU,sCAAyC;IAGnD,WAAW;;;;;;;;;MAA+D;IAE1E;;OAEG;IACH,SAAS,aAMP;IAEF;;OAEG;IACH,MAAM,aAMJ;IAEF;;OAEG;IACH,MAAM,aAOJ;IAEF;;OAEG;IACH,WAAW,aAMT;IAEF;;OAEG;IACH,YAAY,aAMV;IAEF;;;;;;;;;OASG;IACH,WAAW,yBAMT;IAEF;;;;;OAKG;IACH,gBAAgB,yBAMd;IAEF;;;OAGG;IACH,qBAAqB,2GAInB;IAEF;;OAEG;IACH,gBAAgB,eAId;IAEF,cAAc,2GAMZ;IAEF,cAAc,sGAeZ;IAEF,WAAW,0GAKV;IAED,eAAe,2GAYb;IAEF,SAAS,wGAKP;IAEF,iBAAiB,oHAKf;IAEF,oCAAoC,uEAUlC;IAEF,4BAA4B,4GAK1B;IAEF,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAM/C,uBAAuB,CACrB,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,iBAAiB;IASnC,MAAM;CA0EP;AAED,eAAe,OAAO,CAAC"} \ No newline at end of file diff --git a/lib/WebView.macos.js b/lib/WebView.macos.js new file mode 100644 index 0000000..6f59edf --- /dev/null +++ b/lib/WebView.macos.js @@ -0,0 +1,270 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +import React from 'react'; +import { UIManager as NotTypedUIManager, View, requireNativeComponent, NativeModules, Image, findNodeHandle, } from 'react-native'; +import invariant from 'invariant'; +import { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderError, defaultRenderLoading, } from './WebViewShared'; +import styles from './WebView.styles'; +var UIManager = NotTypedUIManager; +var resolveAssetSource = Image.resolveAssetSource; +var RNCWebViewManager = NativeModules.RNCWebViewManager; +var RNCWebView = requireNativeComponent('RNCWebView'); +var WebView = /** @class */ (function (_super) { + __extends(WebView, _super); + function WebView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.state = { + viewState: _this.props.startInLoadingState ? 'LOADING' : 'IDLE', + lastErrorEvent: null + }; + _this.webViewRef = React.createRef(); + // eslint-disable-next-line react/sort-comp + _this.getCommands = function () { return UIManager.getViewManagerConfig('RNCWebView').Commands; }; + /** + * Go forward one page in the web view's history. + */ + _this.goForward = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().goForward, undefined); + }; + /** + * Go back one page in the web view's history. + */ + _this.goBack = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().goBack, undefined); + }; + /** + * Reloads the current page. + */ + _this.reload = function () { + _this.setState({ viewState: 'LOADING' }); + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().reload, undefined); + }; + /** + * Stop loading the current page. + */ + _this.stopLoading = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().stopLoading, undefined); + }; + /** + * Request focus on WebView rendered page. + */ + _this.requestFocus = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().requestFocus, undefined); + }; + /** + * Posts a message to the web view, which will emit a `message` event. + * Accepts one argument, `data`, which must be a string. + * + * In your webview, you'll need to something like the following. + * + * ```js + * document.addEventListener('message', e => { document.title = e.data; }); + * ``` + */ + _this.postMessage = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().postMessage, [String(data)]); + }; + /** + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + _this.injectJavaScript = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), _this.getCommands().injectJavaScript, [data]); + }; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + _this.updateNavigationState = function (event) { + if (_this.props.onNavigationStateChange) { + _this.props.onNavigationStateChange(event.nativeEvent); + } + }; + /** + * Returns the native `WebView` node. + */ + _this.getWebViewHandle = function () { + var nodeHandle = findNodeHandle(_this.webViewRef.current); + invariant(nodeHandle != null, 'nodeHandle expected to be non-null'); + return nodeHandle; + }; + _this.onLoadingStart = function (event) { + var onLoadStart = _this.props.onLoadStart; + if (onLoadStart) { + onLoadStart(event); + } + _this.updateNavigationState(event); + }; + _this.onLoadingError = function (event) { + event.persist(); // persist this event because we need to store it + var _a = _this.props, onError = _a.onError, onLoadEnd = _a.onLoadEnd; + if (onLoadEnd) { + onLoadEnd(event); + } + if (onError) { + onError(event); + } + console.warn('Encountered an error loading page', event.nativeEvent); + _this.setState({ + lastErrorEvent: event.nativeEvent, + viewState: 'ERROR' + }); + }; + _this.onHttpError = function (event) { + var onHttpError = _this.props.onHttpError; + if (onHttpError) { + onHttpError(event); + } + }; + _this.onLoadingFinish = function (event) { + var _a = _this.props, onLoad = _a.onLoad, onLoadEnd = _a.onLoadEnd; + if (onLoad) { + onLoad(event); + } + if (onLoadEnd) { + onLoadEnd(event); + } + _this.setState({ + viewState: 'IDLE' + }); + _this.updateNavigationState(event); + }; + _this.onMessage = function (event) { + var onMessage = _this.props.onMessage; + if (onMessage) { + onMessage(event); + } + }; + _this.onLoadingProgress = function (event) { + var onLoadProgress = _this.props.onLoadProgress; + if (onLoadProgress) { + onLoadProgress(event); + } + }; + _this.onShouldStartLoadWithRequestCallback = function (shouldStart, _url, lockIdentifier) { + var viewManager = (_this.props.nativeConfig && _this.props.nativeConfig.viewManager) + || RNCWebViewManager; + viewManager.startLoadWithResult(!!shouldStart, lockIdentifier); + }; + _this.onContentProcessDidTerminate = function (event) { + var onContentProcessDidTerminate = _this.props.onContentProcessDidTerminate; + if (onContentProcessDidTerminate) { + onContentProcessDidTerminate(event); + } + }; + return _this; + } + WebView.prototype.componentDidUpdate = function (prevProps) { + this.showRedboxOnPropChanges(prevProps, 'allowsInlineMediaPlayback'); + this.showRedboxOnPropChanges(prevProps, 'incognito'); + this.showRedboxOnPropChanges(prevProps, 'mediaPlaybackRequiresUserAction'); + }; + WebView.prototype.showRedboxOnPropChanges = function (prevProps, propName) { + if (this.props[propName] !== prevProps[propName]) { + console.error("Changes to property " + propName + " do nothing after the initial render."); + } + }; + WebView.prototype.render = function () { + var _a = this.props, _b = _a.nativeConfig, nativeConfig = _b === void 0 ? {} : _b, onMessage = _a.onMessage, onShouldStartLoadWithRequestProp = _a.onShouldStartLoadWithRequest, originWhitelist = _a.originWhitelist, renderError = _a.renderError, renderLoading = _a.renderLoading, style = _a.style, containerStyle = _a.containerStyle, otherProps = __rest(_a, ["nativeConfig", "onMessage", "onShouldStartLoadWithRequest", "originWhitelist", "renderError", "renderLoading", "style", "containerStyle"]); + var otherView = null; + if (this.state.viewState === 'LOADING') { + otherView = (renderLoading || defaultRenderLoading)(); + } + else if (this.state.viewState === 'ERROR') { + var errorEvent = this.state.lastErrorEvent; + invariant(errorEvent != null, 'lastErrorEvent expected to be non-null'); + otherView = (renderError || defaultRenderError)(errorEvent.domain, errorEvent.code, errorEvent.description); + } + else if (this.state.viewState !== 'IDLE') { + console.error("RNCWebView invalid state encountered: " + this.state.viewState); + } + var webViewStyles = [styles.container, styles.webView, style]; + var webViewContainerStyle = [styles.container, containerStyle]; + var onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(this.onShouldStartLoadWithRequestCallback, + // casting cause it's in the default props + originWhitelist, onShouldStartLoadWithRequestProp); + var NativeWebView = nativeConfig.component + || RNCWebView; + var webView = (); + return ( + {webView} + {otherView} + ); + }; + WebView.defaultProps = { + javaScriptEnabled: true, + cacheEnabled: true, + originWhitelist: defaultOriginWhitelist, + useSharedProcessPool: true + }; + WebView.isFileUploadSupported = function () { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + // no native implementation for macOS, depends only on permissions + return [2 /*return*/, true]; + }); + }); }; + return WebView; +}(React.Component)); +export default WebView; diff --git a/lib/WebView.styles.d.ts b/lib/WebView.styles.d.ts new file mode 100644 index 0000000..de8574e --- /dev/null +++ b/lib/WebView.styles.d.ts @@ -0,0 +1,12 @@ +import { ViewStyle, TextStyle } from 'react-native'; +interface Styles { + container: ViewStyle; + errorText: TextStyle; + errorTextTitle: TextStyle; + loadingOrErrorView: ViewStyle; + webView: ViewStyle; + loadingProgressBar: ViewStyle; +} +declare const styles: Styles; +export default styles; +//# sourceMappingURL=WebView.styles.d.ts.map \ No newline at end of file diff --git a/lib/WebView.styles.d.ts.map b/lib/WebView.styles.d.ts.map new file mode 100644 index 0000000..98f6a34 --- /dev/null +++ b/lib/WebView.styles.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebView.styles.d.ts","sourceRoot":"","sources":["../src/WebView.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEhE,UAAU,MAAM;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,SAAS,CAAC;IAC1B,kBAAkB,EAAE,SAAS,CAAC;IAC9B,OAAO,EAAE,SAAS,CAAC;IACnB,kBAAkB,EAAE,SAAS,CAAC;CAC/B;AAED,QAAA,MAAM,MAAM,QA8BV,CAAC;AAEH,eAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/WebView.styles.js b/lib/WebView.styles.js new file mode 100644 index 0000000..de2d08d --- /dev/null +++ b/lib/WebView.styles.js @@ -0,0 +1,33 @@ +import { StyleSheet } from 'react-native'; +var styles = StyleSheet.create({ + container: { + flex: 1, + overflow: 'hidden' + }, + loadingOrErrorView: { + position: 'absolute', + flex: 1, + justifyContent: 'center', + alignItems: 'center', + height: '100%', + width: '100%', + backgroundColor: 'white' + }, + loadingProgressBar: { + height: 20 + }, + errorText: { + fontSize: 14, + textAlign: 'center', + marginBottom: 2 + }, + errorTextTitle: { + fontSize: 15, + fontWeight: '500', + marginBottom: 10 + }, + webView: { + backgroundColor: '#ffffff' + } +}); +export default styles; diff --git a/lib/WebView.windows.d.ts b/lib/WebView.windows.d.ts new file mode 100644 index 0000000..227fcdc --- /dev/null +++ b/lib/WebView.windows.d.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * Portions copyright for react-native-windows: + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ +import React from 'react'; +import { NativeWebViewWindows, WebViewSharedProps, State } from './WebViewTypes'; +export default class WebView extends React.Component { + static defaultProps: { + javaScriptEnabled: boolean; + }; + state: State; + webViewRef: React.RefObject; + goForward: () => void; + goBack: () => void; + reload: () => void; + injectJavaScript: (data: string) => void; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + updateNavigationState: (event: import("react-native").NativeSyntheticEvent) => void; + getWebViewHandle: () => number | null; + onLoadingStart: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingProgress: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingError: (event: import("react-native").NativeSyntheticEvent) => void; + onLoadingFinish: (event: import("react-native").NativeSyntheticEvent) => void; + onMessage: (event: import("react-native").NativeSyntheticEvent) => void; + onHttpError: (event: import("react-native").NativeSyntheticEvent) => void; + render(): JSX.Element; +} +//# sourceMappingURL=WebView.windows.d.ts.map \ No newline at end of file diff --git a/lib/WebView.windows.d.ts.map b/lib/WebView.windows.d.ts.map new file mode 100644 index 0000000..0a64fc8 --- /dev/null +++ b/lib/WebView.windows.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebView.windows.d.ts","sourceRoot":"","sources":["../src/WebView.windows.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAOlB,KAAK,EACN,MAAM,gBAAgB,CAAC;AA0BxB,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,KAAK,CAAC;IAE7E,MAAM,CAAC,YAAY;;MAEjB;IAEF,KAAK,EAAE,KAAK,CAGX;IAED,UAAU,wCAA2C;IAErD,SAAS,aAMR;IAED,MAAM,aAML;IAED,MAAM,aAML;IAED,gBAAgB,yBAMf;IAED;;;OAGG;IACH,qBAAqB,2GAIpB;IAED,gBAAgB,sBAGf;IAED,cAAc,2GAMb;IAED,iBAAiB,oHAKf;IAEF,cAAc,sGAcb;IAED,eAAe,2GAYd;IAED,SAAS,wGAKR;IAED,WAAW,0GAKV;IAED,MAAM;CA6EP"} \ No newline at end of file diff --git a/lib/WebView.windows.js b/lib/WebView.windows.js new file mode 100644 index 0000000..0bf399b --- /dev/null +++ b/lib/WebView.windows.js @@ -0,0 +1,184 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * Portions copyright for react-native-windows: + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +import React from 'react'; +import { UIManager as NotTypedUIManager, View, requireNativeComponent, StyleSheet, Image, findNodeHandle, } from 'react-native'; +import { createOnShouldStartLoadWithRequest, } from './WebViewShared'; +var UIManager = NotTypedUIManager; +var resolveAssetSource = Image.resolveAssetSource; +var RCTWebView = requireNativeComponent('RCTWebView'); +var styles = StyleSheet.create({ + container: { + flex: 1 + }, + hidden: { + height: 0, + flex: 0 + }, + loadingView: { + flex: 1, + justifyContent: 'center', + alignItems: 'center' + }, + loadingProgressBar: { + height: 20 + } +}); +var WebView = /** @class */ (function (_super) { + __extends(WebView, _super); + function WebView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.state = { + viewState: _this.props.startInLoadingState ? 'LOADING' : 'IDLE', + lastErrorEvent: null + }; + _this.webViewRef = React.createRef(); + _this.goForward = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), UIManager.getViewManagerConfig('RCTWebView').Commands.goForward, undefined); + }; + _this.goBack = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), UIManager.getViewManagerConfig('RCTWebView').Commands.goBack, undefined); + }; + _this.reload = function () { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), UIManager.getViewManagerConfig('RCTWebView').Commands.reload, undefined); + }; + _this.injectJavaScript = function (data) { + UIManager.dispatchViewManagerCommand(_this.getWebViewHandle(), UIManager.getViewManagerConfig('RCTWebView').Commands.injectJavaScript, [data]); + }; + /** + * We return an event with a bunch of fields including: + * url, title, loading, canGoBack, canGoForward + */ + _this.updateNavigationState = function (event) { + if (_this.props.onNavigationStateChange) { + _this.props.onNavigationStateChange(event.nativeEvent); + } + }; + _this.getWebViewHandle = function () { + // eslint-disable-next-line react/no-string-refs + return findNodeHandle(_this.webViewRef.current); + }; + _this.onLoadingStart = function (event) { + var onLoadStart = _this.props.onLoadStart; + if (onLoadStart) { + onLoadStart(event); + } + _this.updateNavigationState(event); + }; + _this.onLoadingProgress = function (event) { + var onLoadProgress = _this.props.onLoadProgress; + if (onLoadProgress) { + onLoadProgress(event); + } + }; + _this.onLoadingError = function (event) { + event.persist(); // persist this event because we need to store it + var _a = _this.props, onError = _a.onError, onLoadEnd = _a.onLoadEnd; + if (onError) { + onError(event); + } + if (onLoadEnd) { + onLoadEnd(event); + } + console.error('Encountered an error loading page', event.nativeEvent); + _this.setState({ + lastErrorEvent: event.nativeEvent, + viewState: 'ERROR' + }); + }; + _this.onLoadingFinish = function (event) { + var _a = _this.props, onLoad = _a.onLoad, onLoadEnd = _a.onLoadEnd; + if (onLoad) { + onLoad(event); + } + if (onLoadEnd) { + onLoadEnd(event); + } + _this.setState({ + viewState: 'IDLE' + }); + _this.updateNavigationState(event); + }; + _this.onMessage = function (event) { + var onMessage = _this.props.onMessage; + if (onMessage) { + onMessage(event); + } + }; + _this.onHttpError = function (event) { + var onHttpError = _this.props.onHttpError; + if (onHttpError) { + onHttpError(event); + } + }; + return _this; + } + WebView.prototype.render = function () { + var _a = this.props, _b = _a.nativeConfig, nativeConfig = _b === void 0 ? {} : _b, onMessage = _a.onMessage, onShouldStartLoadWithRequestProp = _a.onShouldStartLoadWithRequest, originWhitelist = _a.originWhitelist, renderError = _a.renderError, renderLoading = _a.renderLoading, style = _a.style, containerStyle = _a.containerStyle, otherProps = __rest(_a, ["nativeConfig", "onMessage", "onShouldStartLoadWithRequest", "originWhitelist", "renderError", "renderLoading", "style", "containerStyle"]); + var otherView = null; + if (this.state.viewState === 'LOADING') { + otherView = this.props.renderLoading && this.props.renderLoading(); + } + else if (this.state.viewState === 'ERROR') { + var errorEvent = this.state.lastErrorEvent; + otherView = this.props.renderError + && this.props.renderError(errorEvent.domain, errorEvent.code, errorEvent.description); + } + else if (this.state.viewState !== 'IDLE') { + console.error('RCTWebView invalid state encountered: ', this.state.viewState); + } + var webViewStyles = [styles.container, this.props.style]; + if (this.state.viewState === 'LOADING' + || this.state.viewState === 'ERROR') { + // if we're in either LOADING or ERROR states, don't show the webView + webViewStyles.push(styles.hidden); + } + var onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(function () { }, + // casting cause it's in the default props + originWhitelist, onShouldStartLoadWithRequestProp); + var NativeWebView = nativeConfig.component + || RCTWebView; + var webView = (); + return ( + {webView} + {otherView} + ); + }; + WebView.defaultProps = { + javaScriptEnabled: true + }; + return WebView; +}(React.Component)); +export default WebView; diff --git a/lib/WebViewShared.d.ts b/lib/WebViewShared.d.ts new file mode 100644 index 0000000..7aa1a14 --- /dev/null +++ b/lib/WebViewShared.d.ts @@ -0,0 +1,7 @@ +import { OnShouldStartLoadWithRequest } from './WebViewTypes'; +declare const defaultOriginWhitelist: string[]; +declare const createOnShouldStartLoadWithRequest: (loadRequest: (shouldStart: boolean, url: string, lockIdentifier: number) => void, originWhitelist: readonly string[], onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest | undefined) => ({ nativeEvent }: import("react-native").NativeSyntheticEvent) => void; +declare const defaultRenderLoading: () => JSX.Element; +declare const defaultRenderError: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => JSX.Element; +export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, }; +//# sourceMappingURL=WebViewShared.d.ts.map \ No newline at end of file diff --git a/lib/WebViewShared.d.ts.map b/lib/WebViewShared.d.ts.map new file mode 100644 index 0000000..43a974a --- /dev/null +++ b/lib/WebViewShared.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebViewShared.d.ts","sourceRoot":"","sources":["../src/WebViewShared.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,4BAA4B,EAC7B,MAAM,gBAAgB,CAAC;AAGxB,QAAA,MAAM,sBAAsB,UAA4B,CAAC;AAuBzD,QAAA,MAAM,kCAAkC,uTA8BvC,CAAC;AAEF,QAAA,MAAM,oBAAoB,mBAIzB,CAAC;AACF,QAAA,MAAM,kBAAkB,wFAWvB,CAAC;AAEF,OAAO,EACL,sBAAsB,EACtB,kCAAkC,EAClC,oBAAoB,EACpB,kBAAkB,GACnB,CAAC"} \ No newline at end of file diff --git a/lib/WebViewShared.js b/lib/WebViewShared.js new file mode 100644 index 0000000..893d48e --- /dev/null +++ b/lib/WebViewShared.js @@ -0,0 +1,59 @@ +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +import escapeStringRegexp from 'escape-string-regexp'; +import React from 'react'; +import { Linking, View, ActivityIndicator, Text } from 'react-native'; +import styles from './WebView.styles'; +var defaultOriginWhitelist = ['http://*', 'https://*']; +var extractOrigin = function (url) { + var result = /^[A-Za-z][A-Za-z0-9+\-.]+:(\/\/)?[^/]*/.exec(url); + return result === null ? '' : result[0]; +}; +var originWhitelistToRegex = function (originWhitelist) { + return "^" + escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*'); +}; +var passesWhitelist = function (compiledWhitelist, url) { + var origin = extractOrigin(url); + return compiledWhitelist.some(function (x) { return new RegExp(x).test(origin); }); +}; +var compileWhitelist = function (originWhitelist) { + return __spreadArrays(['about:blank'], (originWhitelist || [])).map(originWhitelistToRegex); +}; +var createOnShouldStartLoadWithRequest = function (loadRequest, originWhitelist, onShouldStartLoadWithRequest) { + return function (_a) { + var nativeEvent = _a.nativeEvent; + var shouldStart = true; + var url = nativeEvent.url, lockIdentifier = nativeEvent.lockIdentifier; + if (!passesWhitelist(compileWhitelist(originWhitelist), url)) { + Linking.canOpenURL(url).then(function (supported) { + if (supported) { + return Linking.openURL(url); + } + console.warn("Can't open url: " + url); + return undefined; + })["catch"](function (e) { + console.warn('Error opening URL: ', e); + }); + shouldStart = false; + } + else if (onShouldStartLoadWithRequest) { + shouldStart = onShouldStartLoadWithRequest(nativeEvent); + } + loadRequest(shouldStart, url, lockIdentifier); + }; +}; +var defaultRenderLoading = function () { return ( + + ); }; +var defaultRenderError = function (errorDomain, errorCode, errorDesc) { return ( + Error loading page + {"Domain: " + errorDomain} + {"Error Code: " + errorCode} + {"Description: " + errorDesc} + ); }; +export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, }; diff --git a/lib/WebViewTypes.d.ts b/lib/WebViewTypes.d.ts new file mode 100644 index 0000000..a31cbc1 --- /dev/null +++ b/lib/WebViewTypes.d.ts @@ -0,0 +1,785 @@ +import { ReactElement, Component } from 'react'; +import { NativeSyntheticEvent, ViewProps, StyleProp, ViewStyle, NativeMethodsMixin, Constructor, UIManagerStatic, NativeScrollEvent } from 'react-native'; +declare type WebViewCommands = 'goForward' | 'goBack' | 'reload' | 'stopLoading' | 'postMessage' | 'injectJavaScript' | 'loadUrl' | 'requestFocus'; +declare type AndroidWebViewCommands = 'clearHistory' | 'clearCache' | 'clearFormData'; +interface RNCWebViewUIManager extends UIManagerStatic { + getViewManagerConfig: (name: string) => { + Commands: { + [key in Commands]: number; + }; + }; +} +export declare type RNCWebViewUIManagerAndroid = RNCWebViewUIManager; +export declare type RNCWebViewUIManagerIOS = RNCWebViewUIManager; +export declare type RNCWebViewUIManagerMacOS = RNCWebViewUIManager; +export declare type RNCWebViewUIManagerWindows = RNCWebViewUIManager; +declare type WebViewState = 'IDLE' | 'LOADING' | 'ERROR'; +interface BaseState { + viewState: WebViewState; +} +interface NormalState extends BaseState { + viewState: 'IDLE' | 'LOADING'; + lastErrorEvent: WebViewError | null; +} +interface ErrorState extends BaseState { + viewState: 'ERROR'; + lastErrorEvent: WebViewError; +} +export declare type State = NormalState | ErrorState; +declare class NativeWebViewIOSComponent extends Component { +} +declare const NativeWebViewIOSBase: Constructor & typeof NativeWebViewIOSComponent; +export declare class NativeWebViewIOS extends NativeWebViewIOSBase { +} +declare class NativeWebViewMacOSComponent extends Component { +} +declare const NativeWebViewMacOSBase: Constructor & typeof NativeWebViewMacOSComponent; +export declare class NativeWebViewMacOS extends NativeWebViewMacOSBase { +} +declare class NativeWebViewAndroidComponent extends Component { +} +declare const NativeWebViewAndroidBase: Constructor & typeof NativeWebViewAndroidComponent; +export declare class NativeWebViewAndroid extends NativeWebViewAndroidBase { +} +declare class NativeWebViewWindowsComponent extends Component { +} +declare const NativeWebViewWindowsBase: Constructor & typeof NativeWebViewWindowsComponent; +export declare class NativeWebViewWindows extends NativeWebViewWindowsBase { +} +export interface ContentInsetProp { + top?: number; + left?: number; + bottom?: number; + right?: number; +} +export interface WebViewNativeEvent { + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: number; +} +export interface WebViewNativeProgressEvent extends WebViewNativeEvent { + progress: number; +} +export interface WebViewNavigation extends WebViewNativeEvent { + navigationType: 'click' | 'formsubmit' | 'backforward' | 'reload' | 'formresubmit' | 'other'; + mainDocumentURL?: string; +} +export interface FileDownload { + downloadUrl: string; +} +export declare type DecelerationRateConstant = 'normal' | 'fast'; +export interface WebViewMessage extends WebViewNativeEvent { + data: string; +} +export interface WebViewError extends WebViewNativeEvent { + /** + * `domain` is only used on iOS and macOS + */ + domain?: string; + code: number; + description: string; +} +export interface WebViewHttpError extends WebViewNativeEvent { + description: string; + statusCode: number; +} +export declare type WebViewEvent = NativeSyntheticEvent; +export declare type WebViewProgressEvent = NativeSyntheticEvent; +export declare type WebViewNavigationEvent = NativeSyntheticEvent; +export declare type FileDownloadEvent = NativeSyntheticEvent; +export declare type WebViewMessageEvent = NativeSyntheticEvent; +export declare type WebViewErrorEvent = NativeSyntheticEvent; +export declare type WebViewTerminatedEvent = NativeSyntheticEvent; +export declare type WebViewHttpErrorEvent = NativeSyntheticEvent; +export declare type DataDetectorTypes = 'phoneNumber' | 'link' | 'address' | 'calendarEvent' | 'trackingNumber' | 'flightNumber' | 'lookupSuggestion' | 'none' | 'all'; +export declare type OverScrollModeType = 'always' | 'content' | 'never'; +export declare type CacheMode = 'LOAD_DEFAULT' | 'LOAD_CACHE_ONLY' | 'LOAD_CACHE_ELSE_NETWORK' | 'LOAD_NO_CACHE'; +export interface WebViewSourceUri { + /** + * The URI to load in the `WebView`. Can be a local or remote file. + */ + uri: string; + /** + * The HTTP Method to use. Defaults to GET if not specified. + * NOTE: On Android, only GET and POST are supported. + */ + method?: string; + /** + * Additional HTTP headers to send with the request. + * NOTE: On Android, this can only be used with GET requests. + */ + headers?: Object; + /** + * The HTTP body to send with the request. This must be a valid + * UTF-8 string, and will be sent exactly as specified, with no + * additional encoding (e.g. URL-escaping or base64) applied. + * NOTE: On Android, this can only be used with POST requests. + */ + body?: string; +} +export interface WebViewSourceHtml { + /** + * A static HTML page to display in the WebView. + */ + html: string; + /** + * The base URL to be used for any relative links in the HTML. + */ + baseUrl?: string; +} +export declare type WebViewSource = WebViewSourceUri | WebViewSourceHtml; +export interface ViewManager { + startLoadWithResult: Function; +} +export interface WebViewNativeConfig { + /** + * The native component used to render the WebView. + */ + component?: typeof NativeWebViewIOS | typeof NativeWebViewMacOS | typeof NativeWebViewAndroid; + /** + * Set props directly on the native component WebView. Enables custom props which the + * original WebView doesn't pass through. + */ + props?: Object; + /** + * Set the ViewManager to use for communication with the native side. + * @platform ios, macos + */ + viewManager?: ViewManager; +} +export declare type OnShouldStartLoadWithRequest = (event: WebViewNavigation) => boolean; +export interface CommonNativeWebViewProps extends ViewProps { + cacheEnabled?: boolean; + incognito?: boolean; + injectedJavaScript?: string; + injectedJavaScriptBeforeContentLoaded?: string; + mediaPlaybackRequiresUserAction?: boolean; + messagingEnabled: boolean; + onScroll?: (event: NativeScrollEvent) => void; + onLoadingError: (event: WebViewErrorEvent) => void; + onLoadingFinish: (event: WebViewNavigationEvent) => void; + onLoadingProgress: (event: WebViewProgressEvent) => void; + onLoadingStart: (event: WebViewNavigationEvent) => void; + onHttpError: (event: WebViewHttpErrorEvent) => void; + onMessage: (event: WebViewMessageEvent) => void; + onShouldStartLoadWithRequest: (event: WebViewNavigationEvent) => void; + showsHorizontalScrollIndicator?: boolean; + showsVerticalScrollIndicator?: boolean; + source: any; + userAgent?: string; + /** + * Append to the existing user-agent. Overriden if `userAgent` is set. + */ + applicationNameForUserAgent?: string; +} +export interface AndroidNativeWebViewProps extends CommonNativeWebViewProps { + cacheMode?: CacheMode; + allowFileAccess?: boolean; + scalesPageToFit?: boolean; + allowFileAccessFromFileURLs?: boolean; + allowUniversalAccessFromFileURLs?: boolean; + androidHardwareAccelerationDisabled?: boolean; + domStorageEnabled?: boolean; + geolocationEnabled?: boolean; + javaScriptEnabled?: boolean; + mixedContentMode?: 'never' | 'always' | 'compatibility'; + onContentSizeChange?: (event: WebViewEvent) => void; + overScrollMode?: OverScrollModeType; + saveFormDataDisabled?: boolean; + textZoom?: number; + thirdPartyCookiesEnabled?: boolean; + messagingModuleName?: string; + readonly urlPrefixesForDefaultIntent?: string[]; +} +export declare enum ContentInsetAdjustmentBehavior { + automatic = "automatic", + scrollableAxes = "scrollableAxes", + never = "never", + always = "always" +} +export interface IOSNativeWebViewProps extends CommonNativeWebViewProps { + allowingReadAccessToURL?: string; + allowsBackForwardNavigationGestures?: boolean; + allowsInlineMediaPlayback?: boolean; + allowsLinkPreview?: boolean; + automaticallyAdjustContentInsets?: boolean; + bounces?: boolean; + contentInset?: ContentInsetProp; + contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior; + readonly dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[]; + decelerationRate?: number; + directionalLockEnabled?: boolean; + hideKeyboardAccessoryView?: boolean; + pagingEnabled?: boolean; + scrollEnabled?: boolean; + useSharedProcessPool?: boolean; + onContentProcessDidTerminate?: (event: WebViewTerminatedEvent) => void; + injectedJavaScriptForMainFrameOnly?: boolean; + injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean; + onFileDownload?: (event: FileDownloadEvent) => void; +} +export interface MacOSNativeWebViewProps extends CommonNativeWebViewProps { + allowingReadAccessToURL?: string; + allowsBackForwardNavigationGestures?: boolean; + allowsInlineMediaPlayback?: boolean; + allowsLinkPreview?: boolean; + automaticallyAdjustContentInsets?: boolean; + bounces?: boolean; + contentInset?: ContentInsetProp; + contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior; + directionalLockEnabled?: boolean; + hideKeyboardAccessoryView?: boolean; + pagingEnabled?: boolean; + scrollEnabled?: boolean; + useSharedProcessPool?: boolean; + onContentProcessDidTerminate?: (event: WebViewTerminatedEvent) => void; +} +export interface WindowsNativeWebViewProps extends CommonNativeWebViewProps { + testID?: string; +} +export interface IOSWebViewProps extends WebViewSharedProps { + /** + * Does not store any data within the lifetime of the WebView. + */ + incognito?: boolean; + /** + * Boolean value that determines whether the web view bounces + * when it reaches the edge of the content. The default value is `true`. + * @platform ios + */ + bounces?: boolean; + /** + * A floating-point number that determines how quickly the scroll view + * decelerates after the user lifts their finger. You may also use the + * string shortcuts `"normal"` and `"fast"` which match the underlying iOS + * settings for `UIScrollViewDecelerationRateNormal` and + * `UIScrollViewDecelerationRateFast` respectively: + * + * - normal: 0.998 + * - fast: 0.99 (the default for iOS web view) + * @platform ios + */ + decelerationRate?: DecelerationRateConstant | number; + /** + * Boolean value that determines whether scrolling is enabled in the + * `WebView`. The default value is `true`. + * @platform ios + */ + scrollEnabled?: boolean; + /** + * If the value of this property is true, the scroll view stops on multiples + * of the scroll view’s bounds when the user scrolls. + * The default value is false. + * @platform ios + */ + pagingEnabled?: boolean; + /** + * Controls whether to adjust the content inset for web views that are + * placed behind a navigation bar, tab bar, or toolbar. The default value + * is `true`. + * @platform ios + */ + automaticallyAdjustContentInsets?: boolean; + /** + * This property specifies how the safe area insets are used to modify the + * content area of the scroll view. The default value of this property is + * "never". Available on iOS 11 and later. + */ + contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior; + /** + * The amount by which the web view content is inset from the edges of + * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}. + * @platform ios + */ + contentInset?: ContentInsetProp; + /** + * Determines the types of data converted to clickable URLs in the web view's content. + * By default only phone numbers are detected. + * + * You can provide one type or an array of many types. + * + * Possible values for `dataDetectorTypes` are: + * + * - `'phoneNumber'` + * - `'link'` + * - `'address'` + * - `'calendarEvent'` + * - `'none'` + * - `'all'` + * + * With the new WebKit implementation, we have three new values: + * - `'trackingNumber'`, + * - `'flightNumber'`, + * - `'lookupSuggestion'`, + * + * @platform ios + */ + readonly dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[]; + /** + * Boolean that determines whether HTML5 videos play inline or use the + * native full-screen controller. The default value is `false`. + * + * **NOTE** : In order for video to play inline, not only does this + * property need to be set to `true`, but the video element in the HTML + * document must also include the `webkit-playsinline` attribute. + * @platform ios + */ + allowsInlineMediaPlayback?: boolean; + /** + * Hide the accessory view when the keyboard is open. Default is false to be + * backward compatible. + */ + hideKeyboardAccessoryView?: boolean; + /** + * A Boolean value indicating whether horizontal swipe gestures will trigger + * back-forward list navigations. + */ + allowsBackForwardNavigationGestures?: boolean; + /** + * A Boolean value indicating whether WebKit WebView should be created using a shared + * process pool, enabling WebViews to share cookies and localStorage between each other. + * Default is true but can be set to false for backwards compatibility. + * @platform ios + */ + useSharedProcessPool?: boolean; + /** + * The custom user agent string. + */ + userAgent?: string; + /** + * A Boolean value that determines whether pressing on a link + * displays a preview of the destination for the link. + * + * This property is available on devices that support 3D Touch. + * In iOS 10 and later, the default value is `true`; before that, the default value is `false`. + * @platform ios + */ + allowsLinkPreview?: boolean; + /** + * Set true if shared cookies from HTTPCookieStorage should used for every load request. + * The default value is `false`. + * @platform ios + */ + sharedCookiesEnabled?: boolean; + /** + * A Boolean value that determines whether scrolling is disabled in a particular direction. + * The default value is `true`. + * @platform ios + */ + directionalLockEnabled?: boolean; + /** + * A Boolean value indicating whether web content can programmatically display the keyboard. + * + * When this property is set to true, the user must explicitly tap the elements in the + * web view to display the keyboard (or other relevant input view) for that element. + * When set to false, a focus event on an element causes the input view to be displayed + * and associated with that element automatically. + * + * The default value is `true`. + * @platform ios + */ + keyboardDisplayRequiresUserAction?: boolean; + /** + * A String value that indicates which URLs the WebView's file can then + * reference in scripts, AJAX requests, and CSS imports. This is only used + * for WebViews that are loaded with a source.uri set to a `'file://'` URL. + * + * If not provided, the default is to only allow read access to the URL + * provided in source.uri itself. + * @platform ios + */ + allowingReadAccessToURL?: string; + /** + * Function that is invoked when the WebKit WebView content process gets terminated. + * @platform ios + */ + onContentProcessDidTerminate?: (event: WebViewTerminatedEvent) => void; + /** + * If `true` (default), loads the `injectedJavaScript` only into the main frame. + * If `false`, loads it into all frames (e.g. iframes). + * @platform ios + */ + injectedJavaScriptForMainFrameOnly?: boolean; + /** + * If `true` (default), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame. + * If `false`, loads it into all frames (e.g. iframes). + * @platform ios + */ + injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean; + /** + * Function that is invoked when the client needs to download a file. + * + * iOS 13+ only: If the webview navigates to a URL that results in an HTTP + * response with a Content-Disposition header 'attachment...', then + * this will be called. + * + * iOS 8+: If the MIME type indicates that the content is not renderable by the + * webview, that will also cause this to be called. On iOS versions before 13, + * this is the only condition that will cause this function to be called. + * + * The application will need to provide its own code to actually download + * the file. + * + * If not provided, the default is to let the webview try to render the file. + */ + onFileDownload?: (event: FileDownloadEvent) => void; +} +export interface MacOSWebViewProps extends WebViewSharedProps { + /** + * Does not store any data within the lifetime of the WebView. + */ + incognito?: boolean; + /** + * Boolean value that determines whether the web view bounces + * when it reaches the edge of the content. The default value is `true`. + * @platform macos + */ + bounces?: boolean; + /** + * Boolean value that determines whether scrolling is enabled in the + * `WebView`. The default value is `true`. + * @platform macos + */ + scrollEnabled?: boolean; + /** + * If the value of this property is true, the scroll view stops on multiples + * of the scroll view’s bounds when the user scrolls. + * The default value is false. + * @platform macos + */ + pagingEnabled?: boolean; + /** + * Controls whether to adjust the content inset for web views that are + * placed behind a navigation bar, tab bar, or toolbar. The default value + * is `true`. + * @platform macos + */ + automaticallyAdjustContentInsets?: boolean; + /** + * This property specifies how the safe area insets are used to modify the + * content area of the scroll view. The default value of this property is + * "never". Available on iOS 11 and later. + */ + contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior; + /** + * The amount by which the web view content is inset from the edges of + * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}. + * @platform macos + */ + contentInset?: ContentInsetProp; + /** + * Boolean that determines whether HTML5 videos play inline or use the + * native full-screen controller. The default value is `false`. + * + * **NOTE** : In order for video to play inline, not only does this + * property need to be set to `true`, but the video element in the HTML + * document must also include the `webkit-playsinline` attribute. + * @platform macos + */ + allowsInlineMediaPlayback?: boolean; + /** + * Hide the accessory view when the keyboard is open. Default is false to be + * backward compatible. + */ + hideKeyboardAccessoryView?: boolean; + /** + * A Boolean value indicating whether horizontal swipe gestures will trigger + * back-forward list navigations. + */ + allowsBackForwardNavigationGestures?: boolean; + /** + * A Boolean value indicating whether WebKit WebView should be created using a shared + * process pool, enabling WebViews to share cookies and localStorage between each other. + * Default is true but can be set to false for backwards compatibility. + * @platform macos + */ + useSharedProcessPool?: boolean; + /** + * The custom user agent string. + */ + userAgent?: string; + /** + * A Boolean value that determines whether pressing on a link + * displays a preview of the destination for the link. + * + * This property is available on devices that support Force Touch trackpad. + * @platform macos + */ + allowsLinkPreview?: boolean; + /** + * Set true if shared cookies from HTTPCookieStorage should used for every load request. + * The default value is `false`. + * @platform macos + */ + sharedCookiesEnabled?: boolean; + /** + * A Boolean value that determines whether scrolling is disabled in a particular direction. + * The default value is `true`. + * @platform macos + */ + directionalLockEnabled?: boolean; + /** + * A Boolean value indicating whether web content can programmatically display the keyboard. + * + * When this property is set to true, the user must explicitly tap the elements in the + * web view to display the keyboard (or other relevant input view) for that element. + * When set to false, a focus event on an element causes the input view to be displayed + * and associated with that element automatically. + * + * The default value is `true`. + * @platform macos + */ + keyboardDisplayRequiresUserAction?: boolean; + /** + * A String value that indicates which URLs the WebView's file can then + * reference in scripts, AJAX requests, and CSS imports. This is only used + * for WebViews that are loaded with a source.uri set to a `'file://'` URL. + * + * If not provided, the default is to only allow read access to the URL + * provided in source.uri itself. + * @platform macos + */ + allowingReadAccessToURL?: string; + /** + * Function that is invoked when the WebKit WebView content process gets terminated. + * @platform macos + */ + onContentProcessDidTerminate?: (event: WebViewTerminatedEvent) => void; +} +export interface AndroidWebViewProps extends WebViewSharedProps { + onNavigationStateChange?: (event: WebViewNavigation) => void; + onContentSizeChange?: (event: WebViewEvent) => void; + /** + * https://developer.android.com/reference/android/webkit/WebSettings.html#setCacheMode(int) + * Set the cacheMode. Possible values are: + * + * - `'LOAD_DEFAULT'` (default) + * - `'LOAD_CACHE_ELSE_NETWORK'` + * - `'LOAD_NO_CACHE'` + * - `'LOAD_CACHE_ONLY'` + * + * @platform android + */ + cacheMode?: CacheMode; + /** + * https://developer.android.com/reference/android/view/View#OVER_SCROLL_NEVER + * Sets the overScrollMode. Possible values are: + * + * - `'always'` (default) + * - `'content'` + * - `'never'` + * + * @platform android + */ + overScrollMode?: OverScrollModeType; + /** + * Boolean that controls whether the web content is scaled to fit + * the view and enables the user to change the scale. The default value + * is `true`. + */ + scalesPageToFit?: boolean; + /** + * Sets whether Geolocation is enabled. The default is false. + * @platform android + */ + geolocationEnabled?: boolean; + /** + * Boolean that sets whether JavaScript running in the context of a file + * scheme URL should be allowed to access content from other file scheme URLs. + * Including accessing content from other file scheme URLs + * @platform android + */ + allowFileAccessFromFileURLs?: boolean; + /** + * Boolean that sets whether JavaScript running in the context of a file + * scheme URL should be allowed to access content from any origin. + * Including accessing content from other file scheme URLs + * @platform android + */ + allowUniversalAccessFromFileURLs?: boolean; + /** + * Sets whether the webview allow access to file system. + * @platform android + */ + allowFileAccess?: boolean; + /** + * Used on Android only, controls whether form autocomplete data should be saved + * @platform android + */ + saveFormDataDisabled?: boolean; + /** + * Used on Android only, controls whether the given list of URL prefixes should + * make {@link com.facebook.react.views.webview.ReactWebViewClient} to launch a + * default activity intent for those URL instead of loading it within the webview. + * Use this to list URLs that WebView cannot handle, e.g. a PDF url. + * @platform android + */ + readonly urlPrefixesForDefaultIntent?: string[]; + /** + * Boolean value to disable Hardware Acceleration in the `WebView`. Used on Android only + * as Hardware Acceleration is a feature only for Android. The default value is `false`. + * @platform android + */ + androidHardwareAccelerationDisabled?: boolean; + /** + * Boolean value to enable third party cookies in the `WebView`. Used on + * Android Lollipop and above only as third party cookies are enabled by + * default on Android Kitkat and below and on iOS. The default value is `true`. + * @platform android + */ + thirdPartyCookiesEnabled?: boolean; + /** + * Boolean value to control whether DOM Storage is enabled. Used only in + * Android. + * @platform android + */ + domStorageEnabled?: boolean; + /** + * Sets the user-agent for the `WebView`. + * @platform android + */ + userAgent?: string; + /** + * Sets number that controls text zoom of the page in percent. + * @platform android + */ + textZoom?: number; + /** + * Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin. + * + * Possible values for `mixedContentMode` are: + * + * - `'never'` (default) - WebView will not allow a secure origin to load content from an insecure origin. + * - `'always'` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure. + * - `'compatibility'` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content. + * @platform android + */ + mixedContentMode?: 'never' | 'always' | 'compatibility'; + /** + * Sets ability to open fullscreen videos on Android devices. + */ + allowsFullscreenVideo?: boolean; +} +export interface WebViewSharedProps extends ViewProps { + /** + * Loads static html or a uri (with optional headers) in the WebView. + */ + source?: WebViewSource; + /** + * Boolean value to enable JavaScript in the `WebView`. Used on Android only + * as JavaScript is enabled by default on iOS. The default value is `true`. + * @platform android + */ + javaScriptEnabled?: boolean; + /** + * Stylesheet object to set the style of the container view. + */ + containerStyle?: StyleProp; + /** + * Function that returns a view to show if there's an error. + */ + renderError?: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => ReactElement; + /** + * Function that returns a loading indicator. + */ + renderLoading?: () => ReactElement; + /** + * Function that is invoked when the `WebView` scrolls. + */ + onScroll?: (event: NativeScrollEvent) => void; + /** + * Function that is invoked when the `WebView` has finished loading. + */ + onLoad?: (event: WebViewNavigationEvent) => void; + /** + * Function that is invoked when the `WebView` load succeeds or fails. + */ + onLoadEnd?: (event: WebViewNavigationEvent | WebViewErrorEvent) => void; + /** + * Function that is invoked when the `WebView` starts loading. + */ + onLoadStart?: (event: WebViewNavigationEvent) => void; + /** + * Function that is invoked when the `WebView` load fails. + */ + onError?: (event: WebViewErrorEvent) => void; + /** + * Function that is invoked when the `WebView` receives an error status code. + * Works on iOS and Android (minimum API level 23). + */ + onHttpError?: (event: WebViewHttpErrorEvent) => void; + /** + * Function that is invoked when the `WebView` loading starts or ends. + */ + onNavigationStateChange?: (event: WebViewNavigation) => void; + /** + * Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`. + * Setting this property will inject this global into your webview. + * + * `window.ReactNativeWebView.postMessage` accepts one argument, `data`, which will be + * available on the event object, `event.nativeEvent.data`. `data` must be a string. + */ + onMessage?: (event: WebViewMessageEvent) => void; + /** + * Function that is invoked when the `WebView` is loading. + */ + onLoadProgress?: (event: WebViewProgressEvent) => void; + /** + * Boolean value that forces the `WebView` to show the loading view + * on the first load. + */ + startInLoadingState?: boolean; + /** + * Set this to provide JavaScript that will be injected into the web page + * when the view loads. + */ + injectedJavaScript?: string; + /** + * Set this to provide JavaScript that will be injected into the web page + * once the webview is initialized but before the view loads any content. + */ + injectedJavaScriptBeforeContentLoaded?: string; + /** + * Boolean value that determines whether a horizontal scroll indicator is + * shown in the `WebView`. The default value is `true`. + */ + showsHorizontalScrollIndicator?: boolean; + /** + * Boolean value that determines whether a vertical scroll indicator is + * shown in the `WebView`. The default value is `true`. + */ + showsVerticalScrollIndicator?: boolean; + /** + * Boolean that determines whether HTML5 audio and video requires the user + * to tap them before they start playing. The default value is `true`. + */ + mediaPlaybackRequiresUserAction?: boolean; + /** + * List of origin strings to allow being navigated to. The strings allow + * wildcards and get matched against *just* the origin (not the full URL). + * If the user taps to navigate to a new page but the new page is not in + * this whitelist, we will open the URL in Safari. + * The default whitelisted origins are "http://*" and "https://*". + */ + readonly originWhitelist?: string[]; + /** + * Function that allows custom handling of any web view requests. Return + * `true` from the function to continue loading the request and `false` + * to stop loading. The `navigationType` is always `other` on android. + */ + onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest; + /** + * Override the native component used to render the WebView. Enables a custom native + * WebView which uses the same JavaScript as the original WebView. + */ + nativeConfig?: WebViewNativeConfig; + /** + * Should caching be enabled. Default is true. + */ + cacheEnabled?: boolean; +} +export {}; +//# sourceMappingURL=WebViewTypes.d.ts.map \ No newline at end of file diff --git a/lib/WebViewTypes.d.ts.map b/lib/WebViewTypes.d.ts.map new file mode 100644 index 0000000..ab23484 --- /dev/null +++ b/lib/WebViewTypes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WebViewTypes.d.ts","sourceRoot":"","sources":["../src/WebViewTypes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAEtB,aAAK,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,GAAG,aAAa,GAAG,kBAAkB,GAAG,SAAS,GAAG,cAAc,CAAC;AAE3I,aAAK,sBAAsB,GAAG,cAAc,GAAG,YAAY,GAAG,eAAe,CAAC;AAI9E,UAAU,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAE,SAAQ,eAAe;IAC5E,oBAAoB,EAAE,CACpB,IAAI,EAAE,MAAM,KACT;QACH,QAAQ,EAAE;aAAE,GAAG,IAAI,QAAQ,GAAG,MAAM;SAAC,CAAC;KACvC,CAAC;CACH;AAED,oBAAY,0BAA0B,GAAG,mBAAmB,CAAC,eAAe,GAAG,sBAAsB,CAAC,CAAA;AACtG,oBAAY,sBAAsB,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAA;AACzE,oBAAY,wBAAwB,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAA;AAC3E,oBAAY,0BAA0B,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAA;AAG7E,aAAK,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjD,UAAU,SAAS;IACjB,SAAS,EAAE,YAAY,CAAC;CACzB;AAED,UAAU,WAAY,SAAQ,SAAS;IACrC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,cAAc,EAAE,YAAY,GAAG,IAAI,CAAC;CACrC;AAED,UAAU,UAAW,SAAQ,SAAS;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,YAAY,CAAC;CAC9B;AAED,oBAAY,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC;AAG7C,OAAO,OAAO,yBAA0B,SAAQ,SAAS,CACvD,qBAAqB,CACtB;CAAG;AACJ,OAAO,CAAC,MAAM,oBAAoB,EAAE,WAAW,CAAC,kBAAkB,CAAC,GACjE,OAAO,yBAAyB,CAAC;AACnC,qBAAa,gBAAiB,SAAQ,oBAAoB;CAAG;AAG7D,OAAO,OAAO,2BAA4B,SAAQ,SAAS,CACzD,uBAAuB,CACxB;CAAG;AACJ,OAAO,CAAC,MAAM,sBAAsB,EAAE,WAAW,CAAC,kBAAkB,CAAC,GACnE,OAAO,2BAA2B,CAAC;AACrC,qBAAa,kBAAmB,SAAQ,sBAAsB;CAAG;AAGjE,OAAO,OAAO,6BAA8B,SAAQ,SAAS,CAC3D,yBAAyB,CAC1B;CAAG;AACJ,OAAO,CAAC,MAAM,wBAAwB,EAAE,WAAW,CAAC,kBAAkB,CAAC,GACrE,OAAO,6BAA6B,CAAC;AACvC,qBAAa,oBAAqB,SAAQ,wBAAwB;CAAG;AAGrE,OAAO,OAAO,6BAA8B,SAAQ,SAAS,CAC3D,yBAAyB,CAC1B;CAAG;AACJ,OAAO,CAAC,MAAM,wBAAwB,EAAE,WAAW,CAAC,kBAAkB,CAAC,GACrE,OAAO,6BAA6B,CAAC;AACvC,qBAAa,oBAAqB,SAAQ,wBAAwB;CAAG;AAErE,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA2B,SAAQ,kBAAkB;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,cAAc,EACV,OAAO,GACP,YAAY,GACZ,aAAa,GACb,QAAQ,GACR,cAAc,GACd,OAAO,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,oBAAY,wBAAwB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,oBAAY,YAAY,GAAG,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;AAEpE,oBAAY,oBAAoB,GAAG,oBAAoB,CACrD,0BAA0B,CAC3B,CAAC;AAEF,oBAAY,sBAAsB,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;AAE7E,oBAAY,iBAAiB,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAC;AAEnE,oBAAY,mBAAmB,GAAG,oBAAoB,CAAC,cAAc,CAAC,CAAC;AAEvE,oBAAY,iBAAiB,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAC;AAEnE,oBAAY,sBAAsB,GAAG,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;AAE9E,oBAAY,qBAAqB,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;AAE3E,oBAAY,iBAAiB,GACzB,aAAa,GACb,MAAM,GACN,SAAS,GACT,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,kBAAkB,GAClB,MAAM,GACN,KAAK,CAAC;AAEV,oBAAY,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhE,oBAAY,SAAS,GAAG,cAAc,GAAG,iBAAiB,GAAG,yBAAyB,GAAG,eAAe,CAAC;AAEzG,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,oBAAY,aAAa,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,mBAAmB,EAAE,QAAQ,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,gBAAgB,GAAG,OAAO,kBAAkB,GAAG,OAAO,oBAAoB,CAAC;IAC9F;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,oBAAY,4BAA4B,GAAG,CACzC,KAAK,EAAE,iBAAiB,KACrB,OAAO,CAAC;AAEb,MAAM,WAAW,wBAAyB,SAAQ,SAAS;IACzD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC,CAAC,EAAE,MAAM,CAAC;IAC/C,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAC1C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,cAAc,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,eAAe,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACzD,iBAAiB,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACzD,cAAc,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACxD,WAAW,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACpD,SAAS,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChD,4BAA4B,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACtE,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IAGvC,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACzE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAC9C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,eAAe,CAAC;IACxD,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACpD,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,2BAA2B,CAAC,EAAE,MAAM,EAAE,CAAC;CACjD;AAED,oBAAY,8BAA8B;IACxC,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,KAAK,UAAU;IACf,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,qBAAsB,SAAQ,wBAAwB;IACrE,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAC9C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,8BAA8B,CAAC,EAAE,8BAA8B,CAAC;IAChE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,CAAC;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4BAA4B,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACvE,kCAAkC,CAAC,EAAE,OAAO,CAAC;IAC7C,qDAAqD,CAAC,EAAE,OAAO,CAAC;IAChE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAC9C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,8BAA8B,CAAC,EAAE,8BAA8B,CAAC;IAChE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4BAA4B,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC;IAErD;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;OAKG;IACH,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAE3C;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,8BAA8B,CAAC;IAEhE;;;;OAIG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAEhC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,CAAC;IAErE;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;OAGG;IACH,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAC9C;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;;;;;;OAUG;IACH,iCAAiC,CAAC,EAAE,OAAO,CAAC;IAE5C;;;;;;;;OAQG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,4BAA4B,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAEvE;;;;MAIE;IACF,kCAAkC,CAAC,EAAE,OAAO,CAAC;IAE7C;;;;MAIE;IACF,qDAAqD,CAAC,EAAE,OAAO,CAAC;IAEhE;;;;;;;;;;;;;;;OAeG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;OAKG;IACH,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAE3C;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,8BAA8B,CAAC;IAEhE;;;;OAIG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAEhC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;OAGG;IACH,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAC9C;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;;;;;;OAUG;IACH,iCAAiC,CAAC,EAAE,OAAO,CAAC;IAE5C;;;;;;;;OAQG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,4BAA4B,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC7D,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAEpD;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAEpC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAG7B;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;OAKG;IACH,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAE3C;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;;;OAMG;IACH,QAAQ,CAAC,2BAA2B,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhD;;;;OAIG;IACH,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAE9C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,eAAe,CAAC;IAExD;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IAEvB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEtC;;OAEG;IACH,WAAW,CAAC,EAAE,CACZ,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,KACd,YAAY,CAAC;IAElB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,YAAY,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAE9C;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAEjD;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,GAAG,iBAAiB,KAAK,IAAI,CAAC;IAExE;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAEtD;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAE7C;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAErD;;OAEG;IACH,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAE7D;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAEjD;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAEvD;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;OAGG;IACH,qCAAqC,CAAC,EAAE,MAAM,CAAC;IAE/C;;;OAGG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAEzC;;;OAGG;IACH,4BAA4B,CAAC,EAAE,OAAO,CAAC;IAEvC;;;OAGG;IACH,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAE1C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpC;;;;OAIG;IACH,4BAA4B,CAAC,EAAE,4BAA4B,CAAC;IAE5D;;;OAGG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB"} \ No newline at end of file diff --git a/lib/WebViewTypes.js b/lib/WebViewTypes.js new file mode 100644 index 0000000..8b83a9c --- /dev/null +++ b/lib/WebViewTypes.js @@ -0,0 +1,55 @@ +/* eslint-disable react/no-multi-comp, max-classes-per-file */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +import { Component } from 'react'; +var NativeWebViewIOS = /** @class */ (function (_super) { + __extends(NativeWebViewIOS, _super); + function NativeWebViewIOS() { + return _super !== null && _super.apply(this, arguments) || this; + } + return NativeWebViewIOS; +}(NativeWebViewIOSBase)); +export { NativeWebViewIOS }; +var NativeWebViewMacOS = /** @class */ (function (_super) { + __extends(NativeWebViewMacOS, _super); + function NativeWebViewMacOS() { + return _super !== null && _super.apply(this, arguments) || this; + } + return NativeWebViewMacOS; +}(NativeWebViewMacOSBase)); +export { NativeWebViewMacOS }; +var NativeWebViewAndroid = /** @class */ (function (_super) { + __extends(NativeWebViewAndroid, _super); + function NativeWebViewAndroid() { + return _super !== null && _super.apply(this, arguments) || this; + } + return NativeWebViewAndroid; +}(NativeWebViewAndroidBase)); +export { NativeWebViewAndroid }; +var NativeWebViewWindows = /** @class */ (function (_super) { + __extends(NativeWebViewWindows, _super); + function NativeWebViewWindows() { + return _super !== null && _super.apply(this, arguments) || this; + } + return NativeWebViewWindows; +}(NativeWebViewWindowsBase)); +export { NativeWebViewWindows }; +export var ContentInsetAdjustmentBehavior; +(function (ContentInsetAdjustmentBehavior) { + ContentInsetAdjustmentBehavior["automatic"] = "automatic"; + ContentInsetAdjustmentBehavior["scrollableAxes"] = "scrollableAxes"; + ContentInsetAdjustmentBehavior["never"] = "never"; + ContentInsetAdjustmentBehavior["always"] = "always"; +})(ContentInsetAdjustmentBehavior || (ContentInsetAdjustmentBehavior = {})); +; From e25b2b5ab4d2d6c9fd1cfecf8fb273fc7635c717 Mon Sep 17 00:00:00 2001 From: Vitaliy Vlasov Date: Mon, 4 May 2020 20:55:55 +0300 Subject: [PATCH 4/5] Bug fixes --- .../webview/RNCWebViewManager.java | 247 ++++++++++++------ 1 file changed, 173 insertions(+), 74 deletions(-) diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java index 394cb60..7995730 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -12,6 +12,7 @@ import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.OkHttpClient.Builder; import okhttp3.Request; +import okhttp3.HttpUrl; import okhttp3.Response; import org.json.JSONException; import org.json.JSONObject; @@ -293,10 +294,7 @@ public class RNCWebViewManager extends SimpleViewManager { } private Boolean urlStringLooksInvalid(String urlString) { - return urlString == null || - urlString.trim().equals("") || - !(urlString.startsWith("http") && !urlString.startsWith("www")) || - urlString.contains("|"); + return urlString == null || HttpUrl.parse(urlString) == null; } private Boolean responseRequiresJSInjection(Response response) { @@ -313,57 +311,71 @@ public class RNCWebViewManager extends SimpleViewManager { public WebResourceResponse shouldInterceptRequest(WebResourceRequest request, Boolean onlyMainFrame, RNCWebView webView) { - Uri url = request.getUrl(); - String urlStr = url.toString(); + Uri url = request.getUrl(); + String urlStr = url.toString(); - Log.i("StatusNativeLogs", "###shouldInterceptRequest 1"); - Log.d(REACT_CLASS, "new request "); - Log.d(REACT_CLASS, "url " + urlStr); - Log.d(REACT_CLASS, "host " + request.getUrl().getHost()); - Log.d(REACT_CLASS, "path " + request.getUrl().getPath()); - Log.d(REACT_CLASS, "main " + request.isForMainFrame()); - Log.d(REACT_CLASS, "headers " + request.getRequestHeaders().toString()); - Log.d(REACT_CLASS, "method " + request.getMethod()); + Log.d(REACT_CLASS, "new request "); + Log.d(REACT_CLASS, "url " + urlStr); + Log.d(REACT_CLASS, "host " + request.getUrl().getHost()); + Log.d(REACT_CLASS, "path " + request.getUrl().getPath()); + Log.d(REACT_CLASS, "main " + request.isForMainFrame()); + Log.d(REACT_CLASS, "headers " + request.getRequestHeaders().toString()); + Log.d(REACT_CLASS, "method " + request.getMethod()); - Log.i("StatusNativeLogs", "###shouldInterceptRequest 2"); - if (onlyMainFrame && !request.isForMainFrame() || - urlStringLooksInvalid(urlStr)) { - return null;//super.shouldInterceptRequest(webView, request); - } + if (onlyMainFrame && !request.isForMainFrame() || + urlStringLooksInvalid(urlStr)) { + return null;//super.shouldInterceptRequest(webView, request); + } - Log.i("StatusNativeLogs", "###shouldInterceptRequest 3"); - try { - Log.i("StatusNativeLogs", "###shouldInterceptRequest 4"); - Request req = new Request.Builder() - .url(urlStr) - .header("User-Agent", userAgent) - .build(); + Response response = null; + try { + Request.Builder reqBuilder = new Request.Builder().url(urlStr); - Log.i("StatusNativeLogs", "### httpCall " + new Boolean(httpClient != null).toString()); - Response response = httpClient.newCall(req).execute(); + Map requestHeaders = request.getRequestHeaders(); + for(String header: requestHeaders.keySet()) { + reqBuilder.header(header, requestHeaders.get(header)); + } - Log.d(REACT_CLASS, "response headers " + response.headers().toString()); - Log.d(REACT_CLASS, "response code " + response.code()); - Log.d(REACT_CLASS, "response suc " + response.isSuccessful()); + Request httpRequest = reqBuilder.build(); + response = httpClient.newCall(httpRequest).execute(); - if (!responseRequiresJSInjection(response)) { - return null; - } - InputStream is = response.body().byteStream(); - MediaType contentType = response.body().contentType(); - Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8; + } catch (Exception e) { + Log.w(REACT_CLASS, "Error executing URL, ignoring: " + urlStr); + return null; + } + + if (response == null) { + Log.w(REACT_CLASS, "Unexpected null response, ignore: " + urlStr); + } + + Log.d(REACT_CLASS, "response headers " + response.headers().toString()); + Log.d(REACT_CLASS, "response code " + response.code()); + Log.d(REACT_CLASS, "response suc " + response.isSuccessful()); + if (!responseRequiresJSInjection(response)) { + return null; + } + + InputStream is = response.body().byteStream(); + MediaType contentType = response.body().contentType(); + Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8; + + RNCWebView reactWebView = (RNCWebView) webView; + if (response.code() == HttpURLConnection.HTTP_OK || + response.headers().get("content-type").toLowerCase().equals(HTML_MIME_TYPE)) { + is = new InputStreamWithInjectedJS(is, reactWebView.injectedJSBeforeContentLoaded, charset); + } + + Log.d(REACT_CLASS, "inject our custom JS to this request"); + Map responseHeaders = new HashMap<>(); + for (String hname: response.headers().names()) { + Log.d(REACT_CLASS, "HEAD " + hname + " " + response.headers().get(hname)); + responseHeaders.put(hname, response.headers().get(hname)); + } + + return new WebResourceResponse("text/html", charset.name(), response.code(), "phrase", responseHeaders, is); - RNCWebView reactWebView = (RNCWebView) webView; - if (response.code() == HttpURLConnection.HTTP_OK) { - is = new InputStreamWithInjectedJS(is, reactWebView.injectedJSBeforeContentLoaded, charset); - } - Log.d(REACT_CLASS, "inject our custom JS to this request"); - return new WebResourceResponse("text/html", charset.name(), is); - } catch (IOException e) { - return null; - } } @ReactProp(name = "javaScriptEnabled") @@ -862,11 +874,18 @@ public class RNCWebViewManager extends SimpleViewManager { private InputStream pageIS; private InputStream scriptIS; private Charset charset; - private static final String REACT_CLASS = "InputStreamWithInjectedJS"; + private static final String REACT_CLASS = "InpStreamWithInjectedJS"; private static Map script = new HashMap<>(); + private int GREATER_THAN_SIGN = 62; + private int LESS_THAN_SIGN = 60; + private int SCRIPT_TAG_LENGTH = 7; private boolean hasJS = false; - private boolean headWasFound = false; + private boolean tagWasFound = false; + private int[] tag = new int[SCRIPT_TAG_LENGTH]; + private boolean readFromTagVector = false; + private int tagVectorIdx = 0; + private int maxTagVectorIdx = SCRIPT_TAG_LENGTH; private boolean scriptWasInjected = false; private StringBuffer contentBuffer = new StringBuffer(); @@ -907,38 +926,118 @@ public class RNCWebViewManager extends SimpleViewManager { } } - @Override - public int read() throws IOException { - if (scriptWasInjected || !hasJS) { - return pageIS.read(); + private int readScript() throws IOException { + int nextByte = scriptIS.read(); + if (nextByte == -1) { + scriptIS.close(); + scriptWasInjected = true; + if(readFromTagVector) { + return readTag(); + } else { + return pageIS.read(); + } + } else { + return nextByte; + } + } + + private int readTag() { + int nextByte = tag[tagVectorIdx]; + tagVectorIdx++; + if(tagVectorIdx > maxTagVectorIdx) { + readFromTagVector = false; } - if (!scriptWasInjected && headWasFound) { - int nextByte = scriptIS.read(); - if (nextByte == -1) { - scriptIS.close(); - scriptWasInjected = true; - return pageIS.read(); + return nextByte; + } + + private boolean checkHeadTag(int nextByte) { + int bufferLength = contentBuffer.length(); + if (nextByte == GREATER_THAN_SIGN && + bufferLength >= 6 && + contentBuffer.substring(bufferLength - 6).equals("")) { + + Log.d(REACT_CLASS, " tag was found"); + this.scriptIS = getScript(this.charset); + tagWasFound = true; + + return true; + } + + return false; + } + + private boolean checkScriptTagByByte(int index, int anotherByte) { + if(index == 1) { + // 115 = "s" + return anotherByte == 115; + } else if(index == 2) { + // 99 = "c" + return anotherByte == 99; + } + + return true; + } + + private boolean checkScriptTag(int nextByte) throws IOException { + if (nextByte == LESS_THAN_SIGN) { + StringBuilder tagBuffer = new StringBuilder(); + tag[0] = nextByte; + tagBuffer.append((char) nextByte); + readFromTagVector = true; + tagVectorIdx = 1; + maxTagVectorIdx = SCRIPT_TAG_LENGTH - 1; + for (int i = 1; i < SCRIPT_TAG_LENGTH; i++) { + int anotherByte = pageIS.read(); + tag[i] = anotherByte; + tagBuffer.append((char) anotherByte); + contentBuffer.append((char) anotherByte); + if (!checkScriptTagByByte(i, anotherByte) || anotherByte == -1) { + maxTagVectorIdx = i; + return false; + } + } + + if(tagBuffer.length() == SCRIPT_TAG_LENGTH) { + String sub = tagBuffer.substring(0, SCRIPT_TAG_LENGTH); + if (sub.equals("= 6) { - if (contentBuffer.substring(bufferLength - 6).equals("")) { - this.scriptIS = getScript(this.charset); - headWasFound = true; - } - } - - return nextByte; - } - - return pageIS.read(); } } From 23ff0900c9eb2f741c95321fdc733124d6934f4c Mon Sep 17 00:00:00 2001 From: Vitaliy Vlasov Date: Thu, 11 Jun 2020 13:24:11 +0300 Subject: [PATCH 5/5] Add ssl error handling (https://github.com/react-native-community/react-native-webview/pull/1450) --- .../webview/RNCWebViewManager.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java index 7995730..6993fbb 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -33,6 +33,7 @@ import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Color; import android.Manifest; +import android.net.http.SslError; import android.net.Uri; import android.os.Build; import android.os.Environment; @@ -49,6 +50,7 @@ import android.webkit.CookieManager; import android.webkit.DownloadListener; import android.webkit.GeolocationPermissions; import android.webkit.JavascriptInterface; +import android.webkit.SslErrorHandler; import android.webkit.PermissionRequest; import android.webkit.URLUtil; import android.webkit.ServiceWorkerController; @@ -1136,6 +1138,50 @@ public class RNCWebViewManager extends SimpleViewManager { } + @Override + public void onReceivedSslError(final WebView webView, final SslErrorHandler handler, final SslError error) { + handler.cancel(); + + int code = error.getPrimaryError(); + String failingUrl = error.getUrl(); + String description = ""; + String descriptionPrefix = "SSL error: "; + + // https://developer.android.com/reference/android/net/http/SslError.html + switch (code) { + case SslError.SSL_DATE_INVALID: + description = "The date of the certificate is invalid"; + break; + case SslError.SSL_EXPIRED: + description = "The certificate has expired"; + break; + case SslError.SSL_IDMISMATCH: + description = "Hostname mismatch"; + break; + case SslError.SSL_INVALID: + description = "A generic error occurred"; + break; + case SslError.SSL_NOTYETVALID: + description = "The certificate is not yet valid"; + break; + case SslError.SSL_UNTRUSTED: + description = "The certificate authority is not trusted"; + break; + default: + description = "Unknown SSL Error"; + break; + } + + description = descriptionPrefix + description; + + this.onReceivedError( + webView, + code, + description, + failingUrl + ); + } + @Override public void onReceivedError( WebView webView,