@capgo/inappbrowser 7.2.21 → 7.3.2

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.
@@ -28,6 +28,7 @@ import com.getcapacitor.annotation.Permission;
28
28
  import com.getcapacitor.annotation.PermissionCallback;
29
29
  import java.util.ArrayList;
30
30
  import java.util.Iterator;
31
+ import java.util.Objects;
31
32
  import java.util.regex.Pattern;
32
33
  import java.util.regex.PatternSyntaxException;
33
34
  import org.json.JSONException;
@@ -91,7 +92,9 @@ public class InAppBrowserPlugin
91
92
  currentPermissionRequest.deny();
92
93
  currentPermissionRequest = null;
93
94
  }
94
- call.reject("Microphone permission is required");
95
+ if (call != null) {
96
+ call.reject("Microphone permission is required");
97
+ }
95
98
  }
96
99
  }
97
100
 
@@ -155,7 +158,7 @@ public class InAppBrowserPlugin
155
158
  webViewDialog.mFilePathCallback.onReceiveValue(results);
156
159
  webViewDialog.mFilePathCallback = null;
157
160
  } catch (Exception e) {
158
- Log.e("ACTIVITYRESULT", e.getMessage());
161
+ Log.e("ACTIVITYRESULT", Objects.requireNonNull(e.getMessage()));
159
162
  }
160
163
  }
161
164
  }
@@ -723,10 +726,8 @@ public class InAppBrowserPlugin
723
726
  new CustomTabsCallback() {
724
727
  @Override
725
728
  public void onNavigationEvent(int navigationEvent, Bundle extras) {
726
- switch (navigationEvent) {
727
- case NAVIGATION_FINISHED:
728
- notifyListeners("browserPageLoaded", new JSObject());
729
- break;
729
+ if (navigationEvent == NAVIGATION_FINISHED) {
730
+ notifyListeners("browserPageLoaded", new JSObject());
730
731
  }
731
732
  }
732
733
  }
@@ -734,4 +735,20 @@ public class InAppBrowserPlugin
734
735
  }
735
736
  return currentSession;
736
737
  }
738
+
739
+ @Override
740
+ protected void handleOnDestroy() {
741
+ if (webViewDialog != null) {
742
+ try {
743
+ webViewDialog.dismiss();
744
+ } catch (Exception e) {
745
+ // Ignore, dialog may already be dismissed
746
+ }
747
+ webViewDialog = null;
748
+ }
749
+ currentPermissionRequest = null;
750
+ customTabsClient = null;
751
+ currentSession = null;
752
+ super.handleOnDestroy();
753
+ }
737
754
  }
@@ -17,10 +17,10 @@ public class Options {
17
17
  ASSET,
18
18
  }
19
19
 
20
- private AllIconTypes iconType;
21
- private String icon;
22
- private int height;
23
- private int width;
20
+ private final AllIconTypes iconType;
21
+ private final String icon;
22
+ private final int height;
23
+ private final int width;
24
24
 
25
25
  private ButtonNearDone(
26
26
  AllIconTypes iconType,
@@ -80,14 +80,20 @@ public class Options {
80
80
  try {
81
81
  fileInputString.close();
82
82
  } catch (IOException e) {
83
- throw new RuntimeException(e);
83
+ e.printStackTrace();
84
84
  }
85
85
  }
86
86
  }
87
87
  Integer width = android.getInteger("width", 48);
88
88
 
89
89
  Integer height = android.getInteger("height", 48);
90
- return new ButtonNearDone(AllIconTypes.ASSET, icon, height, width);
90
+ final ButtonNearDone buttonNearDone1 = new ButtonNearDone(
91
+ AllIconTypes.ASSET,
92
+ icon,
93
+ height,
94
+ width
95
+ );
96
+ return buttonNearDone1;
91
97
  }
92
98
 
93
99
  public AllIconTypes getIconType() {
@@ -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,45 @@ 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
+ String currentUrl = _webView != null ? _webView.getUrl() : "";
149
+ dismiss();
150
+ if (_options != null && _options.getCallbacks() != null) {
151
+ _options.getCallbacks().closeEvent(currentUrl);
152
+ }
153
+ } catch (Exception e) {
154
+ Log.e("InAppBrowser", "Error closing WebView: " + e.getMessage());
155
+ }
156
+ });
148
157
  }
