@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.
@@ -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 HashMap<String, ProxiedRequest> proxiedRequestsHashmap;
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 preshowError = null;
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
- public class JavaScriptInterface {
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
- // Handle message from JavaScript
134
- _options.getCallbacks().javascriptCallback(message);
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
- // close webview
140
- activity.runOnUiThread(
141
- new Runnable() {
142
- @Override
143
- public void run() {
144
- dismiss();
145
- _options.getCallbacks().closeEvent(_webView.getUrl());
146
- _webView.destroy();
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
- // Handle message from JavaScript
158
- if (preShowSemaphore != null) {
159
- preshowError = error;
160
- preShowSemaphore.release();
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
- // Handle message from JavaScript
167
- if (preShowSemaphore != null) {
168
- preShowSemaphore.release();
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
- WebChromeClient.FileChooserParams fileChooserParams
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 (preshowError != null && !preshowError.isEmpty()) {
414
+ if (preShowError != null && !preShowError.isEmpty()) {
396
415
  Log.e(
397
416
  "InjectPreShowScript",
398
- "Error within the user-provided preShowFunction: " + preshowError
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
- preshowError = null;
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 DialogInterface.OnClickListener() {
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
- throw new RuntimeException(e);
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
- proxiedRequestsHashmap.put(requestId, proxiedRequest);
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
- proxiedRequestsHashmap.remove(requestId); // prevent mem leak
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
- return "OK";
1074
- case (201):
1075
- return "Created";
1076
- case (202):
1077
- return "Accepted";
1078
- case (203):
1079
- return "Non Authoritative Information";
1080
- case (204):
1081
- return "No Content";
1082
- case (205):
1083
- return "Reset Content";
1084
- case (206):
1085
- return "Partial Content";
1086
- case (207):
1087
- return "Partial Update OK";
1088
- case (300):
1089
- return "Mutliple Choices";
1090
- case (301):
1091
- return "Moved Permanently";
1092
- case (302):
1093
- return "Moved Temporarily";
1094
- case (303):
1095
- return "See Other";
1096
- case (304):
1097
- return "Not Modified";
1098
- case (305):
1099
- return "Use Proxy";
1100
- case (307):
1101
- return "Temporary Redirect";
1102
- case (400):
1103
- return "Bad Request";
1104
- case (401):
1105
- return "Unauthorized";
1106
- case (402):
1107
- return "Payment Required";
1108
- case (403):
1109
- return "Forbidden";
1110
- case (404):
1111
- return "Not Found";
1112
- case (405):
1113
- return "Method Not Allowed";
1114
- case (406):
1115
- return "Not Acceptable";
1116
- case (407):
1117
- return "Proxy Authentication Required";
1118
- case (408):
1119
- return "Request Timeout";
1120
- case (409):
1121
- return "Conflict";
1122
- case (410):
1123
- return "Gone";
1124
- case (411):
1125
- return "Length Required";
1126
- case (412):
1127
- return "Precondition Failed";
1128
- case (413):
1129
- return "Request Entity Too Large";
1130
- case (414):
1131
- return "Request-URI Too Long";
1132
- case (415):
1133
- return "Unsupported Media Type";
1134
- case (416):
1135
- return "Requested Range Not Satisfiable";
1136
- case (417):
1137
- return "Expectation Failed";
1138
- case (418):
1139
- return "Reauthentication Required";
1140
- case (419):
1141
- return "Proxy Reauthentication Required";
1142
- case (422):
1143
- return "Unprocessable Entity";
1144
- case (423):
1145
- return "Locked";
1146
- case (424):
1147
- return "Failed Dependency";
1148
- case (500):
1149
- return "Server Error";
1150
- case (501):
1151
- return "Not Implemented";
1152
- case (502):
1153
- return "Bad Gateway";
1154
- case (503):
1155
- return "Service Unavailable";
1156
- case (504):
1157
- return "Gateway Timeout";
1158
- case (505):
1159
- return "HTTP Version Not Supported";
1160
- case (507):
1161
- return "Insufficient Storage";
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
  }