@capgo/inappbrowser 7.10.0 → 7.10.3
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/Package.swift +2 -2
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +56 -41
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +150 -47
- package/ios/Plugin/InAppBrowserPlugin.swift +16 -16
- package/ios/Plugin/WKWebViewController.swift +57 -57
- package/package.json +1 -1
package/Package.swift
CHANGED
|
@@ -10,14 +10,14 @@ let package = Package(
|
|
|
10
10
|
targets: ["InappbrowserPlugin"])
|
|
11
11
|
],
|
|
12
12
|
dependencies: [
|
|
13
|
-
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.2.0")
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.2.0")
|
|
14
14
|
],
|
|
15
15
|
targets: [
|
|
16
16
|
.target(
|
|
17
17
|
name: "InappbrowserPlugin",
|
|
18
18
|
dependencies: [
|
|
19
19
|
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
20
|
-
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
20
|
+
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
21
21
|
],
|
|
22
22
|
path: "ios/Sources/InappbrowserPlugin"),
|
|
23
23
|
.testTarget(
|
|
@@ -251,6 +251,7 @@ public class InAppBrowserPlugin
|
|
|
251
251
|
String url = call.getString("url");
|
|
252
252
|
if (url == null || TextUtils.isEmpty(url)) {
|
|
253
253
|
call.reject("Invalid URL");
|
|
254
|
+
return;
|
|
254
255
|
}
|
|
255
256
|
currentUrl = url;
|
|
256
257
|
this.getActivity()
|
|
@@ -258,11 +259,15 @@ public class InAppBrowserPlugin
|
|
|
258
259
|
new Runnable() {
|
|
259
260
|
@Override
|
|
260
261
|
public void run() {
|
|
261
|
-
webViewDialog
|
|
262
|
+
if (webViewDialog != null) {
|
|
263
|
+
webViewDialog.setUrl(url);
|
|
264
|
+
call.resolve();
|
|
265
|
+
} else {
|
|
266
|
+
call.reject("WebView is not initialized");
|
|
267
|
+
}
|
|
262
268
|
}
|
|
263
269
|
}
|
|
264
270
|
);
|
|
265
|
-
call.resolve();
|
|
266
271
|
}
|
|
267
272
|
|
|
268
273
|
@PluginMethod
|
|
@@ -396,12 +401,15 @@ public class InAppBrowserPlugin
|
|
|
396
401
|
new Runnable() {
|
|
397
402
|
@Override
|
|
398
403
|
public void run() {
|
|
399
|
-
webViewDialog
|
|
404
|
+
if (webViewDialog != null) {
|
|
405
|
+
webViewDialog.executeScript(scriptToRun.toString());
|
|
406
|
+
call.resolve();
|
|
407
|
+
} else {
|
|
408
|
+
call.reject("WebView is not initialized");
|
|
409
|
+
}
|
|
400
410
|
}
|
|
401
411
|
}
|
|
402
412
|
);
|
|
403
|
-
|
|
404
|
-
call.resolve();
|
|
405
413
|
}
|
|
406
414
|
|
|
407
415
|
@PluginMethod
|
|
@@ -409,22 +417,21 @@ public class InAppBrowserPlugin
|
|
|
409
417
|
String url = call.getString("url");
|
|
410
418
|
if (url == null || TextUtils.isEmpty(url)) {
|
|
411
419
|
call.reject("Invalid URL");
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
CookieManager cookieManager = CookieManager.getInstance();
|
|
423
|
+
String cookieString = cookieManager.getCookie(url);
|
|
424
|
+
JSObject result = new JSObject();
|
|
425
|
+
if (cookieString != null) {
|
|
426
|
+
String[] cookiePairs = cookieString.split("; ");
|
|
427
|
+
for (String cookie : cookiePairs) {
|
|
428
|
+
String[] parts = cookie.split("=", 2);
|
|
429
|
+
if (parts.length == 2) {
|
|
430
|
+
result.put(parts[0], parts[1]);
|
|
423
431
|
}
|
|
424
|
-
call.resolve(result);
|
|
425
432
|
}
|
|
426
|
-
call.resolve(new JSObject());
|
|
427
433
|
}
|
|
434
|
+
call.resolve(result);
|
|
428
435
|
}
|
|
429
436
|
|
|
430
437
|
@PluginMethod
|
|
@@ -753,8 +760,12 @@ public class InAppBrowserPlugin
|
|
|
753
760
|
new Runnable() {
|
|
754
761
|
@Override
|
|
755
762
|
public void run() {
|
|
756
|
-
webViewDialog
|
|
757
|
-
|
|
763
|
+
if (webViewDialog != null) {
|
|
764
|
+
webViewDialog.postMessageToJS(eventData);
|
|
765
|
+
call.resolve();
|
|
766
|
+
} else {
|
|
767
|
+
call.reject("WebView is not initialized");
|
|
768
|
+
}
|
|
758
769
|
}
|
|
759
770
|
}
|
|
760
771
|
);
|
|
@@ -765,37 +776,40 @@ public class InAppBrowserPlugin
|
|
|
765
776
|
String script = call.getString("code");
|
|
766
777
|
if (script == null || TextUtils.isEmpty(script)) {
|
|
767
778
|
call.reject("No script to run");
|
|
779
|
+
return;
|
|
768
780
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
public void run() {
|
|
781
|
+
this.getActivity()
|
|
782
|
+
.runOnUiThread(
|
|
783
|
+
new Runnable() {
|
|
784
|
+
@Override
|
|
785
|
+
public void run() {
|
|
786
|
+
if (webViewDialog != null) {
|
|
776
787
|
webViewDialog.executeScript(script);
|
|
788
|
+
call.resolve();
|
|
789
|
+
} else {
|
|
790
|
+
call.reject("WebView is not initialized");
|
|
777
791
|
}
|
|
778
792
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
call.resolve();
|
|
793
|
+
}
|
|
794
|
+
);
|
|
783
795
|
}
|
|
784
796
|
|
|
785
797
|
@PluginMethod
|
|
786
798
|
public void reload(PluginCall call) {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
799
|
+
this.getActivity()
|
|
800
|
+
.runOnUiThread(
|
|
801
|
+
new Runnable() {
|
|
802
|
+
@Override
|
|
803
|
+
public void run() {
|
|
804
|
+
if (webViewDialog != null) {
|
|
793
805
|
webViewDialog.reload();
|
|
806
|
+
call.resolve();
|
|
807
|
+
} else {
|
|
808
|
+
call.reject("WebView is not initialized");
|
|
794
809
|
}
|
|
795
810
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
call.resolve();
|
|
811
|
+
}
|
|
812
|
+
);
|
|
799
813
|
}
|
|
800
814
|
|
|
801
815
|
@PluginMethod
|
|
@@ -826,9 +840,10 @@ public class InAppBrowserPlugin
|
|
|
826
840
|
@Override
|
|
827
841
|
public void run() {
|
|
828
842
|
if (webViewDialog != null) {
|
|
843
|
+
String currentUrl = webViewDialog.getUrl();
|
|
829
844
|
notifyListeners(
|
|
830
845
|
"closeEvent",
|
|
831
|
-
new JSObject().put("url",
|
|
846
|
+
new JSObject().put("url", currentUrl)
|
|
832
847
|
);
|
|
833
848
|
webViewDialog.dismiss();
|
|
834
849
|
webViewDialog = null;
|
|
@@ -948,7 +948,7 @@ public class WebViewDialog extends Dialog {
|
|
|
948
948
|
}
|
|
949
949
|
}
|
|
950
950
|
|
|
951
|
-
// Apply system insets to WebView (compatible with all Android versions)
|
|
951
|
+
// Apply system insets to WebView content view (compatible with all Android versions)
|
|
952
952
|
ViewCompat.setOnApplyWindowInsetsListener(_webView, (v, windowInsets) -> {
|
|
953
953
|
Insets insets = windowInsets.getInsets(
|
|
954
954
|
WindowInsetsCompat.Type.systemBars()
|
|
@@ -971,9 +971,13 @@ public class WebViewDialog extends Dialog {
|
|
|
971
971
|
// On Android 15+, don't add top margin as it's handled by AppBarLayout
|
|
972
972
|
mlp.topMargin = 0;
|
|
973
973
|
} else {
|
|
974
|
-
//
|
|
975
|
-
mlp.topMargin =
|
|
976
|
-
|
|
974
|
+
// For all other Android versions, ensure bottom margin respects navigation bar
|
|
975
|
+
mlp.topMargin = 0; // Top is handled by toolbar
|
|
976
|
+
if (keyboardVisible) {
|
|
977
|
+
mlp.bottomMargin = 0;
|
|
978
|
+
} else {
|
|
979
|
+
mlp.bottomMargin = insets.bottom;
|
|
980
|
+
}
|
|
977
981
|
}
|
|
978
982
|
|
|
979
983
|
// These stay the same for all Android versions
|
|
@@ -984,41 +988,44 @@ public class WebViewDialog extends Dialog {
|
|
|
984
988
|
return WindowInsetsCompat.CONSUMED;
|
|
985
989
|
});
|
|
986
990
|
|
|
987
|
-
// Handle window decoration - version-specific
|
|
991
|
+
// Handle window decoration - version-specific handling
|
|
988
992
|
if (getWindow() != null) {
|
|
989
993
|
if (isAndroid15Plus) {
|
|
990
|
-
//
|
|
994
|
+
// Android 15+: Use edge-to-edge with proper insets handling
|
|
991
995
|
getWindow().setDecorFitsSystemWindows(false);
|
|
992
996
|
getWindow().setStatusBarColor(Color.TRANSPARENT);
|
|
997
|
+
getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
|
998
|
+
|
|
999
|
+
WindowInsetsControllerCompat controller =
|
|
1000
|
+
new WindowInsetsControllerCompat(
|
|
1001
|
+
getWindow(),
|
|
1002
|
+
getWindow().getDecorView()
|
|
1003
|
+
);
|
|
993
1004
|
|
|
994
1005
|
// Set status bar text color
|
|
995
|
-
int backgroundColor;
|
|
996
1006
|
if (
|
|
997
1007
|
_options.getToolbarColor() != null &&
|
|
998
1008
|
!_options.getToolbarColor().isEmpty()
|
|
999
1009
|
) {
|
|
1000
1010
|
try {
|
|
1001
|
-
backgroundColor = Color.parseColor(_options.getToolbarColor());
|
|
1011
|
+
int backgroundColor = Color.parseColor(_options.getToolbarColor());
|
|
1002
1012
|
boolean isDarkBackground = isDarkColor(backgroundColor);
|
|
1003
|
-
WindowInsetsControllerCompat controller =
|
|
1004
|
-
new WindowInsetsControllerCompat(
|
|
1005
|
-
getWindow(),
|
|
1006
|
-
getWindow().getDecorView()
|
|
1007
|
-
);
|
|
1008
1013
|
controller.setAppearanceLightStatusBars(!isDarkBackground);
|
|
1009
1014
|
} catch (IllegalArgumentException e) {
|
|
1010
1015
|
// Ignore color parsing errors
|
|
1011
1016
|
}
|
|
1012
1017
|
}
|
|
1013
1018
|
} else if (Build.VERSION.SDK_INT >= 30) {
|
|
1014
|
-
// Android 11-14:
|
|
1019
|
+
// Android 11-14: Keep navigation bar transparent but respect status bar
|
|
1020
|
+
getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
|
1021
|
+
|
|
1015
1022
|
WindowInsetsControllerCompat controller =
|
|
1016
1023
|
new WindowInsetsControllerCompat(
|
|
1017
1024
|
getWindow(),
|
|
1018
1025
|
getWindow().getDecorView()
|
|
1019
1026
|
);
|
|
1020
1027
|
|
|
1021
|
-
//
|
|
1028
|
+
// Set status bar color to match toolbar or use system default
|
|
1022
1029
|
if (
|
|
1023
1030
|
_options.getToolbarColor() != null &&
|
|
1024
1031
|
!_options.getToolbarColor().isEmpty()
|
|
@@ -1026,23 +1033,34 @@ public class WebViewDialog extends Dialog {
|
|
|
1026
1033
|
try {
|
|
1027
1034
|
int toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
1028
1035
|
getWindow().setStatusBarColor(toolbarColor);
|
|
1029
|
-
|
|
1030
1036
|
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
1031
1037
|
controller.setAppearanceLightStatusBars(!isDarkBackground);
|
|
1032
1038
|
} catch (IllegalArgumentException e) {
|
|
1033
|
-
//
|
|
1039
|
+
// Follow system theme if color parsing fails
|
|
1040
|
+
boolean isDarkTheme = isDarkThemeEnabled();
|
|
1041
|
+
int statusBarColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
1042
|
+
getWindow().setStatusBarColor(statusBarColor);
|
|
1043
|
+
controller.setAppearanceLightStatusBars(!isDarkTheme);
|
|
1034
1044
|
}
|
|
1045
|
+
} else {
|
|
1046
|
+
// Follow system theme if no toolbar color provided
|
|
1047
|
+
boolean isDarkTheme = isDarkThemeEnabled();
|
|
1048
|
+
int statusBarColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
1049
|
+
getWindow().setStatusBarColor(statusBarColor);
|
|
1050
|
+
controller.setAppearanceLightStatusBars(!isDarkTheme);
|
|
1035
1051
|
}
|
|
1036
1052
|
} else {
|
|
1037
|
-
// Pre-Android 11:
|
|
1053
|
+
// Pre-Android 11: Use deprecated flags for edge-to-edge navigation bar only
|
|
1038
1054
|
getWindow()
|
|
1039
1055
|
.getDecorView()
|
|
1040
1056
|
.setSystemUiVisibility(
|
|
1041
1057
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
|
1042
|
-
View.
|
|
1058
|
+
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
1043
1059
|
);
|
|
1044
1060
|
|
|
1045
|
-
|
|
1061
|
+
getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
|
1062
|
+
|
|
1063
|
+
// Set status bar color to match toolbar
|
|
1046
1064
|
if (
|
|
1047
1065
|
_options.getToolbarColor() != null &&
|
|
1048
1066
|
!_options.getToolbarColor().isEmpty()
|
|
@@ -1051,7 +1069,7 @@ public class WebViewDialog extends Dialog {
|
|
|
1051
1069
|
int toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
1052
1070
|
getWindow().setStatusBarColor(toolbarColor);
|
|
1053
1071
|
} catch (IllegalArgumentException e) {
|
|
1054
|
-
//
|
|
1072
|
+
// Use system default
|
|
1055
1073
|
}
|
|
1056
1074
|
}
|
|
1057
1075
|
}
|
|
@@ -1068,7 +1086,11 @@ public class WebViewDialog extends Dialog {
|
|
|
1068
1086
|
"window.dispatchEvent(new CustomEvent('messageFromNative', " +
|
|
1069
1087
|
jsonDetail +
|
|
1070
1088
|
"));";
|
|
1071
|
-
_webView.post(() ->
|
|
1089
|
+
_webView.post(() -> {
|
|
1090
|
+
if (_webView != null) {
|
|
1091
|
+
_webView.evaluateJavascript(script, null);
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1072
1094
|
} catch (Exception e) {
|
|
1073
1095
|
Log.e(
|
|
1074
1096
|
"postMessageToJS",
|
|
@@ -1079,6 +1101,9 @@ public class WebViewDialog extends Dialog {
|
|
|
1079
1101
|
}
|
|
1080
1102
|
|
|
1081
1103
|
private void injectJavaScriptInterface() {
|
|
1104
|
+
if (_webView == null) {
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1082
1107
|
String script =
|
|
1083
1108
|
"if (!window.mobileApp) { " +
|
|
1084
1109
|
" window.mobileApp = { " +
|
|
@@ -1126,7 +1151,14 @@ public class WebViewDialog extends Dialog {
|
|
|
1126
1151
|
new Runnable() {
|
|
1127
1152
|
@Override
|
|
1128
1153
|
public void run() {
|
|
1129
|
-
_webView
|
|
1154
|
+
if (_webView != null) {
|
|
1155
|
+
_webView.evaluateJavascript(script, null);
|
|
1156
|
+
} else {
|
|
1157
|
+
// If WebView is null, release semaphore to prevent deadlock
|
|
1158
|
+
if (preShowSemaphore != null) {
|
|
1159
|
+
preShowSemaphore.release();
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1130
1162
|
}
|
|
1131
1163
|
}
|
|
1132
1164
|
);
|
|
@@ -1317,36 +1349,45 @@ public class WebViewDialog extends Dialog {
|
|
|
1317
1349
|
}
|
|
1318
1350
|
|
|
1319
1351
|
public void reload() {
|
|
1320
|
-
if (_webView
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1352
|
+
if (_webView == null) {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
// First stop any ongoing loading
|
|
1356
|
+
_webView.stopLoading();
|
|
1357
|
+
|
|
1358
|
+
// Check if there's a URL to reload
|
|
1359
|
+
String currentUrl = _webView.getUrl();
|
|
1360
|
+
if (currentUrl != null) {
|
|
1361
|
+
// Reload the current page
|
|
1362
|
+
_webView.reload();
|
|
1363
|
+
Log.d("InAppBrowser", "Reloading page: " + currentUrl);
|
|
1364
|
+
} else if (_options != null && _options.getUrl() != null) {
|
|
1365
|
+
// If webView URL is null but we have an initial URL, load that
|
|
1366
|
+
setUrl(_options.getUrl());
|
|
1367
|
+
Log.d("InAppBrowser", "Loading initial URL: " + _options.getUrl());
|
|
1334
1368
|
}
|
|
1335
1369
|
}
|
|
1336
1370
|
|
|
1337
1371
|
public void destroy() {
|
|
1338
|
-
_webView
|
|
1372
|
+
if (_webView != null) {
|
|
1373
|
+
_webView.destroy();
|
|
1374
|
+
}
|
|
1339
1375
|
}
|
|
1340
1376
|
|
|
1341
1377
|
public String getUrl() {
|
|
1342
|
-
return _webView.getUrl();
|
|
1378
|
+
return _webView != null ? _webView.getUrl() : "";
|
|
1343
1379
|
}
|
|
1344
1380
|
|
|
1345
1381
|
public void executeScript(String script) {
|
|
1346
|
-
_webView
|
|
1382
|
+
if (_webView != null) {
|
|
1383
|
+
_webView.evaluateJavascript(script, null);
|
|
1384
|
+
}
|
|
1347
1385
|
}
|
|
1348
1386
|
|
|
1349
1387
|
public void setUrl(String url) {
|
|
1388
|
+
if (_webView == null) {
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1350
1391
|
Map<String, String> requestHeaders = new HashMap<>();
|
|
1351
1392
|
if (_options.getHeaders() != null) {
|
|
1352
1393
|
Iterator<String> keys = _options.getHeaders().keys();
|
|
@@ -1496,10 +1537,11 @@ public class WebViewDialog extends Dialog {
|
|
|
1496
1537
|
_webView.stopLoading();
|
|
1497
1538
|
|
|
1498
1539
|
// Check if there's a URL to reload
|
|
1499
|
-
|
|
1540
|
+
String currentUrl = _webView.getUrl();
|
|
1541
|
+
if (currentUrl != null) {
|
|
1500
1542
|
// Reload the current page
|
|
1501
1543
|
_webView.reload();
|
|
1502
|
-
Log.d("InAppBrowser", "Reloading page: " +
|
|
1544
|
+
Log.d("InAppBrowser", "Reloading page: " + currentUrl);
|
|
1503
1545
|
} else if (_options.getUrl() != null) {
|
|
1504
1546
|
// If webView URL is null but we have an initial URL, load that
|
|
1505
1547
|
setUrl(_options.getUrl());
|
|
@@ -1944,6 +1986,9 @@ public class WebViewDialog extends Dialog {
|
|
|
1944
1986
|
WebView view,
|
|
1945
1987
|
WebResourceRequest request
|
|
1946
1988
|
) {
|
|
1989
|
+
if (view == null || _webView == null) {
|
|
1990
|
+
return false;
|
|
1991
|
+
}
|
|
1947
1992
|
Context context = view.getContext();
|
|
1948
1993
|
String url = request.getUrl().toString();
|
|
1949
1994
|
Log.d("InAppBrowser", "shouldOverrideUrlLoading: " + url);
|
|
@@ -1997,6 +2042,9 @@ public class WebViewDialog extends Dialog {
|
|
|
1997
2042
|
WebView view,
|
|
1998
2043
|
WebResourceRequest request
|
|
1999
2044
|
) {
|
|
2045
|
+
if (view == null || _webView == null) {
|
|
2046
|
+
return null;
|
|
2047
|
+
}
|
|
2000
2048
|
Pattern pattern = _options.getProxyRequestsPattern();
|
|
2001
2049
|
if (pattern == null) {
|
|
2002
2050
|
return null;
|
|
@@ -2078,6 +2126,12 @@ public class WebViewDialog extends Dialog {
|
|
|
2078
2126
|
String host,
|
|
2079
2127
|
String realm
|
|
2080
2128
|
) {
|
|
2129
|
+
if (view == null || _webView == null) {
|
|
2130
|
+
if (handler != null) {
|
|
2131
|
+
handler.cancel();
|
|
2132
|
+
}
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2081
2135
|
final String sourceUrl = _options.getUrl();
|
|
2082
2136
|
final String url = view.getUrl();
|
|
2083
2137
|
final JSObject credentials = _options.getCredentials();
|
|
@@ -2141,12 +2195,18 @@ public class WebViewDialog extends Dialog {
|
|
|
2141
2195
|
|
|
2142
2196
|
@Override
|
|
2143
2197
|
public void onLoadResource(WebView view, String url) {
|
|
2198
|
+
if (view == null || _webView == null) {
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2144
2201
|
super.onLoadResource(view, url);
|
|
2145
2202
|
}
|
|
2146
2203
|
|
|
2147
2204
|
@Override
|
|
2148
2205
|
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
|
2149
2206
|
super.onPageStarted(view, url, favicon);
|
|
2207
|
+
if (view == null || _webView == null) {
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2150
2210
|
try {
|
|
2151
2211
|
URI uri = new URI(url);
|
|
2152
2212
|
if (TextUtils.isEmpty(_options.getTitle())) {
|
|
@@ -2162,6 +2222,9 @@ public class WebViewDialog extends Dialog {
|
|
|
2162
2222
|
String url,
|
|
2163
2223
|
boolean isReload
|
|
2164
2224
|
) {
|
|
2225
|
+
if (view == null || _webView == null) {
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
2165
2228
|
if (!isReload) {
|
|
2166
2229
|
_options.getCallbacks().urlChangeEvent(url);
|
|
2167
2230
|
}
|
|
@@ -2172,6 +2235,9 @@ public class WebViewDialog extends Dialog {
|
|
|
2172
2235
|
@Override
|
|
2173
2236
|
public void onPageFinished(WebView view, String url) {
|
|
2174
2237
|
super.onPageFinished(view, url);
|
|
2238
|
+
if (view == null || _webView == null) {
|
|
2239
|
+
return;
|
|
2240
|
+
}
|
|
2175
2241
|
if (!isInitialized) {
|
|
2176
2242
|
isInitialized = true;
|
|
2177
2243
|
_webView.clearHistory();
|
|
@@ -2223,10 +2289,20 @@ public class WebViewDialog extends Dialog {
|
|
|
2223
2289
|
}
|
|
2224
2290
|
|
|
2225
2291
|
ImageButton backButton = _toolbar.findViewById(R.id.backButton);
|
|
2226
|
-
if (_webView.canGoBack()) {
|
|
2292
|
+
if (_webView != null && _webView.canGoBack()) {
|
|
2227
2293
|
backButton.setImageResource(R.drawable.arrow_back_enabled);
|
|
2228
2294
|
backButton.setEnabled(true);
|
|
2229
2295
|
backButton.setColorFilter(iconColor);
|
|
2296
|
+
backButton.setOnClickListener(
|
|
2297
|
+
new View.OnClickListener() {
|
|
2298
|
+
@Override
|
|
2299
|
+
public void onClick(View view) {
|
|
2300
|
+
if (_webView != null && _webView.canGoBack()) {
|
|
2301
|
+
_webView.goBack();
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
);
|
|
2230
2306
|
} else {
|
|
2231
2307
|
backButton.setImageResource(R.drawable.arrow_back_disabled);
|
|
2232
2308
|
backButton.setEnabled(false);
|
|
@@ -2241,10 +2317,20 @@ public class WebViewDialog extends Dialog {
|
|
|
2241
2317
|
}
|
|
2242
2318
|
|
|
2243
2319
|
ImageButton forwardButton = _toolbar.findViewById(R.id.forwardButton);
|
|
2244
|
-
if (_webView.canGoForward()) {
|
|
2320
|
+
if (_webView != null && _webView.canGoForward()) {
|
|
2245
2321
|
forwardButton.setImageResource(R.drawable.arrow_forward_enabled);
|
|
2246
2322
|
forwardButton.setEnabled(true);
|
|
2247
2323
|
forwardButton.setColorFilter(iconColor);
|
|
2324
|
+
forwardButton.setOnClickListener(
|
|
2325
|
+
new View.OnClickListener() {
|
|
2326
|
+
@Override
|
|
2327
|
+
public void onClick(View view) {
|
|
2328
|
+
if (_webView != null && _webView.canGoForward()) {
|
|
2329
|
+
_webView.goForward();
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
);
|
|
2248
2334
|
} else {
|
|
2249
2335
|
forwardButton.setImageResource(R.drawable.arrow_forward_disabled);
|
|
2250
2336
|
forwardButton.setEnabled(false);
|
|
@@ -2269,6 +2355,9 @@ public class WebViewDialog extends Dialog {
|
|
|
2269
2355
|
WebResourceError error
|
|
2270
2356
|
) {
|
|
2271
2357
|
super.onReceivedError(view, request, error);
|
|
2358
|
+
if (view == null || _webView == null) {
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2272
2361
|
_options.getCallbacks().pageLoadError();
|
|
2273
2362
|
}
|
|
2274
2363
|
|
|
@@ -2279,6 +2368,12 @@ public class WebViewDialog extends Dialog {
|
|
|
2279
2368
|
SslErrorHandler handler,
|
|
2280
2369
|
SslError error
|
|
2281
2370
|
) {
|
|
2371
|
+
if (view == null || _webView == null) {
|
|
2372
|
+
if (handler != null) {
|
|
2373
|
+
handler.cancel();
|
|
2374
|
+
}
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2282
2377
|
boolean ignoreSSLUntrustedError = _options.ignoreUntrustedSSLError();
|
|
2283
2378
|
if (
|
|
2284
2379
|
ignoreSSLUntrustedError &&
|
|
@@ -2295,14 +2390,18 @@ public class WebViewDialog extends Dialog {
|
|
|
2295
2390
|
@Override
|
|
2296
2391
|
public void onBackPressed() {
|
|
2297
2392
|
if (
|
|
2393
|
+
_webView != null &&
|
|
2298
2394
|
_webView.canGoBack() &&
|
|
2299
2395
|
(TextUtils.equals(_options.getToolbarType(), "navigation") ||
|
|
2300
2396
|
_options.getActiveNativeNavigationForWebview())
|
|
2301
2397
|
) {
|
|
2302
2398
|
_webView.goBack();
|
|
2303
2399
|
} else if (!_options.getDisableGoBackOnNativeApplication()) {
|
|
2304
|
-
|
|
2305
|
-
|
|
2400
|
+
String currentUrl = _webView != null ? _webView.getUrl() : "";
|
|
2401
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
2402
|
+
if (_webView != null) {
|
|
2403
|
+
_webView.destroy();
|
|
2404
|
+
}
|
|
2306
2405
|
super.onBackPressed();
|
|
2307
2406
|
}
|
|
2308
2407
|
}
|
|
@@ -2488,7 +2587,11 @@ public class WebViewDialog extends Dialog {
|
|
|
2488
2587
|
})();""";
|
|
2489
2588
|
|
|
2490
2589
|
// Execute the script in the WebView
|
|
2491
|
-
_webView.post(() ->
|
|
2590
|
+
_webView.post(() -> {
|
|
2591
|
+
if (_webView != null) {
|
|
2592
|
+
_webView.evaluateJavascript(script, null);
|
|
2593
|
+
}
|
|
2594
|
+
});
|
|
2492
2595
|
|
|
2493
2596
|
Log.d("InAppBrowser", "Applied minimal date picker fixes");
|
|
2494
2597
|
}
|
|
@@ -369,14 +369,14 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
if self.bridge?.statusBarVisible == true {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
372
|
+
let subviews = self.bridge?.webView?.superview?.subviews
|
|
373
|
+
if let emptyStatusBarIndex = subviews?.firstIndex(where: { $0.subviews.isEmpty }) {
|
|
374
|
+
if let emptyStatusBar = subviews?[emptyStatusBarIndex] {
|
|
375
|
+
webViewController.capacitorStatusBar = emptyStatusBar
|
|
376
|
+
emptyStatusBar.removeFromSuperview()
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
380
|
|
|
381
381
|
webViewController.source = .remote(url)
|
|
382
382
|
webViewController.leftNavigationBarItemTypes = []
|
|
@@ -697,14 +697,14 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
if self.bridge?.statusBarVisible == true {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
700
|
+
let subviews = self.bridge?.webView?.superview?.subviews
|
|
701
|
+
if let emptyStatusBarIndex = subviews?.firstIndex(where: { $0.subviews.isEmpty }) {
|
|
702
|
+
if let emptyStatusBar = subviews?[emptyStatusBarIndex] {
|
|
703
|
+
webViewController.capacitorStatusBar = emptyStatusBar
|
|
704
|
+
emptyStatusBar.removeFromSuperview()
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
708
|
|
|
709
709
|
webViewController.source = .remote(url)
|
|
710
710
|
webViewController.leftNavigationBarItemTypes = [.back, .forward, .reload]
|
|
@@ -277,9 +277,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
277
277
|
// Check if custom image is provided
|
|
278
278
|
if let image = activityBarButtonItemImage {
|
|
279
279
|
let button = UIBarButtonItem(image: image.withRenderingMode(.alwaysTemplate),
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
280
|
+
style: .plain,
|
|
281
|
+
target: self,
|
|
282
|
+
action: #selector(activityDidClick(sender:)))
|
|
283
283
|
|
|
284
284
|
// Apply tint from navigation bar or from tintColor property
|
|
285
285
|
if let tintColor = self.tintColor ?? self.navigationController?.navigationBar.tintColor {
|
|
@@ -291,8 +291,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
291
291
|
} else {
|
|
292
292
|
// Use system share icon
|
|
293
293
|
let button = UIBarButtonItem(barButtonSystemItem: .action,
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
target: self,
|
|
295
|
+
action: #selector(activityDidClick(sender:)))
|
|
296
296
|
|
|
297
297
|
// Apply tint from navigation bar or from tintColor property
|
|
298
298
|
if let tintColor = self.tintColor ?? self.navigationController?.navigationBar.tintColor {
|
|
@@ -404,9 +404,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
404
404
|
|
|
405
405
|
// Create a properly tinted button
|
|
406
406
|
let buttonItem = UIBarButtonItem(image: buttonNearDoneIcon?.withRenderingMode(.alwaysTemplate),
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
407
|
+
style: .plain,
|
|
408
|
+
target: self,
|
|
409
|
+
action: #selector(buttonNearDoneDidClick))
|
|
410
410
|
buttonItem.tintColor = tintColor
|
|
411
411
|
|
|
412
412
|
// Add it to right items
|
|
@@ -444,7 +444,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
444
444
|
// Method to send a message from Swift to JavaScript
|
|
445
445
|
open func postMessageToJS(message: [String: Any]) {
|
|
446
446
|
if let jsonData = try? JSONSerialization.data(withJSONObject: message, options: []),
|
|
447
|
-
|
|
447
|
+
let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
448
448
|
let script = "window.dispatchEvent(new CustomEvent('messageFromNative', { detail: \(jsonString) }));"
|
|
449
449
|
DispatchQueue.main.async {
|
|
450
450
|
self.webView?.evaluateJavaScript(script, completionHandler: nil)
|
|
@@ -478,20 +478,20 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
478
478
|
semaphore.signal()
|
|
479
479
|
} else if message.name == "close" {
|
|
480
480
|
closeView()
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
481
|
+
} else if message.name == "magicPrint" {
|
|
482
|
+
if let webView = self.webView {
|
|
483
|
+
let printController = UIPrintInteractionController.shared
|
|
484
484
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
485
|
+
let printInfo = UIPrintInfo(dictionary: nil)
|
|
486
|
+
printInfo.outputType = .general
|
|
487
|
+
printInfo.jobName = "Print Job"
|
|
488
488
|
|
|
489
|
-
|
|
490
|
-
|
|
489
|
+
printController.printInfo = printInfo
|
|
490
|
+
printController.printFormatter = webView.viewPrintFormatter()
|
|
491
491
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
492
|
+
printController.present(animated: true, completionHandler: nil)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
func injectJavaScriptInterface() {
|
|
@@ -509,17 +509,17 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
509
509
|
};
|
|
510
510
|
}
|
|
511
511
|
"""
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
512
|
+
DispatchQueue.main.async {
|
|
513
|
+
self.webView?.evaluateJavaScript(script) { result, error in
|
|
514
|
+
if let error = error {
|
|
515
|
+
print("JavaScript evaluation error: \(error)")
|
|
516
|
+
} else if let result = result {
|
|
517
|
+
print("JavaScript result: \(result)")
|
|
518
|
+
} else {
|
|
519
|
+
print("JavaScript executed with no result")
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
open func initWebview(isInspectable: Bool = true) {
|
|
@@ -534,35 +534,35 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
534
534
|
userContentController.add(self, name: "preShowScriptError")
|
|
535
535
|
userContentController.add(self, name: "preShowScriptSuccess")
|
|
536
536
|
userContentController.add(self, name: "close")
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
537
|
+
userContentController.add(self, name: "magicPrint")
|
|
538
|
+
|
|
539
|
+
// Inject JavaScript to override window.print
|
|
540
|
+
let script = WKUserScript(
|
|
541
|
+
source: """
|
|
542
|
+
window.print = function() {
|
|
543
|
+
window.webkit.messageHandlers.magicPrint.postMessage('magicPrint');
|
|
544
|
+
};
|
|
545
|
+
""",
|
|
546
|
+
injectionTime: .atDocumentStart,
|
|
547
|
+
forMainFrameOnly: false
|
|
548
|
+
)
|
|
549
|
+
userContentController.addUserScript(script)
|
|
550
550
|
|
|
551
551
|
webConfiguration.allowsInlineMediaPlayback = true
|
|
552
552
|
webConfiguration.userContentController = userContentController
|
|
553
553
|
|
|
554
554
|
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
|
|
555
555
|
|
|
556
|
-
// if webView.responds(to: Selector(("setInspectable:"))) {
|
|
557
|
-
// // Fix: https://stackoverflow.com/questions/76216183/how-to-debug-wkwebview-in-ios-16-4-1-using-xcode-14-2/76603043#76603043
|
|
558
|
-
// webView.perform(Selector(("setInspectable:")), with: isInspectable)
|
|
559
|
-
// }
|
|
556
|
+
// if webView.responds(to: Selector(("setInspectable:"))) {
|
|
557
|
+
// // Fix: https://stackoverflow.com/questions/76216183/how-to-debug-wkwebview-in-ios-16-4-1-using-xcode-14-2/76603043#76603043
|
|
558
|
+
// webView.perform(Selector(("setInspectable:")), with: isInspectable)
|
|
559
|
+
// }
|
|
560
560
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
561
|
+
if #available(iOS 16.4, *) {
|
|
562
|
+
webView.isInspectable = true
|
|
563
|
+
} else {
|
|
564
|
+
// Fallback on earlier versions
|
|
565
|
+
}
|
|
566
566
|
|
|
567
567
|
if self.blankNavigationTab {
|
|
568
568
|
// First add the webView to view hierarchy
|
|
@@ -1438,8 +1438,8 @@ extension WKWebViewController: WKNavigationDelegate {
|
|
|
1438
1438
|
|
|
1439
1439
|
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
|
|
1440
1440
|
if let credentials = credentials,
|
|
1441
|
-
|
|
1442
|
-
|
|
1441
|
+
challenge.protectionSpace.receivesCredentialSecurely,
|
|
1442
|
+
let url = webView.url, challenge.protectionSpace.host == url.host, challenge.protectionSpace.protocol == url.scheme, challenge.protectionSpace.port == url.port ?? (url.scheme == "https" ? 443 : url.scheme == "http" ? 80 : nil) {
|
|
1443
1443
|
let urlCredential = URLCredential(user: credentials.username, password: credentials.password, persistence: .none)
|
|
1444
1444
|
completionHandler(.useCredential, urlCredential)
|
|
1445
1445
|
} else if let bypassedSSLHosts = bypassedSSLHosts, bypassedSSLHosts.contains(challenge.protectionSpace.host) {
|
|
@@ -1451,8 +1451,8 @@ extension WKWebViewController: WKNavigationDelegate {
|
|
|
1451
1451
|
return
|
|
1452
1452
|
}
|
|
1453
1453
|
/* allows to open links with self-signed certificates
|
|
1454
|
-
|
|
1455
|
-
|
|
1454
|
+
Follow Apple's guidelines https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication
|
|
1455
|
+
*/
|
|
1456
1456
|
guard let serverTrust = challenge.protectionSpace.serverTrust else {
|
|
1457
1457
|
completionHandler(.useCredential, nil)
|
|
1458
1458
|
return
|