Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ When you open a webview with this method, a JavaScript interface is automaticall
- `window.mobileApp.close()`: Closes the webview from JavaScript
- `window.mobileApp.postMessage({detail: {message: "myMessage"}})`: Sends a message from the webview to the app, detail object is the data you want to send to the webview

Promise timing differs by platform when `isPresentAfterPageLoad` is used.
Android resolves with `{ id }` after the dialog is ready to control, while iOS resolves with `{ id }` immediately after creating the native webview.

| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| **`options`** | <code><a href="#openwebviewoptions">OpenWebViewOptions</a></code> |
Expand Down Expand Up @@ -868,7 +871,7 @@ And in the AndroidManifest.xml file:
| **`backgroundColor`** | <code><a href="#backgroundcolor">BackgroundColor</a></code> | Background color of the browser | <code>BackgroundColor.BLACK</code> | 0.1.0 |
| **`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> | |
| **`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> | |
| **`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. | <code>false</code> | 0.1.0 |
| **`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 |
| **`isInspectable`** | <code>boolean</code> | Whether the website in the webview is inspectable or not, ios only | <code>false</code> | |
| **`isAnimated`** | <code>boolean</code> | Whether the webview opening is animated or not, ios only | <code>true</code> | |
| **`showReloadButton`** | <code>boolean</code> | Shows a reload button that reloads the web page | <code>false</code> | 1.0.15 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -874,9 +874,6 @@ public void run() {
dialog.activity = InAppBrowserPlugin.this.getActivity();
registerWebView(webViewId, dialog);
dialog.presentWebView();
JSObject result = new JSObject();
result.put("id", webViewId);
call.resolve(result);
}
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public ProxiedRequest() {
public static final int FILE_CHOOSER_REQUEST_CODE = 1000;
public ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> mFilePathCallback;
private boolean openWebViewResolved;

// Temporary URI for storing camera capture
public Uri tempCameraUri;
Expand All @@ -154,6 +155,7 @@ public WebViewDialog(Context context, int theme, Options options, PermissionHand
this._context = context;
this.permissionHandler = permissionHandler;
this.isInitialized = false;
this.openWebViewResolved = false;
this.capacitorWebView = capacitorWebView;
}

Expand All @@ -165,6 +167,16 @@ public String getInstanceId() {
return instanceId;
}

private void resolveOpenWebViewIfNeeded() {
if (openWebViewResolved || _options == null || _options.getPluginCall() == null) {
return;
}
openWebViewResolved = true;
JSObject result = new JSObject();
result.put("id", instanceId);
_options.getPluginCall().resolve(result);
}

// Add this class to provide safer JavaScript interface
private class JavaScriptInterface {

Expand Down Expand Up @@ -978,10 +990,10 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
show();
applyHiddenMode();
}
_options.getPluginCall().resolve();
resolveOpenWebViewIfNeeded();
} else if (!this._options.isPresentAfterPageLoad()) {
show();
_options.getPluginCall().resolve();
resolveOpenWebViewIfNeeded();
}
}

Expand Down Expand Up @@ -2796,7 +2808,7 @@ public void onPageFinished(WebView view, String url) {
boolean usePreShowScript = _options.getPreShowScript() != null && !_options.getPreShowScript().isEmpty();
if (!usePreShowScript) {
show();
_options.getPluginCall().resolve();
resolveOpenWebViewIfNeeded();
Comment on lines 2835 to +2838

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve openWebView on deferred-load failures

With isPresentAfterPageLoad=true, this change makes openWebView() resolve only from onPageFinished, so any first-load failure path that does not reach that callback leaves the promise pending forever. In the same WebViewClient, failure branches like onReceivedError(...) and the custom-scheme ActivityNotFoundException path only emit pageLoadError and never resolve/reject the original plugin call, which means callers never get the { id } needed to recover (close/retry) when initial navigation fails.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in d26c6c7. The deferred-load path now rejects the original openWebView() call on initial main-frame failures before first initialization, specifically for custom-scheme ActivityNotFoundException handling and onReceivedError(...). That preserves the single-return contract while avoiding a hung promise when isPresentAfterPageLoad=true.

} else {
executorService.execute(
new Runnable() {
Expand All @@ -2811,7 +2823,7 @@ public void run() {
@Override
public void run() {
show();
_options.getPluginCall().resolve();
resolveOpenWebViewIfNeeded();
}
}
);
Expand Down
6 changes: 6 additions & 0 deletions src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@ export interface OpenWebViewOptions {
/**
* 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.
* @since 0.1.0
* @default false
* @example
Expand Down Expand Up @@ -852,6 +855,9 @@ export interface InAppBrowserPlugin {
* - `window.mobileApp.close()`: Closes the webview from JavaScript
* - `window.mobileApp.postMessage({detail: {message: "myMessage"}})`: Sends a message from the webview to the app, detail object is the data you want to send to the webview
*
* Promise timing differs by platform when `isPresentAfterPageLoad` is used.
* Android resolves with `{ id }` after the dialog is ready to control, while iOS resolves with `{ id }` immediately after creating the native webview.
*
* @returns Promise that resolves with the created webview id.
* @since 0.1.0
*/
Expand Down