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 https://api.github.com/repos/pliablepixels/zmNinja/releases/latest as well as https://medium.com/zmninja/latest?format=json - 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) https://www.exratione.com/2013/08/angularjs-wrapping-http-for-fun-and-profit/
    // b) https://gist.github.com/adamreisnz/354364e2a58786e2be71

    $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
          };

           cordova.plugin.http.sendRequest(encodeURI(url),options,
            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
                d.resolve({"data":succ.data});
                return d.promise;
              }
              else {
                try {
                  d.resolve({"data":JSON.parse(succ.data)});
                  return d.promise;
                }
                catch (e) {
                  d.resolve({"data":succ.data});
                  return d.promise;
                }

              }
            }, 
            function (err) {
              console.log ("***  Inside native HTTP error");
              d.reject(err);
              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
        }));
      };

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

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

      return wrapper;
    }]);

3 Likes

Great post! Thank you.

Hi there,

First of all thank you for your thoughts and the snippet. I just have this problem because itunes dont accept anymore the old WebView and I need to adapt a old Ionic V1 App to work with WKWebView.

How ever I have not really an idea about this changes and I am not sure how to use/work with your snippet in my project. I would be happy if you can help me understand a little bit more what I need to change in my old Ionic App to make this work? How I use this snippet exactly, what else I might need to change?

thank you in advance