Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -863,10 +863,7 @@ public void run() {
dialog.setInstanceId(webViewId);
dialog.activity = InAppBrowserPlugin.this.getActivity();
registerWebView(webViewId, dialog);
dialog.presentWebView();
JSObject result = new JSObject();
result.put("id", webViewId);
call.resolve(result);
dialog.presentWebView();
}
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -972,16 +972,17 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {

setupToolbar();
setWebViewClient();

JSObject result = new JSObject();
result.put("id", instanceId);
if (this._options.isHidden()) {
if (_options.getInvisibilityMode() == Options.InvisibilityMode.FAKE_VISIBLE) {
show();
applyHiddenMode();
}
_options.getPluginCall().resolve();
_options.getPluginCall().resolve(result);
} else if (!this._options.isPresentAfterPageLoad()) {
show();
_options.getPluginCall().resolve();
_options.getPluginCall().resolve(result);
}
Comment on lines +975 to 986
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there's any mutual exclusion logic between isHidden and isPresentAfterPageLoad
echo "Checking Options class for isHidden/isPresentAfterPageLoad relationship:"
rg -n -A 5 "isPresentAfterPageLoad|isHidden" android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java

echo ""
echo "Checking plugin for how these options are set together:"
rg -n -B 2 -A 5 "setHidden|setPresentAfterPageLoad" android/src/main/java/ee/forgr/capacitor_inappbrowser/

Repository: Cap-go/capacitor-inappbrowser

Length of output: 10943


🏁 Script executed:

#!/bin/bash
# Check the onPageFinished method to see resolution logic
echo "Checking onPageFinished method (around lines 2784-2808):"
sed -n '2780,2820p' android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java

echo ""
echo "Checking for any 'resolved' or 'completed' flags:"
rg -n "resolved|completed|isResolved" android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java | head -20

Repository: Cap-go/capacitor-inappbrowser

Length of output: 2457


🏁 Script executed:

#!/bin/bash
# Search for validation logic that might prevent both flags being true
echo "Checking for validation in Options class:"
sed -n '1,600p' android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java | grep -A 10 -B 5 "setHidden\|setPresentAfterPageLoad" | head -40

echo ""
echo "Checking for validation in InAppBrowserPlugin:"
rg -B 5 -A 10 "setHidden|setPresentAfterPageLoad" android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java | grep -A 10 -B 5 "validate\|check\|if.*hidden\|if.*present"

echo ""
echo "Checking for any assertions or guards about these options together:"
rg -n "isHidden.*isPresentAfterPageLoad|isPresentAfterPageLoad.*isHidden" android/src/main/java/ee/forgr/capacitor_inappbrowser/

Repository: Cap-go/capacitor-inappbrowser

Length of output: 1077


🏁 Script executed:

#!/bin/bash
# Check if PluginCall is defined in this repo or if it's from Capacitor
echo "Searching for PluginCall definition:"
find . -name "*.java" -type f -exec grep -l "interface PluginCall\|class PluginCall" {} \;

echo ""
echo "Checking imports to see where PluginCall comes from:"
rg "import.*PluginCall" android/src/main/java/ee/forgr/capacitor_inappbrowser/ | head -5

echo ""
echo "Checking Capacitor documentation or comments about resolve:"
rg -B 3 -A 3 "getPluginCall.*resolve" android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java | head -20

Repository: Cap-go/capacitor-inappbrowser

Length of output: 1237


🌐 Web query:

Capacitor PluginCall resolve() called multiple times behavior

💡 Result:

By default in Capacitor, a PluginCall/CAPPluginCall is single-shot: once you call call.resolve() or call.reject() the bridge removes its bookkeeping for that callback, so later resolve() calls won’t be delivered back to JS (and may just log/behave like a no-op). [1]

If you intentionally need to send multiple results from one native call, you must mark the call as a callback/stream by setting keepAlive (call.setKeepAlive(true) on Android / call.keepAlive = true on iOS). With keepAlive = true, resolve() can be called repeatedly and each result is sent to JS. [1]

Also, even with keepAlive, you cannot receive multiple results via a normal JS Promise (await plugin.method() / .then(...)), because a promise resolves only once. You must use a callback-style method (or plugin events like notifyListeners) to receive multiple updates. [2]

Sources: [1] Saving/Persisting Plugin Calls (Capacitor docs) (capacitorjs.jp), [2] Ionic Forum: “Help with resolving call multiple times (Call keepAlive)” (forum.ionicframework.com)

Citations:


🏁 Script executed:

#!/bin/bash
# Check if setKeepAlive is used on PluginCall
echo "Searching for setKeepAlive usage:"
rg -n "setKeepAlive" android/src/main/java/ee/forgr/capacitor_inappbrowser/

echo ""
echo "Also check if the PluginCall returned by getPluginCall is modified:"
rg -n "getPluginCall()" android/src/main/java/ee/forgr/capacitor_inappbrowser/ | head -10

Repository: Cap-go/capacitor-inappbrowser

Length of output: 876


Fix correctly includes instanceId in the resolved result.

The implementation properly creates a JSObject with the id field set to instanceId, addressing the issue where JavaScript received undefined for the webViewId.

However, there is a logical issue: if both isHidden() and isPresentAfterPageLoad() are true, presentWebView() will resolve at line 982, and onPageFinished() will attempt to resolve again at lines 2793/2808. While Capacitor's single-shot PluginCall prevents the second resolution from reaching JavaScript, this still represents flawed logic. Either:

  • Ensure isHidden() and isPresentAfterPageLoad() are mutually exclusive through validation, or
  • Add a guard to prevent duplicate resolution attempts (e.g., by checking if the call is already resolved or using a completion flag).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java`
around lines 975 - 986, presentWebView() currently resolves the same PluginCall
that onPageFinished() may also resolve, causing duplicate resolution attempts;
add a guard boolean (e.g., private boolean presentResolved) to WebViewDialog and
use it to ensure the PluginCall is resolved only once: before calling
_options.getPluginCall().resolve(result) in presentWebView() and before any
resolve call in onPageFinished(), check if presentResolved is false, then call
resolve and set presentResolved = true; reference the methods presentWebView(),
onPageFinished(), the _options.getPluginCall() call site, and the
isHidden()/isPresentAfterPageLoad() checks when adding this guard.

}

Expand Down Expand Up @@ -2780,14 +2781,16 @@ public void onPageFinished(WebView view, String url) {
if (view == null || _webView == null) {
return;
}
JSObject result = new JSObject();
result.put("id", instanceId);
if (!isInitialized) {
isInitialized = true;
_webView.clearHistory();
if (_options.isPresentAfterPageLoad()) {
boolean usePreShowScript = _options.getPreShowScript() != null && !_options.getPreShowScript().isEmpty();
if (!usePreShowScript) {
show();
_options.getPluginCall().resolve();
_options.getPluginCall().resolve(result);
} else {
executorService.execute(
new Runnable() {
Expand All @@ -2802,7 +2805,7 @@ public void run() {
@Override
public void run() {
show();
_options.getPluginCall().resolve();
_options.getPluginCall().resolve(result);
}
}
);
Expand Down
Loading