cordova-plugin-inappbrowser
cordova-plugin-inappbrowser copied to clipboard
'beforeload' event can only fire once in an InAppBrowser session
Bug Report
Problem
When an InAppBrowser session is started, the 'beforeload' event will only ever trigger once.
What is expected to happen?
Every time a redirect event is triggered from the InAppBrowser, 'beforeload' should trigger and run each time.
What does actually happen?
If the InAppBrowser session is not killed as a result of the 'beforeload' event, all attempts at redirect from that moment on do nothing. All URLs essentially break.
Information
I have a SPA that gets accessed as part of my Cordova application. There are some URLs within that SPA that cannot be handled by Cordova's InAppBrowser (at least on Android) in any capacity. Any URL that does not use the HTTP protocol (for example, deep link URLs that use a different protocol) fail. As a result, I wanted to hook into the 'beforeload' event for two reasons:
- I can intercept this request to the URL the InAppBrowser cannot handle and redirect the user to that page using the system browser.
- I can prevent the user's SPA session from being killed off and having to be refreshed.
Using the 'beforeload' event accomplishes both items. My InAppBrowser session switches to the System Browser, and if I back out of the System Browser or return to the application, the page stays where it was in the state it was in. However, from that moment on, every single link fails to work. I can no longer navigate in any capacity to any other URL. This makes the 'beforeload' event completely useless to me, because I need to be able to navigate to other locations.
Command or Code
inAppObj.addEventListener('beforeload', (event: any, callback: Function) => { let currentURL: string = event.url; if (currentURL.includes('someurl')) { cordova.InAppBrowser.open(currentURL, '_system'); } else { callback(currentURL); } });
Environment, Platform, Device
This is specifically an issue that I've noticed on Android, as I am trying to fix an issue specific to Android.
Version information
"cordova": "9.0.0", "cordova-android": "8.1.0", "cordova-ios": "5.0.0", "cordova-browser": "6.0.0", "cordova-plugin-androidx": "1.0.2", "cordova-plugin-androidx-adapter": "1.1.0", "cordova-plugin-device": "2.0.3", "cordova-plugin-firebasex": "6.1.0", "cordova-plugin-inappbrowser": "3.1.0", "cordova-plugin-local-notification": "0.9.0-beta.2", "cordova-plugin-network-information": "2.0.2", "cordova-plugin-secure-storage": "3.0.2", "cordova-plugin-whitelist": "1.3.4"
Checklist
- [x] I searched for existing GitHub issues
- [x] I updated all Cordova tooling to most recent version
- [x] I included all the necessary information above
Hint: using inAppBrowser to open an external link can reset the current inAppBrowser instance, so to open an external link, you need to use a different method. See this code for an example. See also CB-13198.
It's not resetting the current InAppBrowser instance at all.
The functionality I implemented works perfectly fine one time, and only one time within the InAppBrowser instance. The beforeload callback is triggered, and the functionality works fine. If you do not close or redirect the InAppBrowser instance as a result of the beforeload callback, all event hooks die completely. That's not proper flow in any circumstance.
I cannot see how this is intended functionality. There's no excuse for the hooks to die off. Either the InAppBrowser should refresh itself if it can't keep the hooks alive (which in my opinion would make beforeload entirely useless, as the entire point of the call is to stop a redirect before it even starts), or it shouldn't let the hooks die at all.
In my scenario, everything I want to do with the beforeload event is done as I wanted it to be done. The problem is that after I return from the beforeload hook, if the end result of the beforeload function wasn't to then load a URL anyway, Cordova stops listening to all events from the InAppBrowser. In fact, it doesn't listen to anything at all, and all links in the instance fail to work from then on.
Hi @Polantaris
Does this touch on the issue you've been having? The ticket is entitled:
InAppBrowser doesnot disptach events after system browser is open using cordova.InAppBrowser.open(url, '_system')
https://issues.apache.org/jira/browse/CB-13198
The user there posted a temporary solution, which i've been using myself.
Just ran into this too. I'm not sure it's the intended behaviour. It only seems to happen on android, for instance. Attaching all events to whatever's returned by the _system open call fixes my issue in the meantime.
In all honesty, I wouldn't expect a fix and to meet my release I had to abandon using the beforeload event entirely. My team accepted the loss of potential functionality that came with using the loadstart event when we had wanted to use beforeload.
@Polantaris I moved my comment over to https://github.com/apache/cordova-plugin-inappbrowser/issues/540 which is where I meant to post it.
When you say you ended up using loadstart instead, I don't think there's anything we can use there as we needed to intercept loading and decide whether to continue in the launched InApp browser or open in a new system browser. Did you have a similar requirement?
@Polantaris I moved my comment over to #540 which is where I meant to post it.
Ah, my bad, sorry for any confusion.
When you say you ended up using
loadstartinstead, I don't think there's anything we can use there as we needed to intercept loading and decide whether to continue in the launched InApp browser or open in a new system browser. Did you have a similar requirement?
My requirement was that I wanted to intercept specific requests before the In App Browser attempted to load them because they would be opened outside of the In App Browser anyway, but when done in the loadstart you would lose state information on the page that the redirect came from.
For example, if the user was on a single page application, and clicked a link deep within that that would just be opened in a separate window (specifically it was an app protocol that the IAB couldn't even recognize), I wanted to not leave the page the IAB was on because they would lose their state on the page and would have to re-navigate to wherever they were when they came back.
The beforeload event would work to allow this, but it only worked one time and afterward every link on the app effectively became worthless, even ones that wouldn't trigger the beforeload condition. Completely unusable. This issue was never resolved and I had to take the state loss.
Ah, my bad, sorry for any confusion.
That's fine, more than happy to have someone reply!
For example, if the user was on a single page application, and clicked a link deep within that that would just be opened in a separate window (specifically it was an app protocol that the IAB couldn't even recognize), I wanted to not leave the page the IAB was on because they would lose their state on the page and would have to re-navigate to wherever they were when they came back.
That's effectively what we're trying to do also, I think anyway. We want some links from a single page app to open in a system browser and the rest to remain in the launched InApp browser. I thought you need to use beforeload to either continue the load in the opened InApp browser using _loadAfterBeforeload or else load a new system browser? I can't see how I'd prevent navigation without using beforeload, though I'm maybe misunderstanding.
I can't see how I'd prevent navigation without using beforeload, though I'm maybe misunderstanding.
You can't, that's effectively the problem. I had to drop that requirement (which I didn't want to do) because beforeload doesn't work at all.
You might be able to rig those links using window.open with the target _blank. Cordova should recognize that as a system browser open request, but that'll change the behavior of the page for people not using the In App Browser as well and open those links in separate tabs/windows.
I spent about a collective month or so on this issue and came out empty. Without the event working properly there's nothing you can do that I'm aware of to achieve the same functionality.
I can't see how I'd prevent navigation without using beforeload, though I'm maybe misunderstanding.
You can't, that's effectively the problem. I had to drop that requirement (which I didn't want to do) because
beforeloaddoesn't work at all.You might be able to rig those links using
window.openwith the target_blank. Cordova should recognize that as a system browser open request, but that'll change the behavior of the page for people not using the In App Browser as well and open those links in separate tabs/windows.I spent about a collective month or so on this issue and came out empty. Without the event working properly there's nothing you can do that I'm aware of to achieve the same functionality.
To add insult to injury: I don't know if it's specific to angular but window.open with the target _blank does nothing when inside a Cordova inAppBrowser so we had to opt for the target _system to get it to open the url within the Cordova app wrapper. Which is also not the required behaviour because we need external links to open in the system browser of the mobile device instead of within the app because then you can't navigate back to where you where on an IOS device because they don't have a built in back button, and using the toolbar doesn't allow for a seamless looking experience.
Furthermore, even if the behaviour did work more than a single time without killing the listener there is an issue with beforeload and OIDC authentication flows. Even if you have a callback function like this:
function beforeloadCallBack(params, callback) { callback(params.url); }
That does nothing more than just listen and redirect It does not work with OIDC flows.
https://github.com/apache/cordova-plugin-inappbrowser/issues/965 likely the reason why it works how it works