Question

I have a cordova (2.7.0) android app that is crashing with an Application Error when it tries to load an iframe where the source has a protocol relative (network-path reference) src.

For instance, if the iframe is:

<iframe src="//instagram.com/p/beGdCuhQYl/embed/?wmode=opaque&amp;wmode=opaque" width="800" height="928" style="border:0;" frameborder="0"></iframe>

Then the app tries to load the source from

file://instagram.com/p/beGdCuhQYl/embed/?wmode=opaque&amp;wmode=opaque

Since the html page that loads this iframe is loaded from the file system, it makes sense that it is doing this. However, is there a way to stop the app from crashing? The same cordova app on iOS just doesn't load anything, and has a blank iframe. I would be nice if the android app behaved the same way.

It would be even nicer if there was a way to tell the cordova app to load these types of urls from http:// and not file:// but I think that is asking too much.

Was it helpful?

Solution

Ok, so I ended up doing this in two parts. First part, try to fix as many protocol relative urls as possible in javascript, and the second part was to provide some java code to ignore any that I missed.

First part (uses jQuery)

/**
 * Takes text, looks for elements with src attributes that are
 * protocol relative (//) and converts them to http (http://)
 * @param {String} text the text that you want to fix urls in
 * @returns {String} the updated text with corrected urls
 */
fixProtocolRelativeUrlsInText: function(text) {
    var $html, $elements;
    try {
        $html = $('<div>' + text + '</div>');
        $elements = $html.find('[src^="//"]');

        if ($elements.length) {
            $elements.each(function() {
                var $this = $(this);
                $this.attr('src', 'http:' + $this.attr('src'));
            });
            return $html.html();
        } else {
            return text;
        }
    } catch(ex) {
        return text;
    }
},

Second part:

/**
 * Override the default makeWebViewClient and provide a custom handler for protocol
 * relative urls.
 */
@Override
public CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
    //
    // We already try to fix protocol relative urls in the javascript. But this is a safety net in case anything
    // gets through. So, in order to not crash the app, lets handle these types ourself and just swallow them up
    // for now. The url won't load but at least it won't crash the app either. By the time the protocol relative
    // url gets in here, it has the file: appended to it already. If it was a true file:// path to something on the
    // device, then it will have file:///some/path, and if it was a protocol relative url that was converted to a
    // file:// then it will have file://some.domain, so we look for urls that don't have the three /'s
    //
    final Pattern pattern = Pattern.compile("^file://[^/].*$");

    CordovaWebViewClient webViewClient;

    if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
        webViewClient = new CordovaWebViewClient(this, webView) {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                Matcher matcher = pattern.matcher(url);
                if (matcher.matches()) {
                    Log.i(LOG_TAG, "swallowing url '" + url + "'");
                    return true;
                } else {
                    return super.shouldOverrideUrlLoading(view, url);
                }
            }
        };
    } else {
        webViewClient = new IceCreamCordovaWebViewClient(this, webView) {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                Matcher matcher = pattern.matcher(url);
                if (matcher.matches()) {
                    Log.i(LOG_TAG, "swallowing url '" + url + "'");
                    return true;
                } else {
                    return super.shouldOverrideUrlLoading(view, url);
                }
            }
        };
    }

    return webViewClient;
}

OTHER TIPS

Cordova doesn't support protocol relative src, it expects you to specify either file, or http.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top