@capgo/inappbrowser 6.10.0 → 6.11.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/README.md +33 -99
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +23 -6
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +12 -6
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +159 -145
- package/dist/docs.json +9 -636
- package/dist/esm/definitions.d.ts +9 -9
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Plugin/InAppBrowserPlugin.swift +44 -36
- package/ios/Plugin/WKWebViewController.swift +19 -6
- package/package.json +1 -1
|
@@ -15,7 +15,6 @@ import android.graphics.Picture;
|
|
|
15
15
|
import android.graphics.drawable.PictureDrawable;
|
|
16
16
|
import android.net.Uri;
|
|
17
17
|
import android.net.http.SslError;
|
|
18
|
-
import android.os.Build;
|
|
19
18
|
import android.text.TextUtils;
|
|
20
19
|
import android.util.Base64;
|
|
21
20
|
import android.util.Log;
|
|
@@ -37,7 +36,6 @@ import android.widget.ImageButton;
|
|
|
37
36
|
import android.widget.TextView;
|
|
38
37
|
import android.widget.Toast;
|
|
39
38
|
import android.widget.Toolbar;
|
|
40
|
-
import androidx.annotation.RequiresApi;
|
|
41
39
|
import androidx.core.view.WindowInsetsControllerCompat;
|
|
42
40
|
import com.caverock.androidsvg.SVG;
|
|
43
41
|
import com.caverock.androidsvg.SVGParseException;
|
|
@@ -45,15 +43,12 @@ import com.getcapacitor.JSObject;
|
|
|
45
43
|
import java.io.ByteArrayInputStream;
|
|
46
44
|
import java.io.IOException;
|
|
47
45
|
import java.io.InputStream;
|
|
48
|
-
import java.net.CookiePolicy;
|
|
49
46
|
import java.net.URI;
|
|
50
47
|
import java.net.URISyntaxException;
|
|
51
|
-
import java.net.URL;
|
|
52
48
|
import java.nio.charset.StandardCharsets;
|
|
53
49
|
import java.util.Arrays;
|
|
54
50
|
import java.util.HashMap;
|
|
55
51
|
import java.util.Iterator;
|
|
56
|
-
import java.util.List;
|
|
57
52
|
import java.util.Map;
|
|
58
53
|
import java.util.Objects;
|
|
59
54
|
import java.util.UUID;
|
|
@@ -61,7 +56,6 @@ import java.util.concurrent.ExecutorService;
|
|
|
61
56
|
import java.util.concurrent.Executors;
|
|
62
57
|
import java.util.concurrent.Semaphore;
|
|
63
58
|
import java.util.concurrent.TimeUnit;
|
|
64
|
-
import java.util.function.Consumer;
|
|
65
59
|
import java.util.regex.Matcher;
|
|
66
60
|
import java.util.regex.Pattern;
|
|
67
61
|
import org.json.JSONException;
|
|
@@ -69,10 +63,10 @@ import org.json.JSONObject;
|
|
|
69
63
|
|
|
70
64
|
public class WebViewDialog extends Dialog {
|
|
71
65
|
|
|
72
|
-
private class ProxiedRequest {
|
|
66
|
+
private static class ProxiedRequest {
|
|
73
67
|
|
|
74
68
|
private WebResourceResponse response;
|
|
75
|
-
private Semaphore semaphore;
|
|
69
|
+
private final Semaphore semaphore;
|
|
76
70
|
|
|
77
71
|
public WebResourceResponse getResponse() {
|
|
78
72
|
return response;
|
|
@@ -86,21 +80,23 @@ public class WebViewDialog extends Dialog {
|
|
|
86
80
|
|
|
87
81
|
private WebView _webView;
|
|
88
82
|
private Toolbar _toolbar;
|
|
89
|
-
private Options _options;
|
|
90
|
-
private Context _context;
|
|
83
|
+
private Options _options = null;
|
|
84
|
+
private final Context _context;
|
|
91
85
|
public Activity activity;
|
|
92
86
|
private boolean isInitialized = false;
|
|
93
|
-
private WebView capacitorWebView;
|
|
94
|
-
private
|
|
87
|
+
private final WebView capacitorWebView;
|
|
88
|
+
private final Map<String, ProxiedRequest> proxiedRequestsHashmap =
|
|
89
|
+
new HashMap<>();
|
|
90
|
+
private final ExecutorService executorService =
|
|
91
|
+
Executors.newCachedThreadPool();
|
|
95
92
|
|
|
96
93
|
Semaphore preShowSemaphore = null;
|
|
97
|
-
String
|
|
94
|
+
String preShowError = null;
|
|
98
95
|
|
|
99
96
|
public PermissionRequest currentPermissionRequest;
|
|
100
97
|
public static final int FILE_CHOOSER_REQUEST_CODE = 1000;
|
|
101
98
|
public ValueCallback<Uri> mUploadMessage;
|
|
102
99
|
public ValueCallback<Uri[]> mFilePathCallback;
|
|
103
|
-
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
|
104
100
|
|
|
105
101
|
public interface PermissionHandler {
|
|
106
102
|
void handleCameraPermissionRequest(PermissionRequest request);
|
|
@@ -108,7 +104,7 @@ public class WebViewDialog extends Dialog {
|
|
|
108
104
|
void handleMicrophonePermissionRequest(PermissionRequest request);
|
|
109
105
|
}
|
|
110
106
|
|
|
111
|
-
private PermissionHandler permissionHandler;
|
|
107
|
+
private final PermissionHandler permissionHandler;
|
|
112
108
|
|
|
113
109
|
public WebViewDialog(
|
|
114
110
|
Context context,
|
|
@@ -123,30 +119,48 @@ public class WebViewDialog extends Dialog {
|
|
|
123
119
|
this.permissionHandler = permissionHandler;
|
|
124
120
|
this.isInitialized = false;
|
|
125
121
|
this.capacitorWebView = capacitorWebView;
|
|
126
|
-
this.proxiedRequestsHashmap = new HashMap<>();
|
|
127
122
|
}
|
|
128
123
|
|
|
129
|
-
|
|
124
|
+
// Add this class to provide safer JavaScript interface
|
|
125
|
+
private class JavaScriptInterface {
|
|
130
126
|
|
|
131
127
|
@JavascriptInterface
|
|
132
128
|
public void postMessage(String message) {
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
try {
|
|
130
|
+
// Handle message from JavaScript safely
|
|
131
|
+
if (message == null || message.isEmpty()) {
|
|
132
|
+
Log.e("InAppBrowser", "Received empty message from WebView");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
_options.getCallbacks().javascriptCallback(message);
|
|
136
|
+
} catch (Exception e) {
|
|
137
|
+
Log.e("InAppBrowser", "Error in postMessage: " + e.getMessage());
|
|
138
|
+
}
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
@JavascriptInterface
|
|
138
142
|
public void close() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
try {
|
|
144
|
+
// close webview safely
|
|
145
|
+
if (activity != null) {
|
|
146
|
+
activity.runOnUiThread(() -> {
|
|
147
|
+
try {
|
|
148
|
+
dismiss();
|
|
149
|
+
if (_webView != null) {
|
|
150
|
+
String currentUrl = _webView.getUrl();
|
|
151
|
+
if (_options != null && _options.getCallbacks() != null) {
|
|
152
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
153
|
+
}
|
|
154
|
+
_webView.destroy();
|
|
155
|
+
}
|
|
156
|
+
} catch (Exception e) {
|
|
157
|
+
Log.e("InAppBrowser", "Error closing WebView: " + e.getMessage());
|
|
158
|
+
}
|
|
159
|
+
});
|
|
148
160
|
}
|
|
149
|
-
)
|
|
161
|
+
} catch (Exception e) {
|
|
162
|
+
Log.e("InAppBrowser", "Error in close: " + e.getMessage());
|
|
163
|
+
}
|
|
150
164
|
}
|
|
151
165
|
}
|
|
152
166
|
|
|
@@ -154,23 +168,31 @@ public class WebViewDialog extends Dialog {
|
|
|
154
168
|
|
|
155
169
|
@JavascriptInterface
|
|
156
170
|
public void error(String error) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
try {
|
|
172
|
+
// Handle message from JavaScript
|
|
173
|
+
if (preShowSemaphore != null) {
|
|
174
|
+
preShowError = error;
|
|
175
|
+
preShowSemaphore.release();
|
|
176
|
+
}
|
|
177
|
+
} catch (Exception e) {
|
|
178
|
+
Log.e("InAppBrowser", "Error in error callback: " + e.getMessage());
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
181
|
|
|
164
182
|
@JavascriptInterface
|
|
165
183
|
public void success() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
preShowSemaphore
|
|
184
|
+
try {
|
|
185
|
+
// Handle message from JavaScript
|
|
186
|
+
if (preShowSemaphore != null) {
|
|
187
|
+
preShowSemaphore.release();
|
|
188
|
+
}
|
|
189
|
+
} catch (Exception e) {
|
|
190
|
+
Log.e("InAppBrowser", "Error in success callback: " + e.getMessage());
|
|
169
191
|
}
|
|
170
192
|
}
|
|
171
193
|
}
|
|
172
194
|
|
|
173
|
-
@SuppressLint("SetJavaScriptEnabled")
|
|
195
|
+
@SuppressLint({ "SetJavaScriptEnabled", "AddJavascriptInterface" })
|
|
174
196
|
public void presentWebView() {
|
|
175
197
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
176
198
|
setCancelable(true);
|
|
@@ -210,9 +232,6 @@ public class WebViewDialog extends Dialog {
|
|
|
210
232
|
_webView.getSettings().setDatabaseEnabled(true);
|
|
211
233
|
_webView.getSettings().setDomStorageEnabled(true);
|
|
212
234
|
_webView.getSettings().setAllowFileAccess(true);
|
|
213
|
-
_webView
|
|
214
|
-
.getSettings()
|
|
215
|
-
.setPluginState(android.webkit.WebSettings.PluginState.ON);
|
|
216
235
|
_webView.getSettings().setLoadWithOverviewMode(true);
|
|
217
236
|
_webView.getSettings().setUseWideViewPort(true);
|
|
218
237
|
_webView.getSettings().setAllowFileAccessFromFileURLs(true);
|
|
@@ -228,7 +247,7 @@ public class WebViewDialog extends Dialog {
|
|
|
228
247
|
public boolean onShowFileChooser(
|
|
229
248
|
WebView webView,
|
|
230
249
|
ValueCallback<Uri[]> filePathCallback,
|
|
231
|
-
|
|
250
|
+
FileChooserParams fileChooserParams
|
|
232
251
|
) {
|
|
233
252
|
openFileChooser(
|
|
234
253
|
filePathCallback,
|
|
@@ -392,10 +411,10 @@ public class WebViewDialog extends Dialog {
|
|
|
392
411
|
);
|
|
393
412
|
return;
|
|
394
413
|
}
|
|
395
|
-
if (
|
|
414
|
+
if (preShowError != null && !preShowError.isEmpty()) {
|
|
396
415
|
Log.e(
|
|
397
416
|
"InjectPreShowScript",
|
|
398
|
-
"Error within the user-provided preShowFunction: " +
|
|
417
|
+
"Error within the user-provided preShowFunction: " + preShowError
|
|
399
418
|
);
|
|
400
419
|
}
|
|
401
420
|
} catch (InterruptedException e) {
|
|
@@ -405,7 +424,7 @@ public class WebViewDialog extends Dialog {
|
|
|
405
424
|
);
|
|
406
425
|
} finally {
|
|
407
426
|
preShowSemaphore = null;
|
|
408
|
-
|
|
427
|
+
preShowError = null;
|
|
409
428
|
}
|
|
410
429
|
}
|
|
411
430
|
|
|
@@ -529,7 +548,7 @@ public class WebViewDialog extends Dialog {
|
|
|
529
548
|
.setMessage(_options.getCloseModalDescription())
|
|
530
549
|
.setPositiveButton(
|
|
531
550
|
_options.getCloseModalOk(),
|
|
532
|
-
new
|
|
551
|
+
new OnClickListener() {
|
|
533
552
|
public void onClick(DialogInterface dialog, int which) {
|
|
534
553
|
// Close button clicked, do something
|
|
535
554
|
dismiss();
|
|
@@ -618,7 +637,7 @@ public class WebViewDialog extends Dialog {
|
|
|
618
637
|
try {
|
|
619
638
|
inputStream.close();
|
|
620
639
|
} catch (IOException e) {
|
|
621
|
-
|
|
640
|
+
e.printStackTrace();
|
|
622
641
|
}
|
|
623
642
|
}
|
|
624
643
|
}
|
|
@@ -742,9 +761,7 @@ public class WebViewDialog extends Dialog {
|
|
|
742
761
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
743
762
|
context.startActivity(intent);
|
|
744
763
|
return true;
|
|
745
|
-
} catch (ActivityNotFoundException e) {
|
|
746
|
-
// Do nothing
|
|
747
|
-
} catch (URISyntaxException e) {
|
|
764
|
+
} catch (ActivityNotFoundException | URISyntaxException e) {
|
|
748
765
|
// Do nothing
|
|
749
766
|
}
|
|
750
767
|
}
|
|
@@ -769,7 +786,6 @@ public class WebViewDialog extends Dialog {
|
|
|
769
786
|
// _webView.evaluateJavascript("");
|
|
770
787
|
// }
|
|
771
788
|
//
|
|
772
|
-
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
|
773
789
|
@Override
|
|
774
790
|
public WebResourceResponse shouldInterceptRequest(
|
|
775
791
|
WebView view,
|
|
@@ -798,7 +814,7 @@ public class WebViewDialog extends Dialog {
|
|
|
798
814
|
// We need to call a JS function
|
|
799
815
|
String requestId = randomRequestId();
|
|
800
816
|
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
801
|
-
|
|
817
|
+
addProxiedRequest(requestId, proxiedRequest);
|
|
802
818
|
|
|
803
819
|
// lsuakdchgbbaHandleProxiedRequest
|
|
804
820
|
activity.runOnUiThread(
|
|
@@ -841,7 +857,7 @@ public class WebViewDialog extends Dialog {
|
|
|
841
857
|
return proxiedRequest.response;
|
|
842
858
|
} else {
|
|
843
859
|
Log.e("InAppBrowserProxy", "Semaphore timed out");
|
|
844
|
-
|
|
860
|
+
removeProxiedRequest(requestId); // prevent mem leak
|
|
845
861
|
}
|
|
846
862
|
} catch (InterruptedException e) {
|
|
847
863
|
Log.e("InAppBrowserProxy", "Semaphore wait error", e);
|
|
@@ -1068,99 +1084,97 @@ public class WebViewDialog extends Dialog {
|
|
|
1068
1084
|
}
|
|
1069
1085
|
|
|
1070
1086
|
public static String getReasonPhrase(int statusCode) {
|
|
1071
|
-
switch (statusCode) {
|
|
1072
|
-
case (200)
|
|
1073
|
-
|
|
1074
|
-
case (
|
|
1075
|
-
|
|
1076
|
-
case (
|
|
1077
|
-
|
|
1078
|
-
case (
|
|
1079
|
-
|
|
1080
|
-
case (
|
|
1081
|
-
|
|
1082
|
-
case (
|
|
1083
|
-
|
|
1084
|
-
case (
|
|
1085
|
-
|
|
1086
|
-
case (
|
|
1087
|
-
|
|
1088
|
-
case (
|
|
1089
|
-
|
|
1090
|
-
case (
|
|
1091
|
-
|
|
1092
|
-
case (
|
|
1093
|
-
|
|
1094
|
-
case (
|
|
1095
|
-
|
|
1096
|
-
case (
|
|
1097
|
-
|
|
1098
|
-
case (
|
|
1099
|
-
|
|
1100
|
-
case (
|
|
1101
|
-
|
|
1102
|
-
case (
|
|
1103
|
-
|
|
1104
|
-
case (
|
|
1105
|
-
|
|
1106
|
-
case (
|
|
1107
|
-
|
|
1108
|
-
case (
|
|
1109
|
-
|
|
1110
|
-
case (
|
|
1111
|
-
|
|
1112
|
-
case (
|
|
1113
|
-
|
|
1114
|
-
case (
|
|
1115
|
-
|
|
1116
|
-
case (
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
default:
|
|
1163
|
-
return "";
|
|
1087
|
+
return switch (statusCode) {
|
|
1088
|
+
case (200) -> "OK";
|
|
1089
|
+
case (201) -> "Created";
|
|
1090
|
+
case (202) -> "Accepted";
|
|
1091
|
+
case (203) -> "Non Authoritative Information";
|
|
1092
|
+
case (204) -> "No Content";
|
|
1093
|
+
case (205) -> "Reset Content";
|
|
1094
|
+
case (206) -> "Partial Content";
|
|
1095
|
+
case (207) -> "Partial Update OK";
|
|
1096
|
+
case (300) -> "Mutliple Choices";
|
|
1097
|
+
case (301) -> "Moved Permanently";
|
|
1098
|
+
case (302) -> "Moved Temporarily";
|
|
1099
|
+
case (303) -> "See Other";
|
|
1100
|
+
case (304) -> "Not Modified";
|
|
1101
|
+
case (305) -> "Use Proxy";
|
|
1102
|
+
case (307) -> "Temporary Redirect";
|
|
1103
|
+
case (400) -> "Bad Request";
|
|
1104
|
+
case (401) -> "Unauthorized";
|
|
1105
|
+
case (402) -> "Payment Required";
|
|
1106
|
+
case (403) -> "Forbidden";
|
|
1107
|
+
case (404) -> "Not Found";
|
|
1108
|
+
case (405) -> "Method Not Allowed";
|
|
1109
|
+
case (406) -> "Not Acceptable";
|
|
1110
|
+
case (407) -> "Proxy Authentication Required";
|
|
1111
|
+
case (408) -> "Request Timeout";
|
|
1112
|
+
case (409) -> "Conflict";
|
|
1113
|
+
case (410) -> "Gone";
|
|
1114
|
+
case (411) -> "Length Required";
|
|
1115
|
+
case (412) -> "Precondition Failed";
|
|
1116
|
+
case (413) -> "Request Entity Too Large";
|
|
1117
|
+
case (414) -> "Request-URI Too Long";
|
|
1118
|
+
case (415) -> "Unsupported Media Type";
|
|
1119
|
+
case (416) -> "Requested Range Not Satisfiable";
|
|
1120
|
+
case (417) -> "Expectation Failed";
|
|
1121
|
+
case (418) -> "Reauthentication Required";
|
|
1122
|
+
case (419) -> "Proxy Reauthentication Required";
|
|
1123
|
+
case (422) -> "Unprocessable Entity";
|
|
1124
|
+
case (423) -> "Locked";
|
|
1125
|
+
case (424) -> "Failed Dependency";
|
|
1126
|
+
case (500) -> "Server Error";
|
|
1127
|
+
case (501) -> "Not Implemented";
|
|
1128
|
+
case (502) -> "Bad Gateway";
|
|
1129
|
+
case (503) -> "Service Unavailable";
|
|
1130
|
+
case (504) -> "Gateway Timeout";
|
|
1131
|
+
case (505) -> "HTTP Version Not Supported";
|
|
1132
|
+
case (507) -> "Insufficient Storage";
|
|
1133
|
+
default -> "";
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
@Override
|
|
1138
|
+
public void dismiss() {
|
|
1139
|
+
if (_webView != null) {
|
|
1140
|
+
_webView.loadUrl("about:blank");
|
|
1141
|
+
_webView.onPause();
|
|
1142
|
+
_webView.removeAllViews();
|
|
1143
|
+
_webView.destroy();
|
|
1144
|
+
_webView = null;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (executorService != null && !executorService.isShutdown()) {
|
|
1148
|
+
executorService.shutdown();
|
|
1149
|
+
try {
|
|
1150
|
+
if (!executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
|
|
1151
|
+
executorService.shutdownNow();
|
|
1152
|
+
}
|
|
1153
|
+
} catch (InterruptedException e) {
|
|
1154
|
+
executorService.shutdownNow();
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
super.dismiss();
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
public void addProxiedRequest(String key, ProxiedRequest request) {
|
|
1162
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1163
|
+
proxiedRequestsHashmap.put(key, request);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
public ProxiedRequest getProxiedRequest(String key) {
|
|
1168
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1169
|
+
ProxiedRequest request = proxiedRequestsHashmap.get(key);
|
|
1170
|
+
proxiedRequestsHashmap.remove(key);
|
|
1171
|
+
return request;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
public void removeProxiedRequest(String key) {
|
|
1176
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1177
|
+
proxiedRequestsHashmap.remove(key);
|
|
1164
1178
|
}
|
|
1165
1179
|
}
|
|
1166
1180
|
}
|