@capgo/inappbrowser 7.2.21 → 7.3.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.
@@ -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,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
  }
@@ -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.0",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",