@capgo/inappbrowser 8.1.13 → 8.1.14

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.
@@ -31,9 +31,14 @@ import com.getcapacitor.annotation.CapacitorPlugin;
31
31
  import com.getcapacitor.annotation.Permission;
32
32
  import com.getcapacitor.annotation.PermissionCallback;
33
33
  import java.lang.reflect.Field;
34
+ import java.util.ArrayDeque;
34
35
  import java.util.ArrayList;
36
+ import java.util.Deque;
37
+ import java.util.HashMap;
35
38
  import java.util.Iterator;
36
39
  import java.util.List;
40
+ import java.util.Map;
41
+ import java.util.UUID;
37
42
  import java.util.regex.Pattern;
38
43
  import java.util.regex.PatternSyntaxException;
39
44
  import org.json.JSONException;
@@ -50,12 +55,15 @@ import org.json.JSONObject;
50
55
  )
51
56
  public class InAppBrowserPlugin extends Plugin implements WebViewDialog.PermissionHandler {
52
57
 
53
- private final String pluginVersion = "8.1.13";
58
+ private final String pluginVersion = "8.1.14";
54
59
 
55
60
  public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
56
61
  private CustomTabsClient customTabsClient;
57
62
  private CustomTabsSession currentSession;
58
63
  private WebViewDialog webViewDialog = null;
64
+ private final Map<String, WebViewDialog> webViewDialogs = new HashMap<>();
65
+ private final Deque<String> webViewStack = new ArrayDeque<>();
66
+ private String activeWebViewId = null;
59
67
  private String currentUrl = "";
60
68
 
61
69
  private PermissionRequest currentPermissionRequest;
@@ -71,7 +79,68 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
71
79
  );
72
80
  }
73
81
 
82
+ private void registerWebView(String id, WebViewDialog dialog) {
83
+ webViewDialogs.put(id, dialog);
84
+ webViewStack.remove(id);
85
+ webViewStack.addLast(id);
86
+ activeWebViewId = id;
87
+ webViewDialog = dialog;
88
+ }
89
+
90
+ private void unregisterWebView(String id) {
91
+ webViewDialogs.remove(id);
92
+ webViewStack.remove(id);
93
+ activeWebViewId = webViewStack.peekLast();
94
+ webViewDialog = activeWebViewId != null ? webViewDialogs.get(activeWebViewId) : null;
95
+ if (webViewDialog != null) {
96
+ String url = webViewDialog.getUrl();
97
+ if (url != null) {
98
+ currentUrl = url;
99
+ }
100
+ }
101
+ }
102
+
103
+ private String resolveTargetId(PluginCall call) {
104
+ String id = call.getString("id");
105
+ return id != null ? id : activeWebViewId;
106
+ }
107
+
108
+ private WebViewDialog resolveDialog(String id) {
109
+ if (id != null) {
110
+ return webViewDialogs.get(id);
111
+ }
112
+ if (activeWebViewId != null) {
113
+ WebViewDialog dialog = webViewDialogs.get(activeWebViewId);
114
+ if (dialog != null) {
115
+ return dialog;
116
+ }
117
+ }
118
+ return webViewDialog;
119
+ }
120
+
121
+ private WebViewDialog findFileChooserDialog() {
122
+ if (activeWebViewId != null) {
123
+ WebViewDialog dialog = webViewDialogs.get(activeWebViewId);
124
+ if (dialog != null && dialog.mFilePathCallback != null) {
125
+ return dialog;
126
+ }
127
+ }
128
+
129
+ if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
130
+ return webViewDialog;
131
+ }
132
+
133
+ for (WebViewDialog dialog : webViewDialogs.values()) {
134
+ if (dialog != null && dialog.mFilePathCallback != null) {
135
+ return dialog;
136
+ }
137
+ }
138
+
139
+ return null;
140
+ }
141
+
74
142
  private void handleFileChooserResult(ActivityResult result) {
143
+ WebViewDialog webViewDialog = findFileChooserDialog();
75
144
  if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
76
145
  Uri[] results = null;
77
146
  Intent data = result.getData();
@@ -224,6 +293,8 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
224
293
  return;
225
294
  }
226
295
 
