@capgo/capacitor-inappbrowser 8.10.7 → 8.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -554,6 +554,8 @@ The W3C Payment Request API (used by Google Pay) requires Android WebView 120+.
554
554
  * [`addListener('messageFromWebview', ...)`](#addlistenermessagefromwebview-)
555
555
  * [`addListener('screenshotTaken', ...)`](#addlistenerscreenshottaken-)
556
556
  * [`addListener('browserPageLoaded', ...)`](#addlistenerbrowserpageloaded-)
557
+ * [`addListener('browserPageLoadStart', ...)`](#addlistenerbrowserpageloadstart-)
558
+ * [`addListener('browserPageLoadProgress', ...)`](#addlistenerbrowserpageloadprogress-)
557
559
  * [`addListener('pageLoadError', ...)`](#addlistenerpageloaderror-)
558
560
  * [`addListener('customSchemeIntercepted', ...)`](#addlistenercustomschemeintercepted-)
559
561
  * [`addListener('downloadCompleted', ...)`](#addlistenerdownloadcompleted-)
@@ -1078,6 +1080,47 @@ Will be triggered when page is loaded
1078
1080
  --------------------
1079
1081
 
1080
1082
 
1083
+ ### addListener('browserPageLoadStart', ...)
1084
+
1085
+ ```typescript
1086
+ addListener(eventName: 'browserPageLoadStart', listenerFunc: (event: { id?: string; }) => void) => Promise<PluginListenerHandle>
1087
+ ```
1088
+
1089
+ Will be triggered when a main-frame page load starts (link navigation, reload, etc.).
1090
+
1091
+ | Param | Type |
1092
+ | ------------------ | ------------------------------------------------- |
1093
+ | **`eventName`** | <code>'browserPageLoadStart'</code> |
1094
+ | **`listenerFunc`** | <code>(event: { id?: string; }) =&gt; void</code> |
1095
+
1096
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
1097
+
1098
+ **Since:** 8.11.0
1099
+
1100
+ --------------------
1101
+
1102
+
1103
+ ### addListener('browserPageLoadProgress', ...)
1104
+
1105
+ ```typescript
1106
+ addListener(eventName: 'browserPageLoadProgress', listenerFunc: (event: { id?: string; progress: number; }) => void) => Promise<PluginListenerHandle>
1107
+ ```
1108
+
1109
+ Will be triggered as a main-frame page load progresses.
1110
+ `progress` is a value from `0` to `1`.
1111
+
1112
+ | Param | Type |
1113
+ | ------------------ | ------------------------------------------------------------------- |
1114
+ | **`eventName`** | <code>'browserPageLoadProgress'</code> |
1115
+ | **`listenerFunc`** | <code>(event: { id?: string; progress: number; }) =&gt; void</code> |
1116
+
1117
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
1118
+
1119
+ **Since:** 8.11.0
1120
+
1121
+ --------------------
1122
+
1123
+
1081
1124
  ### addListener('pageLoadError', ...)
1082
1125
 
1083
1126
  ```typescript
@@ -1497,6 +1540,7 @@ And in the AndroidManifest.xml file:
1497
1540
  | **`titleIcon`** | <code><a href="#toolbartitleiconoptions">ToolbarTitleIconOptions</a></code> | Native toolbar title icon displayed before the title text. For Android: - iconType can be "asset" for a bundled SVG asset or "vector" for a drawable resource - icon path should be in the public folder for assets (e.g. "brand.svg") - width and height are optional and default to 24dp For iOS: - iconType can be "sf-symbol" or "asset" - for sf-symbol, icon should be the symbol name - for asset, icon should be the asset name or bundled web asset path | | 8.7.7 |
1498
1541
  | **`backgroundColor`** | <code><a href="#backgroundcolor">BackgroundColor</a></code> | Background color of the browser | <code>BackgroundColor.BLACK</code> | 0.1.0 |
1499
1542
  | **`activeNativeNavigationForWebview`** | <code>boolean</code> | If true, enables native navigation gestures within the webview. - Android: Native back button navigates within webview history - iOS: Enables swipe left/right gestures for back/forward navigation | <code>false (Android), true (iOS - enabled by default)</code> | |
1543
+ | **`enableReloadGesture`** | <code>boolean</code> | Enable pull-to-refresh (overscroll from top) to reload the current page. - iOS: Uses UIRefreshControl on the WebView scroll view - Android: Uses SwipeRefreshLayout around the WebView On iOS, this requires overscroll bounce. If `disableOverscroll` is `true`, the reload gesture will not work. | <code>false</code> | 8.10.8 |
1500
1544
  | **`disableGoBackOnNativeApplication`** | <code>boolean</code> | Disable the possibility to go back on native application, useful to force user to stay on the webview, Android only | <code>false</code> | |
1501
1545
  | **`isPresentAfterPageLoad`** | <code>boolean</code> | Open url in a new window fullscreen isPresentAfterPageLoad: if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. Promise timing: on Android, `openWebView()` resolves with the webview id when the webview is ready to be controlled (immediately for hidden/immediate presentation, after the first page load when `isPresentAfterPageLoad` is `true`). On iOS, the promise resolves with the id as soon as the native webview is created, even if presentation is deferred. | <code>false</code> | 0.1.0 |
1502
1546
  | **`isInspectable`** | <code>boolean</code> | Whether the website in the webview is inspectable or not, ios only | <code>false</code> | |
@@ -60,5 +60,6 @@ dependencies {
60
60
  androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
61
61
  implementation "androidx.browser:browser:$androidxBrowserVersion"
62
62
  implementation 'com.google.android.material:material:1.13.0'
63
+ implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
63
64
  implementation 'androidx.webkit:webkit:1.15.0'
64
65
  }
@@ -183,6 +183,16 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
183
183
  notifyListeners("browserPageLoaded", new JSObject().put("id", webViewId));
184
184
  }
185
185
 
186
+ @Override
187
+ public void pageLoadStart() {
188
+ notifyListeners("browserPageLoadStart", new JSObject().put("id", webViewId));
189
+ }
190
+
191
+ @Override
192
+ public void pageLoadProgress(double progress) {
193
+ notifyListeners("browserPageLoadProgress", new JSObject().put("id", webViewId).put("progress", progress));
194
+ }
195
+
186
196
  @Override
187
197
  public void pageLoadError() {
188
198
  notifyListeners("pageLoadError", new JSObject().put("id", webViewId));
@@ -1217,6 +1227,7 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
1217
1227
  }
1218
1228
 
1219
1229
  options.setActiveNativeNavigationForWebview(Boolean.TRUE.equals(call.getBoolean("activeNativeNavigationForWebview", false)));
1230
+ options.setEnableReloadGesture(Boolean.TRUE.equals(call.getBoolean("enableReloadGesture", false)));
1220
1231
  options.setDisableGoBackOnNativeApplication(Boolean.TRUE.equals(call.getBoolean("disableGoBackOnNativeApplication", false)));
1221
1232
  options.setPresentAfterPageLoad(Boolean.TRUE.equals(call.getBoolean("isPresentAfterPageLoad", false)));
1222
1233
  options.setPluginCall(call);
@@ -158,6 +158,7 @@ public class Options {
158
158
  private String shareSubject;
159
159
  private boolean disableGoBackOnNativeApplication;
160
160
  private boolean activeNativeNavigationForWebview;
161
+ private boolean enableReloadGesture = false;
161
162
  private boolean isPresentAfterPageLoad;
162
163
  private WebViewCallbacks callbacks;
163
164
  private PluginCall pluginCall;
@@ -539,6 +540,14 @@ public class Options {
539
540
  this.activeNativeNavigationForWebview = activeNativeNavigationForWebview;
540
541
  }
541
542
 
543
+ public boolean getEnableReloadGesture() {
544
+ return enableReloadGesture;
545
+ }
546
+
547
+ public void setEnableReloadGesture(boolean enableReloadGesture) {
548
+ this.enableReloadGesture = enableReloadGesture;
549
+ }
550
+
542
551
  public boolean getDisableGoBackOnNativeApplication() {
543
552
  return disableGoBackOnNativeApplication;
544
553
  }
@@ -763,6 +772,7 @@ public class Options {
763
772
  copy.setShareSubject(shareSubject);
764
773
  copy.setDisableGoBackOnNativeApplication(disableGoBackOnNativeApplication);
765
774
  copy.setActiveNativeNavigationForWebview(activeNativeNavigationForWebview);
775
+ copy.setEnableReloadGesture(enableReloadGesture);
766
776
  copy.setPresentAfterPageLoad(false);
767
777
  copy.setVisibleTitle(VisibleTitle);
768
778
  copy.setToolbarColor(ToolbarColor);
@@ -11,6 +11,10 @@ public interface WebViewCallbacks {
11
11
 
12
12
  public void pageLoaded();
13
13
 
14
+ public void pageLoadStart();
15
+
16
+ public void pageLoadProgress(double progress);
17
+
14
18
  public void pageLoadError();
15
19
 
16
20
  public void customSchemeIntercepted(String url, boolean opened);
@@ -76,6 +76,7 @@ import androidx.core.graphics.Insets;
76
76
  import androidx.core.view.ViewCompat;
77
77
  import androidx.core.view.WindowInsetsCompat;
78
78
  import androidx.core.view.WindowInsetsControllerCompat;
79
+ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
79
80
  import androidx.webkit.WebMessageCompat;
80
81
  import androidx.webkit.WebSettingsCompat;
81
82
  import androidx.webkit.WebViewCompat;
@@ -328,6 +329,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
328
329
  }
329
330
  }
330
331
 
332
+ private SwipeRefreshLayout swipeRefreshLayout;
331
333
  private WebView _webView;
332
334
  private Toolbar _toolbar;
333
335
  private Options _options = null;
@@ -2171,6 +2173,14 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
2171
2173
 
2172
2174
  this._webView = findViewById(R.id.browser_view);
2173
2175
 
2176
+ this.swipeRefreshLayout = findViewById(R.id.content_browser_layout);
2177
+ if (this.swipeRefreshLayout != null) {
2178
+ boolean enableReloadGesture = _options != null && _options.getEnableReloadGesture();
2179
+ this.swipeRefreshLayout.setEnabled(enableReloadGesture);
2180
+ this.swipeRefreshLayout.setOnRefreshListener(() -> reload());
2181
+ this.swipeRefreshLayout.setOnChildScrollUpCallback((parent, child) -> _webView != null && _webView.canScrollVertically(-1));
2182
+ }
2183
+
2174
2184
  // Apply insets to fix edge-to-edge issues on Android 15+
2175
2185
  applyInsets();
2176
2186
 
@@ -2625,6 +2635,10 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
2625
2635
  public void onProgressChanged(WebView view, int newProgress) {
2626
2636
  super.onProgressChanged(view, newProgress);
2627
2637
 
2638
+ if (_options.getCallbacks() != null) {
2639
+ _options.getCallbacks().pageLoadProgress(newProgress / 100.0);
2640
+ }
2641
+
2628
2642
  // When the page is almost loaded, inject our date picker customization
2629
2643
  // Only if materialPicker option is enabled
2630
2644
  if (newProgress > 75 && !datePickerInjected && _options.getMaterialPicker()) {
@@ -3801,6 +3815,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
3801
3815
  public void reload() {
3802
3816
  if (_webView == null) {
3803
3817
  Log.w("InAppBrowser", "Cannot reload - WebView is null");
3818
+ stopReloadGesture();
3804
3819
  return;
3805
3820
  }
3806
3821
 
@@ -3820,9 +3835,17 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
3820
3835
  Log.d("InAppBrowser", "Loading initial URL: " + _options.getUrl());
3821
3836
  } else {
3822
3837
  Log.w("InAppBrowser", "Cannot reload - no valid URL available");
3838
+ stopReloadGesture();
3823
3839
  }
3824
3840
  } catch (Exception e) {
3825
3841
  Log.e("InAppBrowser", "Error during reload: " + e.getMessage());
3842
+ stopReloadGesture();
3843
+ }
3844
+ }
3845
+
3846
+ private void stopReloadGesture() {
3847
+ if (swipeRefreshLayout != null && swipeRefreshLayout.isRefreshing()) {
3848
+ swipeRefreshLayout.setRefreshing(false);
3826
3849
  }
3827
3850
  }
3828
3851
 
@@ -4912,6 +4935,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
4912
4935
  if (_options.getPreventDeeplink()) {
4913
4936
  Log.d("InAppBrowser", "preventDeeplink is true");
4914
4937
  if (isNotHttpOrHttps) {
4938
+ if (request.isForMainFrame()) {
4939
+ stopReloadGesture();
4940
+ }
4915
4941
  return true;
4916
4942
  }
4917
4943
  }
@@ -4930,6 +4956,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
4930
4956
  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
4931
4957
  context.startActivity(intent);
4932
4958
  Log.i("InAppBrowser", "Intent started for authorized link: " + url);
4959
+ if (request.isForMainFrame()) {
4960
+ stopReloadGesture();
4961
+ }
4933
4962
  return true;
4934
4963
  } catch (ActivityNotFoundException e) {
4935
4964
  Log.e("InAppBrowser", "No app found to handle this authorized link", e);
@@ -4951,6 +4980,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
4951
4980
  if (shouldEmitCustomSchemeEvent && _options.getCallbacks() != null) {
4952
4981
  _options.getCallbacks().customSchemeIntercepted(url, true);
4953
4982
  }
4983
+ if (request.isForMainFrame()) {
4984
+ stopReloadGesture();
4985
+ }
4954
4986
  return true;
4955
4987
  } catch (ActivityNotFoundException e) {
4956
4988
  Log.w("InAppBrowser", "No handler for external URL: " + url, e);
@@ -4962,6 +4994,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
4962
4994
  _options.getCallbacks().pageLoadError();
4963
4995
  rejectOpenWebViewIfNeeded("No handler available for external URL: " + url);
4964
4996
  }
4997
+ if (request.isForMainFrame()) {
4998
+ stopReloadGesture();
4999
+ }
4965
5000
  return true; // prevent WebView from attempting to load the custom scheme
4966
5001
  } catch (URISyntaxException e) {
4967
5002
  Log.w("InAppBrowser", "No handler for external URL: " + url, e);
@@ -4970,6 +5005,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
4970
5005
  _options.getCallbacks().pageLoadError();
4971
5006
  rejectOpenWebViewIfNeeded("No handler available for external URL: " + url);
4972
5007
  }
5008
+ if (request.isForMainFrame()) {
5009
+ stopReloadGesture();
5010
+ }
4973
5011
  return true; // prevent WebView from attempting to load the custom scheme
4974
5012
  }
4975
5013
  }
@@ -4984,6 +5022,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
4984
5022
  _options.getCallbacks().urlChangeEvent(url);
4985
5023
  }
4986
5024
  Log.d("InAppBrowser", "Navigation blocked for URL: " + url);
5025
+ stopReloadGesture();
4987
5026
  return true; // Block the navigation
4988
5027
  }
4989
5028
  }
@@ -5431,6 +5470,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
5431
5470
  if (view == null || _webView == null) {
5432
5471
  return;
5433
5472
  }
5473
+ if (_options.getCallbacks() != null) {
5474
+ _options.getCallbacks().pageLoadStart();
5475
+ }
5434
5476
  if (ProxyRequestSupport.shouldInjectBridge(_options) && proxyBridgeScript != null && proxyAccessToken != null) {
5435
5477
  String preparedProxyBridgeScript = prepareProxyBridgeScript();
5436
5478
  if (preparedProxyBridgeScript != null) {
@@ -5520,6 +5562,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
5520
5562
  updateNavigationButtonsState();
5521
5563
 
5522
5564
  _options.getCallbacks().pageLoaded();
5565
+ stopReloadGesture();
5523
5566
  injectJavaScriptInterface();
5524
5567
 
5525
5568
  // Inject Google Pay polyfills if enabled
@@ -5537,6 +5580,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
5537
5580
  if (request == null || !request.isForMainFrame()) {
5538
5581
  return;
5539
5582
  }
5583
+ stopReloadGesture();
5540
5584
  if (_options.getCallbacks() != null) {
5541
5585
  _options.getCallbacks().pageLoadError();
5542
5586
  }
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
+ <androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
3
  xmlns:app="http://schemas.android.com/apk/res-auto"
4
4
  xmlns:tools="http://schemas.android.com/tools"
5
5
  android:layout_width="match_parent"
@@ -14,4 +14,4 @@
14
14
  android:layout_width="match_parent"
15
15
  android:layout_height="match_parent"/>
16
16
 
17
- </RelativeLayout>
17
+ </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
package/dist/docs.json CHANGED
@@ -586,6 +586,62 @@
586
586
  ],
587
587
  "slug": "addlistenerbrowserpageloaded-"
588
588
  },
589
+ {
590
+ "name": "addListener",
591
+ "signature": "(eventName: 'browserPageLoadStart', listenerFunc: (event: { id?: string; }) => void) => Promise<PluginListenerHandle>",
592
+ "parameters": [
593
+ {
594
+ "name": "eventName",
595
+ "docs": "",
596
+ "type": "'browserPageLoadStart'"
597
+ },
598
+ {
599
+ "name": "listenerFunc",
600
+ "docs": "",
601
+ "type": "(event: { id?: string | undefined; }) => void"
602
+ }
603
+ ],
604
+ "returns": "Promise<PluginListenerHandle>",
605
+ "tags": [
606
+ {
607
+ "name": "since",
608
+ "text": "8.11.0"
609
+ }
610
+ ],
611
+ "docs": "Will be triggered when a main-frame page load starts (link navigation, reload, etc.).",
612
+ "complexTypes": [
613
+ "PluginListenerHandle"
614
+ ],
615
+ "slug": "addlistenerbrowserpageloadstart-"
616
+ },
617
+ {
618
+ "name": "addListener",
619
+ "signature": "(eventName: 'browserPageLoadProgress', listenerFunc: (event: { id?: string; progress: number; }) => void) => Promise<PluginListenerHandle>",
620
+ "parameters": [
621
+ {
622
+ "name": "eventName",
623
+ "docs": "",
624
+ "type": "'browserPageLoadProgress'"
625
+ },
626
+ {
627
+ "name": "listenerFunc",
628
+ "docs": "",
629
+ "type": "(event: { id?: string | undefined; progress: number; }) => void"
630
+ }
631
+ ],
632
+ "returns": "Promise<PluginListenerHandle>",
633
+ "tags": [
634
+ {
635
+ "name": "since",
636
+ "text": "8.11.0"
637
+ }
638
+ ],
639
+ "docs": "Will be triggered as a main-frame page load progresses.\n`progress` is a value from `0` to `1`.",
640
+ "complexTypes": [
641
+ "PluginListenerHandle"
642
+ ],
643
+ "slug": "addlistenerbrowserpageloadprogress-"
644
+ },
589
645
  {
590
646
  "name": "addListener",
591
647
  "signature": "(eventName: 'pageLoadError', listenerFunc: (event: { id?: string; }) => void) => Promise<PluginListenerHandle>",
@@ -1700,6 +1756,26 @@
1700
1756
  "complexTypes": [],
1701
1757
  "type": "boolean | undefined"
1702
1758
  },
1759
+ {
1760
+ "name": "enableReloadGesture",
1761
+ "tags": [
1762
+ {
1763
+ "text": "8.10.8",
1764
+ "name": "since"
1765
+ },
1766
+ {
1767
+ "text": "false",
1768
+ "name": "default"
1769
+ },
1770
+ {
1771
+ "text": "enableReloadGesture: true",
1772
+ "name": "example"
1773
+ }
1774
+ ],
1775
+ "docs": "Enable pull-to-refresh (overscroll from top) to reload the current page.\n- iOS: Uses UIRefreshControl on the WebView scroll view\n- Android: Uses SwipeRefreshLayout around the WebView\n\nOn iOS, this requires overscroll bounce. If `disableOverscroll` is `true`,\nthe reload gesture will not work.",
1776
+ "complexTypes": [],
1777
+ "type": "boolean | undefined"
1778
+ },
1703
1779
  {
1704
1780
  "name": "disableGoBackOnNativeApplication",
1705
1781
  "tags": [
@@ -835,6 +835,20 @@ export interface OpenWebViewOptions {
835
835
  * Test URL: https://capgo.app
836
836
  */
837
837
  activeNativeNavigationForWebview?: boolean;
838
+ /**
839
+ * Enable pull-to-refresh (overscroll from top) to reload the current page.
840
+ * - iOS: Uses UIRefreshControl on the WebView scroll view
841
+ * - Android: Uses SwipeRefreshLayout around the WebView
842
+ *
843
+ * On iOS, this requires overscroll bounce. If `disableOverscroll` is `true`,
844
+ * the reload gesture will not work.
845
+ *
846
+ * @since 8.10.8
847
+ * @default false
848
+ * @example
849
+ * enableReloadGesture: true
850
+ */
851
+ enableReloadGesture?: boolean;
838
852
  /**
839
853
  * Disable the possibility to go back on native application,
840
854
  * useful to force user to stay on the webview, Android only
@@ -1534,6 +1548,24 @@ export interface InAppBrowserPlugin {
1534
1548
  addListener(eventName: 'browserPageLoaded', listenerFunc: (event: {
1535
1549
  id?: string;
1536
1550
  }) => void): Promise<PluginListenerHandle>;
1551
+ /**
1552
+ * Will be triggered when a main-frame page load starts (link navigation, reload, etc.).
1553
+ *
1554
+ * @since 8.11.0
1555
+ */
1556
+ addListener(eventName: 'browserPageLoadStart', listenerFunc: (event: {
1557
+ id?: string;
1558
+ }) => void): Promise<PluginListenerHandle>;
1559
+ /**
1560
+ * Will be triggered as a main-frame page load progresses.
1561
+ * `progress` is a value from `0` to `1`.
1562
+ *
1563
+ * @since 8.11.0
1564
+ */
1565
+ addListener(eventName: 'browserPageLoadProgress', listenerFunc: (event: {
1566
+ id?: string;
1567
+ progress: number;
1568
+ }) => void): Promise<PluginListenerHandle>;
1537
1569
  /**
1538
1570
  * Will be triggered when page load error
1539
1571
  */