Preventing iframes containing target="_blank" links from taking over the app

I work on an Ionic app and I’ve been stuck on an issue for some time regarding iframes which contain links with targets set to “_blank”. These can be either anchor tags in the html, or javascript window.open(“www.myurl.com”, “_blank”) events.

These “_blank” target links when opened in the app outside of an iframe will open inside of the inappbrowser, which is great. However, if one of these links is contained within an iframe, the destination url will replace the application within the Cordova browser until the app is force quit and reloaded, which isn’t a great experience to say the least.

The contents of the iframes are usually inline ads, whose contents vary and are not known ahead of time, and sometimes contain additional nested iframes themselves or dynamically created anchor tags. This makes solutions like iterating through all anchor tags and looking for target attributes, or injecting the frame with js which listens for open event and tries swapping out the “_blank” target and replacing with “_system” unreliable.

I have also tried using a Cordova plugin at the OS level to listen for navigation events since we can’t reliably monitor them inside an iframe from the app controller. We can intercept the traffic here, but unfortunately can’t make the distinction between a good link behaving normally being picked up by the inapp browser, and a bad one within an iframe which takes over the application.

This issue has prevented us from using a number of third party widgets in my app, but most notably has made monetization difficult as we can’t sell ads we use in our DoubleClick for Publishers until we can guarantee the inline ads we inject into our html content will work correctly and not break the application.

I believe this is technically a Cordova issue, but as Ionic is one of, if not the largest of the Cordova frameworks, this issue would surely impact other Ionic developers. I have to imagine someone else has tried integrating DFP ads which incorporate iframes, or use some other third party widget which uses an iframe containing links with target “_blank” links into an Ionic app.

I’ve done a lot of work with Ionic v1, not so much with the newer versions though. Am I correct in assuming that this is still something I will have to address even if I update to a newer version of Ionic?

Have any of you run into this issue, and if so, how were you able to overcome it?

Have any of you had success with another ad platform using inline injectable html ads in your Ionic app?

Any feedback from those who have tried to find a solution with this would be greatly appreciated!

1 Like

Have the same issue. I will be OK with both opening inside iframe or in system browser but not with the current behavior when inAppBrowser is opened.

Any updates so far?

No updates. This is something that has been an issue for years and I don’t expect it to be resolved any time soon. I’d love to be wrong though.

Luckily I found solution for myself. I use whitelist plugin and put all links inside iframe to be against whitelisted URLs pattern. With this page is opened either in iframe itself or in an external browser.

1 Like

Unfortunately, we don’t know what the URL’s of the DFP ads will be ahead of time so the whitelisting approach doesn’t solve this issue for us. We also incorporate articles within our app which can contain inline links we won’t know ahead of time, which would break if they weren’t on our whitelist.

I’m glad you found something that worked for you, though!

Hi, I’m facing the same issue. How where you able to intercept the navigation events? (What plugin or what listener?)

Hi, I had the same issue but finally I could solve it, ads from DFP were a requirement for the application that I was building and I have the problem that some ads opened inside the WebView and it broke the flow of the app, I had to read and investigate from different sources, I don´t know if it´s the best solution, but for now it works for me.

I change a function from CDVIntentAndNavigationFilter.m, this function starts on the line 74 and this is the final function

+ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist
{
    // a URL can only allow-intent OR allow-navigation, if both are specified,
    // only allow-navigation is allowed

    BOOL allowNavigationsPass = [navigationsWhitelist URLIsAllowed:url logFailure:NO];
    BOOL allowIntentPass = [intentsWhitelist URLIsAllowed:url logFailure:NO];

    NSRange match;
    match = [url.absoluteString rangeOfString: @"https://googleads.g.doubleclick.net/pcs/click"];


    if(match.location != NSNotFound) {
        return CDVIntentAndNavigationFilterValueIntentAllowed;
    } else if (allowNavigationsPass && allowIntentPass) {
        return CDVIntentAndNavigationFilterValueNavigationAllowed;
    } else if (allowNavigationsPass) {
        return CDVIntentAndNavigationFilterValueNavigationAllowed;
    } else if (allowIntentPass) {
        return CDVIntentAndNavigationFilterValueIntentAllowed;
    }

    return CDVIntentAndNavigationFilterValueNoneAllowed;
}

I only added a validation because the urls to open the ads comes from that domain

https://googleads.g.doubleclick.net

If you want you can make a hook to change the function above automatically, or you can do it manual, I made a hook of type “after_platform_add”, you can find information about hooks here

const fs = require('fs');
const replace = require('replace');

const PATH = "platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/";
const FILE = "CDVIntentAndNavigationFilter.m";

if(fs.existsSync(`${PATH}${FILE}`)) {
    console.log("\n\n -------------- Updating file");
    replace({
        regex: /if \(allowNavigationsPass \&\& allowIntentPass\) \{/g,
        replacement: 'NSRange match;\n\tmatch = [url.absoluteString rangeOfString: @"https://googleads.g.doubleclick.net/pcs/click"];\n\n\tif(match.location != NSNotFound) {\n\t\treturn CDVIntentAndNavigationFilterValueIntentAllowed;\n\t} else if(allowNavigationsPass && allowIntentPass) {',
        paths: [`${PATH}${FILE}`],
        recursive: true,
        silent: true,
      });
} else {
    console.log("\n\n -------------- Error, the file does not exist");    
}

This answer helped me a lot to realize where the problem was and how to build the hook.

I hope that this helps someone :slight_smile: