Ionic v1 app and WKWebView CORS limitations - external APIs


Hi there, I’ve been working towards migrating my v1 app to WKWebView. There are several issues I need to figure out a solution for, but here are a few I am hoping others have faced (and solved):

  1. Due to enforced CORS issue, several well known APIs don’t work anymore with browser http. Here are some examples as well as - all from popular sites, don’t work due to missing Access-Control-Allow-Origin headers. It’s unreasonable to expect them to insert a localhost:8080 - why would they do that? How have others solved these issues?

  2. I realize there is a cordova-advanced-http plugin that can sidestep this. Is anyone aware of a angularjs wrapper that switches between this and browser $http - my app needs to work in both desktop and mobile. There is a wrapper written by a contributor, but that’s for Angular, not AngularJS. If there isn’t one, can someone point me to some simple template that can help me start writing one? I don’t want to replace all code elements around my codebase. Would prefer to keep $http everywhere

  3. Here is the zinger. Even if I use cordova.plugin.http for regular APIs, I need to use the browser <img src> tag to display images that need to borrow credentials from these API calls. Will it work - because img src always uses a browser http function. I know there are several replacements to img but none of the handle streaming images. Thanks.


Understandably, ionic v1 has more or less become an echo chamber now.
Anyway, I’ve made progress and figured out how to write what I need. It needs cleanup and error/fixing which I will do over the next few days but in general it involves:

  1. using a decorator
  2. Making sure you ignore local template/url/asset requests
  3. parse response to JSON or not, depending on responseType=='text'
  4. Make sure we don’t use .success & .error and use .then() instead
  5. Convert cordova-plugin-http into one that returns promises
  6. encode the URLs before passing it

    // Wraps around $http that switches between browser XHR
    // or cordova-advanced-http based on if cordova is available 
    // credits:
    // a)
    // b)

    $provide.decorator('$http', ['$delegate', '$q', function($delegate, $q) {
      // create function which overrides $http function
      var $http = $delegate;

      var wrapper = function () {
        var url;
        var method;

         url = arguments[0].url;
         method = arguments[0].method;
        var isOutgoingRequest = /^(http|https):\/\//.test(url);
        if (window.cordova && isOutgoingRequest) {
          console.log ("**** -->"+method+"<-- using native HTTP with:"+url);
          var d = $q.defer();
          var options = {
            method: method,
            data: arguments[0].data,
            headers: arguments[0].headers,
            timeout: arguments[0].timeout,
            responseType: arguments[0].responseType

            function (succ) {
              // automatic JSON parse if no responseType: text
              // fall back to text if JSON parse fails too
              if (options.responseType =='text') {
                // don't parse into JSON
                return d.promise;
              else {
                try {
                  return d.promise;
                catch (e) {
                  return d.promise;

            function (err) {
              console.log ("***  Inside native HTTP error");
              return d.promise;
            return d.promise;
        else { // not cordova, so lets go back to default http
          console.log ("**** "+method+" using XHR HTTP for "+url);
          return $http.apply($http, arguments);


      // wrap around all HTTP methods
      Object.keys($http).filter(function (key) {
        return (typeof $http[key] === 'function');
      }).forEach(function (key) {
        wrapper[key] = function () {
          return $http[key].apply($http, arguments);
    // wrap convenience functions
      $delegate.get = function (url,config) {
        return wrapper(angular.extend(config || {}, {
          method: 'get',
          url: url

      $ = function (url,data,config) {
        return wrapper(angular.extend(config || {}, {
          method: 'post',
          url: url,

      $delegate.delete = function (url,config) {
        return wrapper(angular.extend(config || {}, {
          method: 'delete',
          url: url

      return wrapper;


Great post! Thank you.