149
- );
158
+ } catch (Exception e) {
159
+ Log.e("InAppBrowser", "Error in close: " + e.getMessage());
160
+ }
150
161
  }
151
162
  }
152
163
 
@@ -154,23 +165,31 @@ public class WebViewDialog extends Dialog {
154
165
 
155
166
  @JavascriptInterface
156
167
  public void error(String error) {
157
- // Handle message from JavaScript
158
- if (preShowSemaphore != null) {
159
- preshowError = error;
160
- preShowSemaphore.release();
168
+ try {
169
+ // Handle message from JavaScript
170
+ if (preShowSemaphore != null) {
171
+ preShowError = error;
172
+ preShowSemaphore.release();
173
+ }
174
+ } catch (Exception e) {
175
+ Log.e("InAppBrowser", "Error in error callback: " + e.getMessage());
161
176
  }
162
177
  }
163
178
 
164
179
  @JavascriptInterface
165
180
  public void success() {
166
- // Handle message from JavaScript
167
- if (preShowSemaphore != null) {
168
- preShowSemaphore.release();
181
+ try {
182
+ // Handle message from JavaScript
183
+ if (preShowSemaphore != null) {
184
+ preShowSemaphore.release();
185
+ }
186
+ } catch (Exception e) {
187
+ Log.e("InAppBrowser", "Error in success callback: " + e.getMessage());
169
188
  }
170
189
  }
171
190
  }
172
191
 
173
- @SuppressLint("SetJavaScriptEnabled")
192
+ @SuppressLint({ "SetJavaScriptEnabled", "AddJavascriptInterface" })
174
193
  public void presentWebView() {
175
194
  requestWindowFeature(Window.FEATURE_NO_TITLE);
176
195
  setCancelable(true);
@@ -210,9 +229,6 @@ public class WebViewDialog extends Dialog {
210
229
  _webView.getSettings().setDatabaseEnabled(true);
211
230
  _webView.getSettings().setDomStorageEnabled(true);
212
231
  _webView.getSettings().setAllowFileAccess(true);
213
- _webView
214
- .getSettings()
215
- .setPluginState(android.webkit.WebSettings.PluginState.ON);
216
232
  _webView.getSettings().setLoadWithOverviewMode(true);
217
233
  _webView.getSettings().setUseWideViewPort(true);
218
234
  _webView.getSettings().setAllowFileAccessFromFileURLs(true);
@@ -228,7 +244,7 @@ public class WebViewDialog extends Dialog {
228
244
  public boolean onShowFileChooser(
229
245
  WebView webView,
230
246
  ValueCallback<Uri[]> filePathCallback,
231
- WebChromeClient.FileChooserParams fileChooserParams
247
+ FileChooserParams fileChooserParams
232
248
  ) {
233
249
  openFileChooser(
234
250
  filePathCallback,
@@ -392,10 +408,10 @@ public class WebViewDialog extends Dialog {
392
408
  );
393
409
  return;
394
410
  }
395
- if (preshowError != null && !preshowError.isEmpty()) {
411
+ if (preShowError != null && !preShowError.isEmpty()) {
396
412
  Log.e(
397
413
  "InjectPreShowScript",
398
- "Error within the user-provided preShowFunction: " + preshowError
414
+ "Error within the user-provided preShowFunction: " + preShowError
399
415
  );
400
416
  }
401
417
  } catch (InterruptedException e) {
@@ -405,7 +421,7 @@ public class WebViewDialog extends Dialog {
405
421
  );
406
422
  } finally {
407
423
  preShowSemaphore = null;
408
- preshowError = null;
424
+ preShowError = null;
409
425
  }
410
426
  }
411
427
 
@@ -529,21 +545,27 @@ public class WebViewDialog extends Dialog {
529
545
  .setMessage(_options.getCloseModalDescription())
530
546
  .setPositiveButton(
531
547
  _options.getCloseModalOk(),
532
- new DialogInterface.OnClickListener() {
548
+ new OnClickListener() {
533
549
  public void onClick(DialogInterface dialog, int which) {
534
550
  // Close button clicked, do something
551
+ String currentUrl = _webView != null
552
+ ? _webView.getUrl()
553
+ : "";
535
554
  dismiss();
536
- _options.getCallbacks().closeEvent(_webView.getUrl());
537
- _webView.destroy();
555
+ if (_options != null && _options.getCallbacks() != null) {
556
+ _options.getCallbacks().closeEvent(currentUrl);
557
+ }
538
558
  }
539
559
  }
540
560
  )
541
561
  .setNegativeButton(_options.getCloseModalCancel(), null)
542
562
  .show();
543
563
  } else {
564
+ String currentUrl = _webView != null ? _webView.getUrl() : "";
544
565
  dismiss();
545
- _options.getCallbacks().closeEvent(_webView.getUrl());
546
- _webView.destroy();
566
+ if (_options != null && _options.getCallbacks() != null) {
567
+ _options.getCallbacks().closeEvent(currentUrl);
568
+ }
547
569
  }
548
570
  }
549
571
  }
@@ -618,7 +640,7 @@ public class WebViewDialog extends Dialog {
618
640
  try {
619
641
  inputStream.close();
620
642
  } catch (IOException e) {
621
- throw new RuntimeException(e);
643
+ e.printStackTrace();
622
644
  }
623
645
  }
624
646
  }
@@ -742,9 +764,7 @@ public class WebViewDialog extends Dialog {
742
764
  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
743
765
  context.startActivity(intent);
744
766
  return true;
745
- } catch (ActivityNotFoundException e) {
746
- // Do nothing
747
- } catch (URISyntaxException e) {
767
+ } catch (ActivityNotFoundException | URISyntaxException e) {
748
768
  // Do nothing
749
769
  }
750
770
  }
@@ -769,7 +789,6 @@ public class WebViewDialog extends Dialog {
769
789
  // _webView.evaluateJavascript("");
770
790
  // }
771
791
  //
772
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
773
792
  @Override
774
793
  public WebResourceResponse shouldInterceptRequest(
775
794
  WebView view,
@@ -798,7 +817,7 @@ public class WebViewDialog extends Dialog {
798
817
  // We need to call a JS function
799
818
  String requestId = randomRequestId();
800
819
  ProxiedRequest proxiedRequest = new ProxiedRequest();
801
- proxiedRequestsHashmap.put(requestId, proxiedRequest);
820
+ addProxiedRequest(requestId, proxiedRequest);
802
821
 
803
822
  // lsuakdchgbbaHandleProxiedRequest
804
823
  activity.runOnUiThread(
@@ -841,7 +860,7 @@ public class WebViewDialog extends Dialog {
841
860
  return proxiedRequest.response;
842
861
  } else {
843
862
  Log.e("InAppBrowserProxy", "Semaphore timed out");
844
- proxiedRequestsHashmap.remove(requestId); // prevent mem leak
863
+ removeProxiedRequest(requestId); // prevent mem leak
845
864
  }
846
865
  } catch (InterruptedException e) {
847
866
  Log.e("InAppBrowserProxy", "Semaphore wait error", e);
@@ -1068,99 +1087,97 @@ public class WebViewDialog extends Dialog {
1068
1087
  }
1069
1088
 
1070
1089
  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 "";
1090
+ return switch (statusCode) {
1091
+ case (200) -> "OK";
1092
+ case (201) -> "Created";
1093
+ case (202) -> "Accepted";
1094
+ case (203) -> "Non Authoritative Information";
1095
+ case (204) -> "No Content";
1096
+ case (205) -> "Reset Content";
1097
+ case (206) -> "Partial Content";
1098
+ case (207) -> "Partial Update OK";
1099
+ case (300) -> "Mutliple Choices";
1100
+ case (301) -> "Moved Permanently";
1101
+ case (302) -> "Moved Temporarily";
1102
+ case (303) -> "See Other";
1103
+ case (304) -> "Not Modified";
1104
+ case (305) -> "Use Proxy";
1105
+ case (307) -> "Temporary Redirect";
1106
+ case (400) -> "Bad Request";
1107
+ case (401) -> "Unauthorized";
1108
+ case (402) -> "Payment Required";
1109
+ case (403) -> "Forbidden";
1110
+ case (404) -> "Not Found";
1111
+ case (405) -> "Method Not Allowed";
1112
+ case (406) -> "Not Acceptable";
1113
+ case (407) -> "Proxy Authentication Required";
1114
+ case (408) -> "Request Timeout";
1115
+ case (409) -> "Conflict";
1116
+ case (410) -> "Gone";
1117
+ case (411) -> "Length Required";
1118
+ case (412) -> "Precondition Failed";
1119
+ case (413) -> "Request Entity Too Large";
1120
+ case (414) -> "Request-URI Too Long";
1121
+ case (415) -> "Unsupported Media Type";
1122
+ case (416) -> "Requested Range Not Satisfiable";
1123
+ case (417) -> "Expectation Failed";
1124
+ case (418) -> "Reauthentication Required";
1125
+ case (419) -> "Proxy Reauthentication Required";
1126
+ case (422) -> "Unprocessable Entity";
1127
+ case (423) -> "Locked";
1128
+ case (424) -> "Failed Dependency";
1129
+ case (500) -> "Server Error";
1130
+ case (501) -> "Not Implemented";
1131
+ case (502) -> "Bad Gateway";
1132
+ case (503) -> "Service Unavailable";
1133
+ case (504) -> "Gateway Timeout";
1134
+ case (505) -> "HTTP Version Not Supported";
1135
+ case (507) -> "Insufficient Storage";
1136
+ default -> "";
1137
+ };
1138
+ }
1139
+
1140
+ @Override
1141
+ public void dismiss() {
1142
+ if (_webView != null) {
1143
+ _webView.loadUrl("about:blank");
1144
+ _webView.onPause();
1145
+ _webView.removeAllViews();
1146
+ _webView.destroy();
1147
+ _webView = null;
1148
+ }
1149
+
1150
+ if (executorService != null && !executorService.isShutdown()) {
1151
+ executorService.shutdown();
1152
+ try {
1153
+ if (!executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
1154
+ executorService.shutdownNow();
1155
+ }
1156
+ } catch (InterruptedException e) {
1157
+ executorService.shutdownNow();
1158
+ }
1159
+ }
1160
+
1161
+ super.dismiss();
1162
+ }
1163
+
1164
+ public void addProxiedRequest(String key, ProxiedRequest request) {
1165
+ synchronized (proxiedRequestsHashmap) {
1166
+ proxiedRequestsHashmap.put(key, request);
1167
+ }
1168
+ }
1169
+
1170
+ public ProxiedRequest getProxiedRequest(String key) {
1171
+ synchronized (proxiedRequestsHashmap) {
1172
+ ProxiedRequest request = proxiedRequestsHashmap.get(key);
1173
+ proxiedRequestsHashmap.remove(key);
1174
+ return request;
1175
+ }
1176
+ }
1177
+
1178
+ public void removeProxiedRequest(String key) {
1179
+ synchronized (proxiedRequestsHashmap) {
1180
+ proxiedRequestsHashmap.remove(key);
1164
1181
  }
1165
1182
  }
1166
1183
  }
@@ -60,7 +60,12 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
60
60
  }
61
61
 
62
62
  func presentView(isAnimated: Bool = true) {
63
- self.bridge?.viewController?.present(self.navigationWebViewController!, animated: isAnimated, completion: {
63
+ guard let navigationController = self.navigationWebViewController else {
64
+ self.currentPluginCall?.reject("Navigation controller is not initialized")
65
+ return
66
+ }
67
+
68
+ self.bridge?.viewController?.present(navigationController, animated: isAnimated, completion: {
64
69
  self.currentPluginCall?.resolve()
65
70
  })
66
71
  }
@@ -98,18 +103,19 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
98
103
 
99
104
  DispatchQueue.main.async {
100
105
  WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
106
+ let group = DispatchGroup()
101
107
  for cookie in cookies {
102
-
103
108
  if cookie.domain == host || cookie.domain.hasSuffix(".\(host)") || host.hasSuffix(cookie.domain) {
104
- let semaphore = DispatchSemaphore(value: 1)
109
+ group.enter()
105
110
  WKWebsiteDataStore.default().httpCookieStore.delete(cookie) {
106
- semaphore.signal()
111
+ group.leave()
107
112
  }
108
- semaphore.wait()
109
113
  }
110
114
  }
111
115
 
112
- call.resolve()
116
+ group.notify(queue: .main) {
117
+ call.resolve()
118
+ }
113
119
  }
114
120
  }
115
121
  }
@@ -211,43 +217,45 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
211
217
  let credentials = self.readCredentials(call)
212
218
 
213
219
  DispatchQueue.main.async {
214
- let url = URL(string: urlString)
215
- if self.isPresentAfterPageLoad {
216
- self.webViewController = WKWebViewController.init(url: url!, headers: headers, isInspectable: isInspectable, credentials: credentials, preventDeeplink: preventDeeplink, blankNavigationTab: toolbarType == "blank")
217
- } else {
218
- self.webViewController = WKWebViewController.init()
219
- self.webViewController?.setHeaders(headers: headers)
220
- self.webViewController?.setCredentials(credentials: credentials)
221
- self.webViewController?.setPreventDeeplink(preventDeeplink: preventDeeplink)
220
+ guard let url = URL(string: urlString) else {
221
+ call.reject("Invalid URL format")
222
+ return
222
223
  }
223
224
 
224
- self.webViewController?.source = .remote(url!)
225
- self.webViewController?.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType) + [.reload]
226
- self.webViewController?.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType)
227
- self.webViewController?.toolbarItemTypes = []
228
- self.webViewController?.doneBarButtonItemPosition = .right
225
+ self.webViewController = WKWebViewController.init(url: url, headers: headers, isInspectable: isInspectable, credentials: credentials, preventDeeplink: preventDeeplink, blankNavigationTab: toolbarType == "blank")
229
226
 
230
- self.webViewController?.buttonNearDoneIcon = buttonNearDoneIcon
227
+ guard let webViewController = self.webViewController else {
228
+ call.reject("Failed to initialize WebViewController")
229
+ return
230
+ }
231
+
232
+ webViewController.source = .remote(url)
233
+ webViewController.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType) + [.reload]
234
+ webViewController.toolbarItemTypes = []
235
+ webViewController.doneBarButtonItemPosition = .right
236
+
237
+ webViewController.buttonNearDoneIcon = buttonNearDoneIcon
231
238
 
232
239
  if call.getBool("showArrow", false) {
233
- self.webViewController?.stopBarButtonItemImage = UIImage(named: "Forward@3x", in: Bundle(for: InAppBrowserPlugin.self), compatibleWith: nil)
240
+ webViewController.stopBarButtonItemImage = UIImage(named: "Forward@3x", in: Bundle(for: InAppBrowserPlugin.self), compatibleWith: nil)
234
241
  }
235
242
 
236
- self.webViewController?.capBrowserPlugin = self
237
- self.webViewController?.title = call.getString("title", "New Window")
238
- self.webViewController?.shareSubject = call.getString("shareSubject")
239
- self.webViewController?.shareDisclaimer = disclaimerContent
240
- self.webViewController?.preShowScript = call.getString("preShowScript")
241
- self.webViewController?.websiteTitleInNavigationBar = call.getBool("visibleTitle", true)
243
+ webViewController.capBrowserPlugin = self
244
+ webViewController.title = call.getString("title", "New Window")
245
+ webViewController.shareSubject = call.getString("shareSubject")
246
+ webViewController.shareDisclaimer = disclaimerContent
247
+ webViewController.preShowScript = call.getString("preShowScript")
248
+ webViewController.websiteTitleInNavigationBar = call.getBool("visibleTitle", true)
242
249
  if closeModal {
243
- self.webViewController?.closeModal = true
244
- self.webViewController?.closeModalTitle = closeModalTitle
245
- self.webViewController?.closeModalDescription = closeModalDescription
246
- self.webViewController?.closeModalOk = closeModalOk
247
- self.webViewController?.closeModalCancel = closeModalCancel
250
+ webViewController.closeModal = true
251
+ webViewController.closeModalTitle = closeModalTitle
252
+ webViewController.closeModalDescription = closeModalDescription
253
+ webViewController.closeModalOk = closeModalOk
254
+ webViewController.closeModalCancel = closeModalCancel
248
255
  }
249
- self.webViewController?.ignoreUntrustedSSLError = ignoreUntrustedSSLError
250
- self.navigationWebViewController = UINavigationController.init(rootViewController: self.webViewController!)
256
+ webViewController.ignoreUntrustedSSLError = ignoreUntrustedSSLError
257
+
258
+ self.navigationWebViewController = UINavigationController.init(rootViewController: webViewController)
251
259
  self.navigationWebViewController?.navigationBar.isTranslucent = false
252
260
  self.navigationWebViewController?.toolbar.isTranslucent = false
253
261
  self.navigationWebViewController?.navigationBar.backgroundColor = backgroundColor
@@ -256,11 +264,11 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
256
264
  self.navigationWebViewController?.modalPresentationStyle = .fullScreen
257
265
  if toolbarType == "blank" {
258
266
  self.navigationWebViewController?.navigationBar.isHidden = true
259
- self.webViewController?.blankNavigationTab = true
267
+ webViewController.blankNavigationTab = true
260
268
  }
261
269
  if showReloadButton {
262
270
  let toolbarItems = self.getToolbarItems(toolbarType: toolbarType)
263
- self.webViewController?.leftNavigationBarItemTypes = toolbarItems + [.reload]
271
+ webViewController.leftNavigationBarItemTypes = toolbarItems + [.reload]
264
272
  }
265
273
  if !self.isPresentAfterPageLoad {
266
274
  self.presentView(isAnimated: isAnimated)
@@ -75,7 +75,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
75
75
  self.setPreventDeeplink(preventDeeplink: preventDeeplink)
76
76
  self.initWebview(isInspectable: isInspectable)
77
77
  }
78
-
78
+
79
79
  public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool, blankNavigationTab: Bool) {
80
80
  super.init(nibName: nil, bundle: nil)
81
81
  self.blankNavigationTab = blankNavigationTab
@@ -111,7 +111,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
111
111
  open var ignoreUntrustedSSLError = false
112
112
  var viewWasPresented = false
113
113
  var preventDeeplink: Bool = false
114
- var blankNavigationTab: Bool = false;
114
+ var blankNavigationTab: Bool = false
115
115
 
116
116
  internal var preShowSemaphore: DispatchSemaphore?
117
117
  internal var preShowError: String?
@@ -326,10 +326,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
326
326
  webView.perform(Selector(("setInspectable:")), with: isInspectable)
327
327
  }
328
328
 
329
- if (self.blankNavigationTab) {
329
+ if self.blankNavigationTab {
330
330
  // First add the webView to view hierarchy
331
331
  self.view.addSubview(webView)
332
-
332
+
333
333
  // Then set up constraints
334
334
  webView.translatesAutoresizingMaskIntoConstraints = false
335
335
  NSLayoutConstraint.activate([
@@ -352,7 +352,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
352
352
  }
353
353
  webView.addObserver(self, forKeyPath: #keyPath(WKWebView.url), options: .new, context: nil)
354
354
 
355
- if (!self.blankNavigationTab) {
355
+ if !self.blankNavigationTab {
356
356
  self.view = webView
357
357
  }
358
358
  self.webView = webView
@@ -841,7 +841,20 @@ fileprivate extension WKWebViewController {
841
841
  canDismiss = delegate?.webViewController?(self, canDismiss: url) ?? true
842
842
  }
843
843
  if canDismiss {
844
- // UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
844
+ // Cleanup webView
845
+ webView?.stopLoading()
846
+ webView?.removeObserver(self, forKeyPath: estimatedProgressKeyPath)
847
+ if websiteTitleInNavigationBar {
848
+ webView?.removeObserver(self, forKeyPath: titleKeyPath)
849
+ }
850
+ webView?.removeObserver(self, forKeyPath: #keyPath(WKWebView.url))
851
+ webView?.configuration.userContentController.removeAllUserScripts()
852
+ webView?.configuration.userContentController.removeScriptMessageHandler(forName: "messageHandler")
853
+ webView?.configuration.userContentController.removeScriptMessageHandler(forName: "close")
854
+ webView?.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptSuccess")
855
+ webView?.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptError")
856
+ webView = nil
857
+
845
858
  self.capBrowserPlugin?.notifyListeners("closeEvent", data: ["url": webView?.url?.absoluteString ?? ""])
846
859
  dismiss(animated: true, completion: nil)
847
860
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/inappbrowser",
3
- "version": "7.2.21",
3
+ "version": "7.3.2",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",