cordova-plugin-inappbrowser icon indicating copy to clipboard operation
cordova-plugin-inappbrowser copied to clipboard

message event fires only once for same inAppBrowser window

Open julia-fix opened this issue 6 years ago • 6 comments
trafficstars

Bug Report

Problem

When message event listener contains another inAppBrowser call to open link in system browser, message event fires only once for one inAppBrowser window

What is expected to happen?

Every time when postMessage is executed in inAppBrowser window, message event listener would be fired.

What does actually happen?

Only first message is received by message event listener.

Information

Command or Code

This is code from remote web page that is opened in inAppBrowser:

$('.share-button').on('click', function(e) {
    var href = $(this).attr('href');
     e.preventDefault();
    console.log('sending message', href);
    webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify({url: href}));
    return false;
 });

Code in application that calls inAppBrowser window and listens to message event:

element.on('click', function(e) {
    e.preventDefault();
    var browserWindow = cordova.InAppBrowser.open(element.attr('href'), element.attr('target'), 'location=no,zoom=no');

    browserWindow.addEventListener('message', function(params) {
        console.log('params', params);
        if (params.data.url) {
            cordova.InAppBrowser.open(params.data.url, '_system');
        } 
    });

    return false;
});

Environment, Platform, Device

Platform: Android. Tested on emulator (API 26) and real device (Android 8.1) with same result.

Version information

Cordova: 9.0.0 ([email protected])

cordova-plugin-inappbrowser 3.1.0 "InAppBrowser"

Cordova platform: android 7.1.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

julia-fix avatar Sep 22 '19 19:09 julia-fix

I just ran into this as well. This happens because the plugin can only store one reference to a cordova callback context. If you open something in the system browser, it overwrites this reference, even though no events will ever be fired for the system browser window.

As a workaround you need to update your event subscriptions to the new object, returned from the call to open the _system window. This reference will fire the events for the still existing, initial, in app browser window.

I hope this makes sense.

diesieben07 avatar Nov 04 '19 11:11 diesieben07

Hi @diesieben07

I am also dealing with the same problem. Would you mind providing a code example of how to update the event subscriptions?

Thanks

flowMartin avatar Dec 02 '19 17:12 flowMartin

I am using Ionic, so you'll have to adapt this if you are using plain cordova. I am also just using pseudocode here, but it should be clear:

class MyComponent {
  private iabSubscriptions = [];
  private iabObject: InAppBrowserObject|null = null;

  private subscribeIab(iab: InAppBrowserObject)
    // unsubscribe from the old IAB object
    for (const s of iabSubscriptions) {
      s.unsubscribe();
    }
    this.iabObject = iab;
    this.iabSubscriptions = [
      // do your subscriptions here
      iab.on('message').subscribe(arg => {
        const newIab = this.inAppBrowser.create(/* new url here */, '_system');
        this.subscribeIab(newIab);
      })
    ]; 
  }

  private openIab(url: string) {
    this.subscribeIab(this.inAppBrowser.create(url));
  }

  private closeIab() {
    if (this.iabObject) {
      this.iabObject.close();
      this.iabObject = null;
    }
  }
}

diesieben07 avatar Dec 03 '19 14:12 diesieben07

I just ran into this as well. This happens because the plugin can only store one reference to a cordova callback context. If you open something in the system browser, it overwrites this reference, even though no events will ever be fired for the system browser window.

As a workaround you need to update your event subscriptions to the new object, returned from the call to open the _system window. This reference will fire the events for the still existing, initial, in app browser window.

I hope this makes sense.

Absolute legend. Thanks for sharing, that fixed it for me!

rigiddesign avatar Mar 24 '20 20:03 rigiddesign

@diesieben07 you are an angel!! thank you very much!

sardapv avatar Sep 09 '20 09:09 sardapv

Unfortunately, this is not possible under Cordova because iab.on('message') does not exist as a function.

I simply start a new instance of the InAppBrowser when the app comes back to the foreground from the background. I make sure internally that I cache the current URL so that I always reload the last page.

The code could look something like this:

var currentUrl = 'https://example.com';

document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() { // Start default page openIAB(currentUrl); // Event when app goes to foreground document.addEventListener('resume', resumeToApp, false);
}

function openIAB(url) { // Open InAppBrowser var iab = cordova.InAppBrowser.open(url, "_blank", 'usewkwebview=yes,hidden=yes,hardwareback=no,toolbar=no,hidenavigationbuttons=yes'); // Store current url iab.addEventListener('loadstart', function(e) { currentUrl = e.url; }); }

function resumeToApp() { openIAB(currentUrl); }

fburian avatar Feb 19 '24 14:02 fburian