296
+ String targetId = call.getString("id");
297
+ WebViewDialog webViewDialog = resolveDialog(targetId);
227
298
  if (webViewDialog == null) {
228
299
  call.reject("WebView is not initialized");
229
300
  return;
@@ -235,12 +306,8 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
235
306
  @Override
236
307
  public void run() {
237
308
  try {
238
- if (webViewDialog != null) {
239
- webViewDialog.setUrl(url);
240
- call.resolve();
241
- } else {
242
- call.reject("WebView is not initialized");
243
- }
309
+ webViewDialog.setUrl(url);
310
+ call.resolve();
244
311
  } catch (Exception e) {
245
312
  Log.e("InAppBrowser", "Error setting URL: " + e.getMessage());
246
313
  call.reject("Failed to set URL: " + e.getMessage());
@@ -262,7 +329,7 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
262
329
  Boolean preventDeeplink = call.getBoolean("preventDeeplink", false);
263
330
  Boolean isPresentAfterPageLoad = call.getBoolean("isPresentAfterPageLoad", false);
264
331
 
265
- if (url == null || TextUtils.isEmpty(url)) {
332
+ if (TextUtils.isEmpty(url)) {
266
333
  call.reject("Invalid URL");
267
334
  }
268
335
  currentUrl = url;
@@ -352,13 +419,29 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
352
419
 
353
420
  Log.i("DelCookies", String.format("Script to run:\n%s", scriptToRun));
354
421
 
422
+ String targetId = call.getString("id");
423
+ ArrayList<WebViewDialog> targetDialogs = new ArrayList<>();
424
+
425
+ if (targetId != null) {
426
+ WebViewDialog dialog = webViewDialogs.get(targetId);
427
+ if (dialog == null) {
428
+ call.reject("WebView is not initialized");
429
+ return;
430
+ }
431
+ targetDialogs.add(dialog);
432
+ } else if (!webViewDialogs.isEmpty()) {
433
+ targetDialogs.addAll(webViewDialogs.values());
434
+ }
435
+
355
436
  this.getActivity().runOnUiThread(
356
437
  new Runnable() {
357
438
  @Override
358
439
  public void run() {
359
440
  try {
360
- if (webViewDialog != null) {
361
- webViewDialog.executeScript(scriptToRun.toString());
441
+ if (!targetDialogs.isEmpty()) {
442
+ for (WebViewDialog dialog : targetDialogs) {
443
+ dialog.executeScript(scriptToRun.toString());
444
+ }
362
445
  call.resolve();
363
446
  } else {
364
447
  call.reject("WebView is not initialized");
@@ -401,6 +484,7 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
401
484
  call.reject("Invalid URL");
402
485
  }
403
486
  currentUrl = url;
487
+ final String webViewId = UUID.randomUUID().toString();
404
488
  final Options options = new Options();
405
489
  options.setUrl(url);
406
490
  options.setHeaders(call.getObject("headers"));
@@ -545,33 +629,36 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
545
629
  new WebViewCallbacks() {
546
630
  @Override
547
631
  public void urlChangeEvent(String url) {
548
- notifyListeners("urlChangeEvent", new JSObject().put("url", url));
632
+ notifyListeners("urlChangeEvent", new JSObject().put("id", webViewId).put("url", url));
633
+ if (webViewId.equals(activeWebViewId)) {
634
+ currentUrl = url;
635
+ }
549
636
  }
550
637
 
551
638
  @Override
552
639
  public void closeEvent(String url) {
553
- notifyListeners("closeEvent", new JSObject().put("url", url));
554
- webViewDialog = null;
640
+ notifyListeners("closeEvent", new JSObject().put("id", webViewId).put("url", url));
641
+ unregisterWebView(webViewId);
555
642
  }
556
643
 
557
644
  @Override
558
645
  public void pageLoaded() {
559
- notifyListeners("browserPageLoaded", new JSObject());
646
+ notifyListeners("browserPageLoaded", new JSObject().put("id", webViewId));
560
647
  }
561
648
 
562
649
  @Override
563
650
  public void pageLoadError() {
564
- notifyListeners("pageLoadError", new JSObject());
651
+ notifyListeners("pageLoadError", new JSObject().put("id", webViewId));
565
652
  }
566
653
 
567
654
  @Override
568
655
  public void buttonNearDoneClicked() {
569
- notifyListeners("buttonNearDoneClick", new JSObject());
656
+ notifyListeners("buttonNearDoneClick", new JSObject().put("id", webViewId));
570
657
  }
571
658
 
572
659
  @Override
573
660
  public void confirmBtnClicked(String url) {
574
- notifyListeners("confirmBtnClicked", new JSObject().put("url", url));
661
+ notifyListeners("confirmBtnClicked", new JSObject().put("id", webViewId).put("url", url));
575
662
  }
576
663
 
577
664
  @Override
@@ -592,6 +679,7 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
592
679
  String key = keys.next();
593
680
  jsObject.put(key, jsonMessage.get(key));
594
681
  }
682
+ jsObject.put("id", webViewId);
595
683
 
596
684
  // Notify listeners with the parsed message
597
685
  notifyListeners("messageFromWebview", jsObject);
@@ -601,6 +689,7 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
601
689
  // If JSON parsing fails, send the raw message as a string
602
690
  JSObject jsObject = new JSObject();
603
691
  jsObject.put("rawMessage", message);
692
+ jsObject.put("id", webViewId);
604
693
  notifyListeners("messageFromWebview", jsObject);
605
694
  }
606
695
  }
@@ -682,16 +771,17 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
682
771
  new Runnable() {
683
772
  @Override
684
773
  public void run() {
685
- webViewDialog = new WebViewDialog(
774
+ WebViewDialog dialog = new WebViewDialog(
686
775
  getContext(),
687
776
  android.R.style.Theme_NoTitleBar,
688
777
  options,
689
778
  InAppBrowserPlugin.this,
690
779
  getBridge().getWebView()
691
780
  );
692
- webViewDialog.activity = InAppBrowserPlugin.this.getActivity();
693
- webViewDialog.presentWebView();
694
- call.resolve();
781
+ dialog.setInstanceId(webViewId);
782
+ dialog.activity = InAppBrowserPlugin.this.getActivity();
783
+ registerWebView(webViewId, dialog);
784
+ dialog.presentWebView();
695
785
  }
696
786
  }
697
787
  );
@@ -712,10 +802,6 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
712
802
 
713
803
  @PluginMethod
714
804
  public void postMessage(PluginCall call) {
715
- if (webViewDialog == null) {
716
- call.reject("WebView is not initialized");
717
- return;
718
- }
719
805
  JSObject eventData = call.getObject("detail");
720
806
  // Log event data
721
807
  if (eventData == null) {
@@ -723,11 +809,32 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
723
809
  return;
724
810
  }
725
811
 
812
+ String targetId = call.getString("id");
726
813
  Log.d("InAppBrowserPlugin", "Event data: " + eventData.toString());
727
814
  this.getActivity().runOnUiThread(
728
815
  new Runnable() {
729
816
  @Override
730
817
  public void run() {
818
+ if (targetId != null) {
819
+ WebViewDialog dialog = webViewDialogs.get(targetId);
820
+ if (dialog == null) {
821
+ call.reject("WebView is not initialized");
822
+ return;
823
+ }
824
+ dialog.postMessageToJS(eventData);
825
+ call.resolve();
826
+ return;
827
+ }
828
+
829
+ if (!webViewDialogs.isEmpty()) {
830
+ for (WebViewDialog dialog : webViewDialogs.values()) {
831
+ dialog.postMessageToJS(eventData);
832
+ }
833
+ call.resolve();
834
+ return;
835
+ }
836
+
837
+ // TODO: Legacy, can be removed(?)
731
838
  if (webViewDialog != null) {
732
839
  webViewDialog.postMessageToJS(eventData);
733
840
  call.resolve();
@@ -798,16 +905,32 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
798
905
  return;
799
906
  }
800
907
 
801
- if (webViewDialog == null) {
802
- call.reject("WebView is not initialized");
803
- return;
804
- }
805
-
908
+ String targetId = call.getString("id");
806
909
  this.getActivity().runOnUiThread(
807
910
  new Runnable() {
808
911
  @Override
809
912
  public void run() {
810
913
  try {
914
+ if (targetId != null) {
915
+ WebViewDialog dialog = webViewDialogs.get(targetId);
916
+ if (dialog == null) {
917
+ call.reject("WebView is not initialized");
918
+ return;
919
+ }
920
+ dialog.executeScript(script);
921
+ call.resolve();
922
+ return;
923
+ }
924
+
925
+ if (!webViewDialogs.isEmpty()) {
926
+ for (WebViewDialog dialog : webViewDialogs.values()) {
927
+ dialog.executeScript(script);
928
+ }
929
+ call.resolve();
930
+ return;
931
+ }
932
+
933
+ // TODO: Legacy, can be removed(?)
811
934
  if (webViewDialog != null) {
812
935
  webViewDialog.executeScript(script);
813
936
  call.resolve();
@@ -829,6 +952,8 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
829
952
  new Runnable() {
830
953
  @Override
831
954
  public void run() {
955
+ String targetId = resolveTargetId(call);
956
+ WebViewDialog webViewDialog = resolveDialog(targetId);
832
957
  if (webViewDialog != null) {
833
958
  boolean canGoBack = webViewDialog.goBack();
834
959
  JSObject result = new JSObject();
@@ -850,6 +975,8 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
850
975
  new Runnable() {
851
976
  @Override
852
977
  public void run() {
978
+ String targetId = resolveTargetId(call);
979
+ WebViewDialog webViewDialog = resolveDialog(targetId);
853
980
  if (webViewDialog != null) {
854
981
  webViewDialog.reload();
855
982
  call.resolve();
@@ -863,6 +990,8 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
863
990
 
864
991
  @PluginMethod
865
992
  public void lsuakdchgbbaHandleProxiedRequest(PluginCall call) {
993
+ String webviewId = call.getString("webviewId");
994
+ WebViewDialog webViewDialog = webviewId != null ? webViewDialogs.get(webviewId) : resolveDialog(null);
866
995
  if (webViewDialog != null) {
867
996
  Boolean ok = call.getBoolean("ok", false);
868
997
  String id = call.getString("id");
@@ -883,7 +1012,9 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
883
1012
 
884
1013
  @PluginMethod
885
1014
  public void close(PluginCall call) {
886
- if (webViewDialog == null) {
1015
+ String targetId = resolveTargetId(call);
1016
+ WebViewDialog dialog = resolveDialog(targetId);
1017
+ if (dialog == null) {
887
1018
  // Fallback: try to bring main activity to foreground
888
1019
  try {
889
1020
  Intent intent = new Intent(getContext(), getBridge().getActivity().getClass());
@@ -902,10 +1033,10 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
902
1033
  @Override
903
1034
  public void run() {
904
1035
  try {
905
- if (webViewDialog != null) {
1036
+ if (dialog != null) {
906
1037
  String currentUrl = "";
907
1038
  try {
908
- currentUrl = webViewDialog.getUrl();
1039
+ currentUrl = dialog.getUrl();
909
1040
  if (currentUrl == null) {
910
1041
  currentUrl = "";
911
1042
  }
@@ -915,10 +1046,18 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
915
1046
  }
916
1047
 
917
1048
  // Notify listeners about the close event
918
- notifyListeners("closeEvent", new JSObject().put("url", currentUrl));
1049
+ JSObject eventData = new JSObject().put("url", currentUrl);
1050
+ if (targetId != null) {
1051
+ eventData.put("id", targetId);
1052
+ }
1053
+ notifyListeners("closeEvent", eventData);
919
1054
 
920
- webViewDialog.dismiss();
921
- webViewDialog = null;
1055
+ dialog.dismiss();
1056
+ if (targetId != null) {
1057
+ unregisterWebView(targetId);
1058
+ } else {
1059
+ webViewDialog = null;
1060
+ }
922
1061
  call.resolve();
923
1062
  } else {
924
1063
  // Secondary fallback inside UI thread
@@ -976,7 +1115,7 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
976
1115
  @Override
977
1116
  public void onNavigationEvent(int navigationEvent, Bundle extras) {
978
1117
  // Only fire browserPageLoaded for Custom Tabs, not for WebView
979
- if (navigationEvent == NAVIGATION_FINISHED && webViewDialog == null) {
1118
+ if (navigationEvent == NAVIGATION_FINISHED && webViewDialogs.isEmpty() && webViewDialog == null) {
980
1119
  notifyListeners("browserPageLoaded", new JSObject());
981
1120
  }
982
1121
  }
@@ -988,14 +1127,17 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
988
1127
 
989
1128
  @Override
990
1129
  protected void handleOnDestroy() {
991
- if (webViewDialog != null) {
1130
+ for (WebViewDialog dialog : webViewDialogs.values()) {
992
1131
  try {
993
- webViewDialog.dismiss();
1132
+ dialog.dismiss();
994
1133
  } catch (Exception e) {
995
1134
  // Ignore, dialog may already be dismissed
996
1135
  }
997
- webViewDialog = null;
998
1136
  }
1137
+ webViewDialogs.clear();
1138
+ webViewStack.clear();
1139
+ activeWebViewId = null;
1140
+ webViewDialog = null;
999
1141
  currentPermissionRequest = null;
1000
1142
  customTabsClient = null;
1001
1143
  currentSession = null;
@@ -1015,6 +1157,8 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
1015
1157
 
1016
1158
  @PluginMethod
1017
1159
  public void updateDimensions(PluginCall call) {
1160
+ String targetId = resolveTargetId(call);
1161
+ WebViewDialog webViewDialog = resolveDialog(targetId);
1018
1162
  if (webViewDialog == null) {
1019
1163
  call.reject("WebView is not initialized");
1020
1164
  return;
@@ -114,6 +114,7 @@ public class WebViewDialog extends Dialog {
114
114
  private boolean isInitialized = false;
115
115
  private boolean datePickerInjected = false; // Track if we've injected date picker fixes
116
116
  private final WebView capacitorWebView;
117
+ private String instanceId = "";
117
118
  private final Map<String, ProxiedRequest> proxiedRequestsHashmap = new HashMap<>();
118
119
  private final ExecutorService executorService = Executors.newCachedThreadPool();
119
120
  private int iconColor = Color.BLACK; // Default icon color
@@ -155,6 +156,14 @@ public class WebViewDialog extends Dialog {
155
156
  this.capacitorWebView = capacitorWebView;
156
157
  }
157
158
 
159
+ public void setInstanceId(String id) {
160
+ this.instanceId = id != null ? id : "";
161
+ }
162
+
163
+ public String getInstanceId() {
164
+ return instanceId;
165
+ }
166
+
158
167
  // Add this class to provide safer JavaScript interface
159
168
  private class JavaScriptInterface {
160
169
 
@@ -2593,31 +2602,38 @@ public class WebViewDialog extends Dialog {
2593
2602
  code: res.status,
2594
2603
  body: (await res.text())
2595
2604
  } : null),
2596
- id: '%s'
2605
+ id: '%s',
2606
+ webviewId: '%s'
2597
2607
  });
2598
2608
  }).catch((e) => {
2599
2609
  Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({
2600
2610
  ok: false,
2601
2611
  result: e.toString(),
2602
- id: '%s'
2612
+ id: '%s',
2613
+ webviewId: '%s'
2603
2614
  });
2604
2615
  });
2605
2616
  } catch (e) {
2606
2617
  Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({
2607
2618
  ok: false,
2608
2619
  result: e.toString(),
2609
- id: '%s'
2620
+ id: '%s',
2621
+ webviewId: '%s'
2610
2622
  });
2611
2623
  }
2612
2624
  """;
2625
+ String dialogId = instanceId != null ? instanceId : "";
2613
2626
  String s = String.format(
2614
2627
  jsTemplate,
2615
2628
  headers,
2616
2629
  toBase64(request.getUrl().toString()),
2617
2630
  request.getMethod(),
2618
2631
  requestId,
2632
+ dialogId,
2633
+ requestId,
2634
+ dialogId,
2619
2635
  requestId,
2620
- requestId
2636
+ dialogId
2621
2637
  );
2622
2638
  // Log.i("HTTP", s);
2623
2639
  capacitorWebView.evaluateJavascript(s, null);