@javascriptcommon/react-native-webview 13.12.21 → 13.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/gradle.properties +1 -1
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/AndroidManifestNew.xml +13 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +52 -25
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +27 -25
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +10 -6
- package/android/src/main/java/com/reactnativecommunity/webview/events/SubResourceErrorEvent.kt +25 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +12 -1
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +7 -0
- package/apple/RNCWebView.h +1 -1
- package/apple/RNCWebView.mm +26 -17
- package/apple/RNCWebViewImpl.h +2 -1
- package/apple/RNCWebViewImpl.m +62 -25
- package/apple/RNCWebViewManager.mm +4 -0
- package/index.d.ts +2 -3
- package/lib/RNCWebViewNativeComponent.d.ts +24 -21
- package/lib/RNCWebViewNativeComponent.js +1 -1
- package/lib/WebView.android.js +1 -1
- package/lib/WebView.ios.js +1 -1
- package/lib/WebView.js +1 -1
- package/lib/WebView.macos.js +1 -1
- package/lib/WebView.windows.js +1 -1
- package/lib/WebViewShared.d.ts +3 -1
- package/lib/WebViewShared.js +1 -1
- package/lib/WebViewTypes.d.ts +32 -8
- package/lib/WebViewTypes.js +1 -1
- package/package.json +9 -1
- package/src/RNCWebViewNativeComponent.ts +27 -21
- package/src/WebView.android.tsx +4 -0
- package/src/WebViewShared.tsx +10 -0
- package/src/WebViewTypes.ts +36 -8
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
2
|
package="com.reactnativecommunity.webview">
|
|
3
3
|
|
|
4
|
+
<queries>
|
|
5
|
+
<intent>
|
|
6
|
+
<action android:name="org.chromium.intent.action.PAY"/>
|
|
7
|
+
</intent>
|
|
8
|
+
<intent>
|
|
9
|
+
<action android:name="org.chromium.intent.action.IS_READY_TO_PAY"/>
|
|
10
|
+
</intent>
|
|
11
|
+
<intent>
|
|
12
|
+
<action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS"/>
|
|
13
|
+
</intent>
|
|
14
|
+
</queries>
|
|
15
|
+
|
|
4
16
|
<application>
|
|
5
17
|
<provider
|
|
6
18
|
android:name=".RNCWebViewFileProvider"
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
|
|
3
|
+
<queries>
|
|
4
|
+
<intent>
|
|
5
|
+
<action android:name="org.chromium.intent.action.PAY"/>
|
|
6
|
+
</intent>
|
|
7
|
+
<intent>
|
|
8
|
+
<action android:name="org.chromium.intent.action.IS_READY_TO_PAY"/>
|
|
9
|
+
</intent>
|
|
10
|
+
<intent>
|
|
11
|
+
<action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS"/>
|
|
12
|
+
</intent>
|
|
13
|
+
</queries>
|
|
14
|
+
|
|
2
15
|
<application>
|
|
3
16
|
<provider
|
|
4
17
|
android:name=".RNCWebViewFileProvider"
|
|
@@ -2,6 +2,7 @@ package com.reactnativecommunity.webview;
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint;
|
|
4
4
|
import android.graphics.Rect;
|
|
5
|
+
import android.net.Uri;
|
|
5
6
|
import android.text.TextUtils;
|
|
6
7
|
import android.view.ActionMode;
|
|
7
8
|
import android.view.Menu;
|
|
@@ -14,7 +15,12 @@ import android.webkit.WebChromeClient;
|
|
|
14
15
|
import android.webkit.WebView;
|
|
15
16
|
import android.webkit.WebViewClient;
|
|
16
17
|
|
|
18
|
+
import androidx.annotation.NonNull;
|
|
17
19
|
import androidx.annotation.Nullable;
|
|
20
|
+
import androidx.webkit.JavaScriptReplyProxy;
|
|
21
|
+
import androidx.webkit.WebMessageCompat;
|
|
22
|
+
import androidx.webkit.WebViewCompat;
|
|
23
|
+
import androidx.webkit.WebViewFeature;
|
|
18
24
|
|
|
19
25
|
import com.facebook.common.logging.FLog;
|
|
20
26
|
import com.facebook.react.bridge.Arguments;
|
|
@@ -38,6 +44,7 @@ import org.json.JSONObject;
|
|
|
38
44
|
|
|
39
45
|
import java.util.List;
|
|
40
46
|
import java.util.Map;
|
|
47
|
+
import java.util.Set;
|
|
41
48
|
|
|
42
49
|
public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
43
50
|
protected @Nullable
|
|
@@ -46,7 +53,9 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
46
53
|
String injectedJSBeforeContentLoaded;
|
|
47
54
|
protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView";
|
|
48
55
|
protected @Nullable
|
|
49
|
-
RNCWebViewBridge
|
|
56
|
+
RNCWebViewBridge fallbackBridge;
|
|
57
|
+
protected @Nullable
|
|
58
|
+
WebViewCompat.WebMessageListener bridgeListener = null;
|
|
50
59
|
|
|
51
60
|
/**
|
|
52
61
|
* android.webkit.WebChromeClient fundamentally does not support JS injection into frames other
|
|
@@ -81,10 +90,6 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
81
90
|
progressChangedFilter = new ProgressChangedFilter();
|
|
82
91
|
}
|
|
83
92
|
|
|
84
|
-
public void setIgnoreErrFailedForThisURL(String url) {
|
|
85
|
-
mRNCWebViewClient.setIgnoreErrFailedForThisURL(url);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
93
|
public void setBasicAuthCredential(RNCBasicAuthCredential credential) {
|
|
89
94
|
mRNCWebViewClient.setBasicAuthCredential(credential);
|
|
90
95
|
}
|
|
@@ -246,12 +251,39 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
246
251
|
return this.messagingEnabled;
|
|
247
252
|
}
|
|
248
253
|
|
|
249
|
-
protected
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
254
|
+
protected void createRNCWebViewBridge(RNCWebView webView) {
|
|
255
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)){
|
|
256
|
+
if (this.bridgeListener == null) {
|
|
257
|
+
this.bridgeListener = new WebViewCompat.WebMessageListener() {
|
|
258
|
+
@Override
|
|
259
|
+
public void onPostMessage(@NonNull WebView view, @NonNull WebMessageCompat message, @NonNull Uri sourceOrigin, boolean isMainFrame, @NonNull JavaScriptReplyProxy replyProxy) {
|
|
260
|
+
RNCWebView.this.onMessage(message.getData(), sourceOrigin.toString());
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
WebViewCompat.addWebMessageListener(
|
|
264
|
+
webView,
|
|
265
|
+
JAVASCRIPT_INTERFACE,
|
|
266
|
+
Set.of("*"),
|
|
267
|
+
this.bridgeListener
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
if (fallbackBridge == null) {
|
|
272
|
+
fallbackBridge = new RNCWebViewBridge(webView);
|
|
273
|
+
addJavascriptInterface(fallbackBridge, JAVASCRIPT_INTERFACE);
|
|
274
|
+
}
|
|
253
275
|
}
|
|
254
|
-
|
|
276
|
+
injectJavascriptObject();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private void injectJavascriptObject() {
|
|
280
|
+
if (getSettings().getJavaScriptEnabled()) {
|
|
281
|
+
String js = "(function(){\n" +
|
|
282
|
+
" window." + JAVASCRIPT_INTERFACE + " = window." + JAVASCRIPT_INTERFACE + " || {};\n" +
|
|
283
|
+
" window." + JAVASCRIPT_INTERFACE + ".injectedObjectJson = function () { return " + (injectedJavaScriptObject == null ? null : ("`" + injectedJavaScriptObject + "`")) + "; };\n" +
|
|
284
|
+
"})();";
|
|
285
|
+
evaluateJavascriptWithFallback(js);
|
|
286
|
+
}
|
|
255
287
|
}
|
|
256
288
|
|
|
257
289
|
@SuppressLint("AddJavascriptInterface")
|
|
@@ -276,6 +308,7 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
276
308
|
injectedJS != null &&
|
|
277
309
|
!TextUtils.isEmpty(injectedJS)) {
|
|
278
310
|
evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();");
|
|
311
|
+
injectJavascriptObject(); // re-inject the Javascript object in case it has been overwritten.
|
|
279
312
|
}
|
|
280
313
|
}
|
|
281
314
|
|
|
@@ -284,17 +317,18 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
284
317
|
injectedJSBeforeContentLoaded != null &&
|
|
285
318
|
!TextUtils.isEmpty(injectedJSBeforeContentLoaded)) {
|
|
286
319
|
evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();");
|
|
320
|
+
injectJavascriptObject(); // re-inject the Javascript object in case it has been overwritten.
|
|
287
321
|
}
|
|
288
322
|
}
|
|
289
323
|
|
|
324
|
+
protected String injectedJavaScriptObject = null;
|
|
325
|
+
|
|
290
326
|
public void setInjectedJavaScriptObject(String obj) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
b.setInjectedObjectJson(obj);
|
|
294
|
-
}
|
|
327
|
+
this.injectedJavaScriptObject = obj;
|
|
328
|
+
injectJavascriptObject();
|
|
295
329
|
}
|
|
296
330
|
|
|
297
|
-
public void onMessage(String message) {
|
|
331
|
+
public void onMessage(String message, String sourceUrl) {
|
|
298
332
|
ThemedReactContext reactContext = getThemedReactContext();
|
|
299
333
|
RNCWebView mWebView = this;
|
|
300
334
|
|
|
@@ -306,7 +340,7 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
306
340
|
if (mRNCWebViewClient == null) {
|
|
307
341
|
return;
|
|
308
342
|
}
|
|
309
|
-
WritableMap data = mRNCWebViewClient.createWebViewEvent(webView,
|
|
343
|
+
WritableMap data = mRNCWebViewClient.createWebViewEvent(webView, sourceUrl);
|
|
310
344
|
data.putString("data", message);
|
|
311
345
|
|
|
312
346
|
if (mMessagingJSModule != null) {
|
|
@@ -408,16 +442,11 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
408
442
|
protected class RNCWebViewBridge {
|
|
409
443
|
private String TAG = "RNCWebViewBridge";
|
|
410
444
|
RNCWebView mWebView;
|
|
411
|
-
String injectedObjectJson;
|
|
412
445
|
|
|
413
446
|
RNCWebViewBridge(RNCWebView c) {
|
|
414
447
|
mWebView = c;
|
|
415
448
|
}
|
|
416
449
|
|
|
417
|
-
public void setInjectedObjectJson(String s) {
|
|
418
|
-
injectedObjectJson = s;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
450
|
/**
|
|
422
451
|
* This method is called whenever JavaScript running within the web view calls:
|
|
423
452
|
* - window[JAVASCRIPT_INTERFACE].postMessage
|
|
@@ -425,14 +454,12 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
425
454
|
@JavascriptInterface
|
|
426
455
|
public void postMessage(String message) {
|
|
427
456
|
if (mWebView.getMessagingEnabled()) {
|
|
428
|
-
mWebView.
|
|
457
|
+
// Post to main thread because `mWebView.getUrl()` requires to be executed on main.
|
|
458
|
+
mWebView.post(() -> mWebView.onMessage(message, mWebView.getUrl()));
|
|
429
459
|
} else {
|
|
430
460
|
FLog.w(TAG, "ReactNativeWebView.postMessage method was called but messaging is disabled. Pass an onMessage handler to the WebView.");
|
|
431
461
|
}
|
|
432
462
|
}
|
|
433
|
-
|
|
434
|
-
@JavascriptInterface
|
|
435
|
-
public String injectedObjectJson() { return injectedObjectJson; }
|
|
436
463
|
}
|
|
437
464
|
|
|
438
465
|
|
|
@@ -25,6 +25,7 @@ import com.facebook.react.bridge.ReadableArray;
|
|
|
25
25
|
import com.facebook.react.bridge.WritableMap;
|
|
26
26
|
import com.facebook.react.uimanager.ThemedReactContext;
|
|
27
27
|
import com.facebook.react.uimanager.UIManagerHelper;
|
|
28
|
+
import com.reactnativecommunity.webview.events.SubResourceErrorEvent;
|
|
28
29
|
import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
|
|
29
30
|
import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
|
|
30
31
|
import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
|
|
@@ -42,13 +43,8 @@ public class RNCWebViewClient extends WebViewClient {
|
|
|
42
43
|
|
|
43
44
|
protected boolean mLastLoadFailed = false;
|
|
44
45
|
protected RNCWebView.ProgressChangedFilter progressChangedFilter = null;
|
|
45
|
-
protected @Nullable String ignoreErrFailedForThisURL = null;
|
|
46
46
|
protected @Nullable RNCBasicAuthCredential basicAuthCredential = null;
|
|
47
47
|
|
|
48
|
-
public void setIgnoreErrFailedForThisURL(@Nullable String url) {
|
|
49
|
-
ignoreErrFailedForThisURL = url;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
48
|
public void setBasicAuthCredential(@Nullable RNCBasicAuthCredential credential) {
|
|
53
49
|
basicAuthCredential = credential;
|
|
54
50
|
}
|
|
@@ -173,12 +169,6 @@ public class RNCWebViewClient extends WebViewClient {
|
|
|
173
169
|
// Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL.
|
|
174
170
|
handler.cancel();
|
|
175
171
|
|
|
176
|
-
if (!topWindowUrl.equalsIgnoreCase(failingUrl)) {
|
|
177
|
-
// If error is not due to top-level navigation, then do not call onReceivedError()
|
|
178
|
-
Log.w(TAG, "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
172
|
int code = error.getPrimaryError();
|
|
183
173
|
String description = "";
|
|
184
174
|
String descriptionPrefix = "SSL error: ";
|
|
@@ -210,6 +200,18 @@ public class RNCWebViewClient extends WebViewClient {
|
|
|
210
200
|
|
|
211
201
|
description = descriptionPrefix + description;
|
|
212
202
|
|
|
203
|
+
if (!topWindowUrl.equalsIgnoreCase(failingUrl)) {
|
|
204
|
+
// If error is not due to top-level navigation, then do not call onReceivedError()
|
|
205
|
+
Log.w(TAG, "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl);
|
|
206
|
+
this.onReceivedSubResourceSslError(
|
|
207
|
+
webView,
|
|
208
|
+
code,
|
|
209
|
+
description,
|
|
210
|
+
failingUrl
|
|
211
|
+
);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
213
215
|
this.onReceivedError(
|
|
214
216
|
webView,
|
|
215
217
|
code,
|
|
@@ -218,6 +220,20 @@ public class RNCWebViewClient extends WebViewClient {
|
|
|
218
220
|
);
|
|
219
221
|
}
|
|
220
222
|
|
|
223
|
+
public void onReceivedSubResourceSslError(
|
|
224
|
+
WebView webView,
|
|
225
|
+
int errorCode,
|
|
226
|
+
String description,
|
|
227
|
+
String failingUrl) {
|
|
228
|
+
|
|
229
|
+
WritableMap eventData = createWebViewEvent(webView, failingUrl);
|
|
230
|
+
eventData.putDouble("code", errorCode);
|
|
231
|
+
eventData.putString("description", description);
|
|
232
|
+
|
|
233
|
+
int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
|
|
234
|
+
UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new SubResourceErrorEvent(reactTag, eventData));
|
|
235
|
+
}
|
|
236
|
+
|
|
221
237
|
@Override
|
|
222
238
|
public void onReceivedError(
|
|
223
239
|
WebView webView,
|
|
@@ -225,20 +241,6 @@ public class RNCWebViewClient extends WebViewClient {
|
|
|
225
241
|
String description,
|
|
226
242
|
String failingUrl) {
|
|
227
243
|
|
|
228
|
-
if (ignoreErrFailedForThisURL != null
|
|
229
|
-
&& failingUrl.equals(ignoreErrFailedForThisURL)
|
|
230
|
-
&& errorCode == -1
|
|
231
|
-
&& description.equals("net::ERR_FAILED")) {
|
|
232
|
-
|
|
233
|
-
// This is a workaround for a bug in the WebView.
|
|
234
|
-
// See these chromium issues for more context:
|
|
235
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=1023678
|
|
236
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=1050635
|
|
237
|
-
// This entire commit should be reverted once this bug is resolved in chromium.
|
|
238
|
-
setIgnoreErrFailedForThisURL(null);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
244
|
super.onReceivedError(webView, errorCode, description, failingUrl);
|
|
243
245
|
mLastLoadFailed = true;
|
|
244
246
|
|
|
@@ -92,7 +92,6 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
|
|
|
92
92
|
WebView.setWebContentsDebuggingEnabled(true)
|
|
93
93
|
}
|
|
94
94
|
webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
|
|
95
|
-
webView.setIgnoreErrFailedForThisURL(url)
|
|
96
95
|
val module = webView.reactApplicationContext.getNativeModule(RNCWebViewModule::class.java) ?: return@DownloadListener
|
|
97
96
|
val request: DownloadManager.Request = try {
|
|
98
97
|
DownloadManager.Request(Uri.parse(url))
|
|
@@ -341,11 +340,9 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
|
|
|
341
340
|
}
|
|
342
341
|
"injectJavaScript" -> webView.evaluateJavascriptWithFallback(args.getString(0))
|
|
343
342
|
"loadUrl" -> {
|
|
344
|
-
|
|
345
|
-
throw RuntimeException("Arguments for loading an url are null!")
|
|
346
|
-
}
|
|
343
|
+
val url = args?.getString(0) ?: throw RuntimeException("Arguments for loading an url are null!")
|
|
347
344
|
webView.progressChangedFilter.setWaitingForCommandLoadUrl(false)
|
|
348
|
-
|
|
345
|
+
webView.loadUrl(url)
|
|
349
346
|
}
|
|
350
347
|
"requestFocus" -> webView.requestFocus()
|
|
351
348
|
"clearFormData" -> webView.clearFormData()
|
|
@@ -721,4 +718,11 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
|
|
|
721
718
|
fun setWebviewDebuggingEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
722
719
|
RNCWebView.setWebContentsDebuggingEnabled(enabled)
|
|
723
720
|
}
|
|
724
|
-
|
|
721
|
+
|
|
722
|
+
fun setPaymentRequestEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
723
|
+
val view = viewWrapper.webView
|
|
724
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.PAYMENT_REQUEST)) {
|
|
725
|
+
WebSettingsCompat.setPaymentRequestEnabled(view.settings, enabled)
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
package/android/src/main/java/com/reactnativecommunity/webview/events/SubResourceErrorEvent.kt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package com.reactnativecommunity.webview.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.WritableMap
|
|
4
|
+
import com.facebook.react.uimanager.events.Event
|
|
5
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Event emitted when there is an error in loading a subresource
|
|
9
|
+
*/
|
|
10
|
+
class SubResourceErrorEvent(viewId: Int, private val mEventData: WritableMap) :
|
|
11
|
+
Event<SubResourceErrorEvent>(viewId) {
|
|
12
|
+
companion object {
|
|
13
|
+
const val EVENT_NAME = "topLoadingSubResourceError"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override fun getEventName(): String = EVENT_NAME
|
|
17
|
+
|
|
18
|
+
override fun canCoalesce(): Boolean = false
|
|
19
|
+
|
|
20
|
+
override fun getCoalescingKey(): Short = 0
|
|
21
|
+
|
|
22
|
+
override fun dispatch(rctEventEmitter: RCTEventEmitter) =
|
|
23
|
+
rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
|
|
24
|
+
|
|
25
|
+
}
|
|
@@ -15,6 +15,7 @@ import com.facebook.react.viewmanagers.RNCWebViewManagerDelegate;
|
|
|
15
15
|
import com.facebook.react.viewmanagers.RNCWebViewManagerInterface;
|
|
16
16
|
import com.facebook.react.views.scroll.ScrollEventType;
|
|
17
17
|
import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent;
|
|
18
|
+
import com.reactnativecommunity.webview.events.SubResourceErrorEvent;
|
|
18
19
|
import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
|
|
19
20
|
import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
|
|
20
21
|
import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
|
|
@@ -232,7 +233,7 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper>
|
|
|
232
233
|
}
|
|
233
234
|
|
|
234
235
|
@Override
|
|
235
|
-
@ReactProp(name = "suppressMenuItems
|
|
236
|
+
@ReactProp(name = "suppressMenuItems")
|
|
236
237
|
public void setSuppressMenuItems(RNCWebViewWrapper view, @Nullable ReadableArray items) {}
|
|
237
238
|
|
|
238
239
|
@Override
|
|
@@ -337,6 +338,12 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper>
|
|
|
337
338
|
mRNCWebViewManagerImpl.setWebviewDebuggingEnabled(view, value);
|
|
338
339
|
}
|
|
339
340
|
|
|
341
|
+
@Override
|
|
342
|
+
@ReactProp(name = "paymentRequestEnabled")
|
|
343
|
+
public void setPaymentRequestEnabled(RNCWebViewWrapper view, boolean value) {
|
|
344
|
+
mRNCWebViewManagerImpl.setPaymentRequestEnabled(view, value);
|
|
345
|
+
}
|
|
346
|
+
|
|
340
347
|
/* iOS PROPS - no implemented here */
|
|
341
348
|
@Override
|
|
342
349
|
public void setAllowingReadAccessToURL(RNCWebViewWrapper view, @Nullable String value) {}
|
|
@@ -401,6 +408,9 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper>
|
|
|
401
408
|
@Override
|
|
402
409
|
public void setRefreshControlLightMode(RNCWebViewWrapper view, boolean value) {}
|
|
403
410
|
|
|
411
|
+
@Override
|
|
412
|
+
public void setIndicatorStyle(RNCWebViewWrapper view, @Nullable String value) {}
|
|
413
|
+
|
|
404
414
|
@Override
|
|
405
415
|
public void setScrollEnabled(RNCWebViewWrapper view, boolean value) {}
|
|
406
416
|
|
|
@@ -521,6 +531,7 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper>
|
|
|
521
531
|
export.put(TopLoadingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingStart"));
|
|
522
532
|
export.put(TopLoadingFinishEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingFinish"));
|
|
523
533
|
export.put(TopLoadingErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingError"));
|
|
534
|
+
export.put(SubResourceErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingSubResourceError"));
|
|
524
535
|
export.put(TopMessageEvent.EVENT_NAME, MapBuilder.of("registrationName", "onMessage"));
|
|
525
536
|
// !Default events but adding them here explicitly for clarity
|
|
526
537
|
|
|
@@ -11,6 +11,7 @@ import com.facebook.react.uimanager.ViewGroupManager;
|
|
|
11
11
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
|
12
12
|
import com.facebook.react.views.scroll.ScrollEventType;
|
|
13
13
|
import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent;
|
|
14
|
+
import com.reactnativecommunity.webview.events.SubResourceErrorEvent;
|
|
14
15
|
import com.reactnativecommunity.webview.events.TopHttpErrorEvent;
|
|
15
16
|
import com.reactnativecommunity.webview.events.TopLoadingErrorEvent;
|
|
16
17
|
import com.reactnativecommunity.webview.events.TopLoadingFinishEvent;
|
|
@@ -278,6 +279,11 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper> {
|
|
|
278
279
|
mRNCWebViewManagerImpl.setUserAgent(view, value);
|
|
279
280
|
}
|
|
280
281
|
|
|
282
|
+
@ReactProp(name = "paymentRequestEnabled")
|
|
283
|
+
public void setPaymentRequestEnabled(RNCWebViewWrapper view, boolean value) {
|
|
284
|
+
mRNCWebViewManagerImpl.setPaymentRequestEnabled(view, value);
|
|
285
|
+
}
|
|
286
|
+
|
|
281
287
|
@Override
|
|
282
288
|
protected void addEventEmitters(@NonNull ThemedReactContext reactContext, RNCWebViewWrapper viewWrapper) {
|
|
283
289
|
// Do not register default touch emitter and let WebView implementation handle touches
|
|
@@ -294,6 +300,7 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper> {
|
|
|
294
300
|
export.put(TopLoadingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingStart"));
|
|
295
301
|
export.put(TopLoadingFinishEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingFinish"));
|
|
296
302
|
export.put(TopLoadingErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingError"));
|
|
303
|
+
export.put(SubResourceErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingSubResourceError"));
|
|
297
304
|
export.put(TopMessageEvent.EVENT_NAME, MapBuilder.of("registrationName", "onMessage"));
|
|
298
305
|
// !Default events but adding them here explicitly for clarity
|
|
299
306
|
|
package/apple/RNCWebView.h
CHANGED
|
@@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
22
22
|
|
|
23
23
|
namespace facebook {
|
|
24
24
|
namespace react {
|
|
25
|
-
bool operator==(const RNCWebViewMenuItemsStruct& a, const RNCWebViewMenuItemsStruct& b)
|
|
25
|
+
inline bool operator==(const RNCWebViewMenuItemsStruct& a, const RNCWebViewMenuItemsStruct& b)
|
|
26
26
|
{
|
|
27
27
|
return b.key == a.key && b.label == a.label;
|
|
28
28
|
}
|
package/apple/RNCWebView.mm
CHANGED
|
@@ -71,9 +71,9 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
71
71
|
if (self = [super initWithFrame:frame]) {
|
|
72
72
|
static const auto defaultProps = std::make_shared<const RNCWebViewProps>();
|
|
73
73
|
_props = defaultProps;
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
_view = [[RNCWebViewImpl alloc] init];
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
_view.onShouldStartLoadWithRequest = [self](NSDictionary* dictionary) {
|
|
78
78
|
if (_eventEmitter) {
|
|
79
79
|
auto webViewEventEmitter = std::static_pointer_cast<RNCWebViewEventEmitter const>(_eventEmitter);
|
|
@@ -83,7 +83,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
83
83
|
.title = std::string([[dictionary valueForKey:@"title"] UTF8String]),
|
|
84
84
|
.navigationType = stringToOnShouldStartLoadWithRequestNavigationTypeEnum(std::string([[dictionary valueForKey:@"navigationType"] UTF8String])),
|
|
85
85
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
86
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
86
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
87
87
|
.isTopFrame = static_cast<bool>([[dictionary valueForKey:@"isTopFrame"] boolValue]),
|
|
88
88
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue]),
|
|
89
89
|
.mainDocumentURL = std::string([[dictionary valueForKey:@"mainDocumentURL"] UTF8String])
|
|
@@ -100,7 +100,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
100
100
|
.title = std::string([[dictionary valueForKey:@"title"] UTF8String]),
|
|
101
101
|
.navigationType = stringToOnLoadingStartNavigationTypeEnum(std::string([[dictionary valueForKey:@"navigationType"] UTF8String])),
|
|
102
102
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
103
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
103
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
104
104
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue]),
|
|
105
105
|
.mainDocumentURL = std::string([[dictionary valueForKey:@"mainDocumentURL"] UTF8String], [[dictionary valueForKey:@"mainDocumentURL"] lengthOfBytesUsingEncoding:NSUTF8StringEncoding])
|
|
106
106
|
};
|
|
@@ -117,7 +117,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
117
117
|
.code = [[dictionary valueForKey:@"code"] intValue],
|
|
118
118
|
.description = std::string([[dictionary valueForKey:@"description"] UTF8String] ?: ""),
|
|
119
119
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
120
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
120
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
121
121
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue]),
|
|
122
122
|
.domain = std::string([[dictionary valueForKey:@"domain"] UTF8String])
|
|
123
123
|
};
|
|
@@ -132,7 +132,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
132
132
|
.lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue],
|
|
133
133
|
.title = std::string([[dictionary valueForKey:@"title"] UTF8String]),
|
|
134
134
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
135
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
135
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
136
136
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue]),
|
|
137
137
|
.data = std::string([[dictionary valueForKey:@"data"] UTF8String])
|
|
138
138
|
};
|
|
@@ -148,7 +148,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
148
148
|
.title = std::string([[dictionary valueForKey:@"title"] UTF8String]),
|
|
149
149
|
.navigationType = stringToOnLoadingFinishNavigationTypeEnum(std::string([[dictionary valueForKey:@"navigationType"] UTF8String], [[dictionary valueForKey:@"navigationType"] lengthOfBytesUsingEncoding:NSUTF8StringEncoding])),
|
|
150
150
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
151
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
151
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
152
152
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue]),
|
|
153
153
|
.mainDocumentURL = std::string([[dictionary valueForKey:@"mainDocumentURL"] UTF8String], [[dictionary valueForKey:@"mainDocumentURL"] lengthOfBytesUsingEncoding:NSUTF8StringEncoding])
|
|
154
154
|
};
|
|
@@ -163,7 +163,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
163
163
|
.lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue],
|
|
164
164
|
.title = std::string([[dictionary valueForKey:@"title"] UTF8String]),
|
|
165
165
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
166
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
166
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
167
167
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue]),
|
|
168
168
|
.progress = [[dictionary valueForKey:@"progress"] doubleValue]
|
|
169
169
|
};
|
|
@@ -178,7 +178,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
178
178
|
.lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue],
|
|
179
179
|
.title = std::string([[dictionary valueForKey:@"title"] UTF8String]),
|
|
180
180
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
181
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
181
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
182
182
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue])
|
|
183
183
|
};
|
|
184
184
|
webViewEventEmitter->onContentProcessDidTerminate(data);
|
|
@@ -191,7 +191,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
191
191
|
.selectedText = std::string([[dictionary valueForKey:@"selectedText"] UTF8String]),
|
|
192
192
|
.key = std::string([[dictionary valueForKey:@"key"] UTF8String]),
|
|
193
193
|
.label = std::string([[dictionary valueForKey:@"label"] UTF8String])
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
};
|
|
196
196
|
webViewEventEmitter->onCustomMenuSelection(data);
|
|
197
197
|
}
|
|
@@ -238,7 +238,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
238
238
|
.statusCode = [[dictionary valueForKey:@"statusCode"] intValue],
|
|
239
239
|
.description = std::string([[dictionary valueForKey:@"description"] UTF8String] ?: ""),
|
|
240
240
|
.canGoBack = static_cast<bool>([[dictionary valueForKey:@"canGoBack"] boolValue]),
|
|
241
|
-
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"
|
|
241
|
+
.canGoForward = static_cast<bool>([[dictionary valueForKey:@"canGoForward"] boolValue]),
|
|
242
242
|
.loading = static_cast<bool>([[dictionary valueForKey:@"loading"] boolValue])
|
|
243
243
|
};
|
|
244
244
|
webViewEventEmitter->onHttpError(data);
|
|
@@ -313,7 +313,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
313
313
|
REMAP_WEBVIEW_PROP(showsHorizontalScrollIndicator)
|
|
314
314
|
REMAP_WEBVIEW_PROP(showsVerticalScrollIndicator)
|
|
315
315
|
REMAP_WEBVIEW_PROP(keyboardDisplayRequiresUserAction)
|
|
316
|
-
|
|
316
|
+
|
|
317
317
|
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */
|
|
318
318
|
REMAP_WEBVIEW_PROP(automaticallyAdjustContentInsets)
|
|
319
319
|
#endif
|
|
@@ -399,7 +399,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
399
399
|
for (const auto &menuItem: newViewProps.suppressMenuItems) {
|
|
400
400
|
[suppressMenuItems addObject: RCTNSStringFromString(menuItem)];
|
|
401
401
|
}
|
|
402
|
-
|
|
402
|
+
|
|
403
403
|
[_view setSuppressMenuItems:suppressMenuItems];
|
|
404
404
|
}
|
|
405
405
|
if (oldViewProps.hasOnFileDownload != newViewProps.hasOnFileDownload) {
|
|
@@ -411,10 +411,10 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
411
411
|
.downloadUrl = std::string([[dictionary valueForKey:@"downloadUrl"] UTF8String])
|
|
412
412
|
};
|
|
413
413
|
webViewEventEmitter->onFileDownload(data);
|
|
414
|
-
}
|
|
414
|
+
}
|
|
415
415
|
};
|
|
416
416
|
} else {
|
|
417
|
-
_view.onFileDownload = nil;
|
|
417
|
+
_view.onFileDownload = nil;
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
420
|
if (oldViewProps.hasOnOpenWindowEvent != newViewProps.hasOnOpenWindowEvent) {
|
|
@@ -460,7 +460,16 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
460
460
|
}
|
|
461
461
|
}
|
|
462
462
|
#endif
|
|
463
|
-
|
|
463
|
+
if (oldViewProps.indicatorStyle != newViewProps.indicatorStyle) {
|
|
464
|
+
if (newViewProps.indicatorStyle == RNCWebViewIndicatorStyle::Black) {
|
|
465
|
+
[_view setIndicatorStyle:@"black"];
|
|
466
|
+
} else if (newViewProps.indicatorStyle == RNCWebViewIndicatorStyle::White) {
|
|
467
|
+
[_view setIndicatorStyle:@"white"];
|
|
468
|
+
} else {
|
|
469
|
+
[_view setIndicatorStyle:@"default"];
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
464
473
|
NSMutableDictionary* source = [[NSMutableDictionary alloc] init];
|
|
465
474
|
if (!newViewProps.newSource.uri.empty()) {
|
|
466
475
|
[source setValue:RCTNSStringFromString(newViewProps.newSource.uri) forKey:@"uri"];
|
|
@@ -485,7 +494,7 @@ auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) {
|
|
|
485
494
|
[source setValue:RCTNSStringFromString(newViewProps.newSource.method) forKey:@"method"];
|
|
486
495
|
}
|
|
487
496
|
[_view setSource:source];
|
|
488
|
-
|
|
497
|
+
|
|
489
498
|
[super updateProps:props oldProps:oldProps];
|
|
490
499
|
}
|
|
491
500
|
|
package/apple/RNCWebViewImpl.h
CHANGED
|
@@ -45,7 +45,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
|
|
|
45
45
|
@end
|
|
46
46
|
|
|
47
47
|
#if !TARGET_OS_OSX
|
|
48
|
-
@interface RNCWebViewImpl : RCTView <UIEditMenuInteractionDelegate>
|
|
48
|
+
@interface RNCWebViewImpl : RCTView <UIEditMenuInteractionDelegate, UIGestureRecognizerDelegate>
|
|
49
49
|
|
|
50
50
|
@property (nonatomic, nullable) UIEditMenuInteraction *editMenuInteraction API_AVAILABLE(ios(16.0));
|
|
51
51
|
#else
|
|
@@ -103,6 +103,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
|
|
|
103
103
|
@property (nonatomic, assign) BOOL allowsLinkPreview;
|
|
104
104
|
@property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
|
|
105
105
|
@property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
|
|
106
|
+
@property (nonatomic, copy) NSString * _Nullable indicatorStyle;
|
|
106
107
|
@property (nonatomic, assign) BOOL directionalLockEnabled;
|
|
107
108
|
@property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch;
|
|
108
109
|
@property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
|