Ionicons: IONIC v4: Icon won't work in android

Created on 26 Jun 2018  路  22Comments  路  Source: ionic-team/ionicons

Ionicons won't work with ionic v4 on android as stated in this issue:
ionic-team/ionic#14509

Most helpful comment

Hi guy, for devices with Android versions bellow 6.0, where the Crosswalk Webview is needed, I'm using this work around:

<script type="text/javascript">
    var originalFetch = window.fetch;

    window.fetch = function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var url = args[0];
        if (typeof url === 'string' && url.match(/\.svg/)) {
            return new Promise(function (resolve, reject) {
                var req = new XMLHttpRequest();
                req.open('GET', url, true);
                req.addEventListener('load', function () {
                    resolve({ ok: true, status: 200, text: function () { return Promise.resolve(req.responseText); } });
                });
                req.addEventListener('error', reject);
                req.send();
            });
        }
        else {
            return originalFetch.apply(void 0, args);
        }
    };
</script>

It works perfectly fine, I'm using @ionic/[email protected] and @angular/[email protected]

All 22 comments

Hi @manucorporat, did you guys test these icons on a real device? They won't work in android or ios, only in the browser(tested with ionic 4).

this problem occur because of: #552

Fetch API cannot load file:///android_asset/www/svg/md-add-circle.svg. URL scheme "file" is not supported.

Hi guys, same issue here, but I developed a small workaround to make it work, while it is been fixed

function androidFetchWorkaround() {
  const originalFetch = (window as any).fetch;

  (window as any).fetch = (...args) => {
    const [url] = args;

    if (typeof url === 'string' && url.match(/\.svg/)) {
      return new Promise((resolve, reject) => {
        const req = new XMLHttpRequest();
        req.open('GET', url, true);
        req.addEventListener('load', () => {
          resolve({ ok: true, text: () => Promise.resolve(req.responseText) });
        });
        req.addEventListener('error', reject);
        req.send();
      });
    } else {
      return originalFetch(...args);
    }
  };
}

document.addEventListener('deviceready', () => {
  androidFetchWorkaround();
  bootstrapMyApp();
}, false);

Where did you put this @evertonrobertoauler ?

You'll need to run this androidFetchWorkaround(); function before the ion-icon custom element is loaded, if you are using Typescript, you could put this code at the start of your application main file, like this:

function androidFetchWorkaround() {
  const originalFetch = (window as any).fetch;

  (window as any).fetch = (...args) => {
    const [url] = args;

    if (typeof url === 'string' && url.match(/\.svg/)) {
      return new Promise((resolve, reject) => {
        const req = new XMLHttpRequest();
        req.open('GET', url, true);
        req.addEventListener('load', () => {
          resolve({ ok: true, text: () => Promise.resolve(req.responseText) });
        });
        req.addEventListener('error', reject);
        req.send();
      });
    } else {
      return originalFetch(...args);
    }
  };
}

androidFetchWorkaround();

If your are using babel, just replace the (window as any).fetch with just window.fetch

Same problem here on iOS as well. The above workaround does not work.

Same problem here with Crosswalk.

I tried to use it with crosswalk, to support android versions bellow the SDK 23, I thought it could be a SVG problem, but SVGs work just fine, be the icon is not showing and there is no error on the console.

Same here. The suggested patch from @evertonrobertoauler worked for me but when will this fixed? I updated dependencies to all latest as suggested in other issues ( cordova-plugin-ionic-webview 2.2.0 / cordova-android 7.1.1 and @ionic/angular 4.0.15 beta) without luck.

same here!
any solutions for this issue!

Hi guy, for devices with Android versions bellow 6.0, where the Crosswalk Webview is needed, I'm using this work around:

<script type="text/javascript">
    var originalFetch = window.fetch;

    window.fetch = function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var url = args[0];
        if (typeof url === 'string' && url.match(/\.svg/)) {
            return new Promise(function (resolve, reject) {
                var req = new XMLHttpRequest();
                req.open('GET', url, true);
                req.addEventListener('load', function () {
                    resolve({ ok: true, status: 200, text: function () { return Promise.resolve(req.responseText); } });
                });
                req.addEventListener('error', reject);
                req.send();
            });
        }
        else {
            return originalFetch.apply(void 0, args);
        }
    };
</script>

It works perfectly fine, I'm using @ionic/[email protected] and @angular/[email protected]

璋㈣阿

FYI: latest release has slightly different fetch API usage (https://github.com/ionic-team/ionicons/commit/685c09df15ea63fe422ed14c44a3479de690a6f7).

Placing following TS code in polyfill.ts seems to work:

const originalFetch = (window as any).fetch;
const xhrToResponse = xhr => {
  const headers = new Headers();
  xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(line => {
    const [name, value] = line.split(': ', 2);
    headers.append(name, value)
  });
  return new Response(xhr.responseText, {
    status: xhr.status,
    statusText: xhr.statusText,
    headers,
  });
};
(window as any).fetch = function (...args) {
  const [url] = args;
  if (typeof url === 'string' && url.match(/\.svg$/)) {
    return new Promise((resolve, reject) => {
      const req = new XMLHttpRequest();
      req.open('GET', url, true);
      req.addEventListener('load', () => {
        resolve(xhrToResponse(req));
      });
      req.addEventListener('error', reject);
      req.send();
    });
  } else {
    return originalFetch.apply(window, args);
  }
};

Hi @ippeiukai,

I implemented your code and I got it working for the icons (thanks a lot).

Nevertheless, because I am using CrossWalk, I had to change the base href in index.html to make it work with ionic, the rest of the fetchs (like JSON files for trads), are not being picked up. Do you have any idea on how to change, either the fetch globally, or the needed href base?

I am getting this (for all files and images, except .svgs now):
file:///assets/i18n/en.json Failed to load resource: net::ERR_FILE_NOT_FOUND

The ideal setup would be to keep the index.html with the default instead of , so that I can also test in the browser when doing the development (and not in the device). If that is not possible, just a work-around for the rest of the files would be much appreciated.

Thanks!

(Worth mentioning, that the en.json is loaded automatically, as you might know, thanks to the TranslateService), so I can not really change any url, myself.

Hi, @martinlombana whats did you do in index.html? I copied the code in polyfill.ts and its looks like not running. Thanks a lot

Set:

<base href="."/>

Worth mentioning that I am using CrossWalk with cordova.

I resolved the above issue, as well, with this, and setting all my relative paths, including the ones for the trads to ./assets/whatever/file.json instead of /assets/whatever/file.json
(With cordova + crosswalk, otherwise, it does not work, simply because the project files are located in another folder when compiling with crosswalk).

Keep happening in the latest release of ionic/angular, i tried update cordova-android to 8.0.0, plugin-cordova-plugin-ionic-webview to 4.0.1, tried to change the to "./" and "/" but nothing works yet

"dependencies": { "@angular/common": "^7.2.2", "@angular/core": "^7.2.2", "@angular/forms": "^7.2.2", "@angular/http": "^7.2.2", "@angular/platform-browser": "^7.2.2", "@angular/platform-browser-dynamic": "^7.2.2", "@angular/router": "^7.2.2", "@ionic-native/core": "^5.0.0", "@ionic-native/geolocation": "^5.0.0", "@ionic-native/ionic-webview": "^5.6.0", "@ionic-native/network": "^5.0.0", "@ionic-native/splash-screen": "^5.0.0", "@ionic-native/status-bar": "^5.0.0", "@ionic-native/unique-device-id": "^5.0.0", "@ionic/angular": "^4.4.2", "@ngx-translate/core": "^11.0.1", "@ngx-translate/http-loader": "^4.0.0", "android-versions": "^1.4.0", "cordova-android": "^8.0.0", "cordova-plugin-device": "^2.0.2", "cordova-plugin-geolocation": "^4.0.1", "cordova-plugin-ionic-keyboard": "^2.1.3", "cordova-plugin-ionic-webview": "^4.0.1", "cordova-plugin-network-information": "^2.0.1", "cordova-plugin-splashscreen": "^5.0.2", "cordova-plugin-statusbar": "^2.4.2", "cordova-plugin-uniquedeviceid": "^1.3.2", "cordova-plugin-whitelist": "^1.3.3", "core-js": "^2.5.4", "moment": "^2.24.0", "pushy-cordova": "^1.0.25", "pushy-cordova-receiver": "^1.0.0", "rxjs": "~6.3.3", "xcode": "^2.0.0", "zone.js": "~0.8.29" }, "devDependencies": { "@angular-devkit/architect": "~0.12.3", "@angular-devkit/build-angular": "~0.12.3", "@angular-devkit/core": "~7.2.3", "@angular-devkit/schematics": "~7.2.3", "@angular/cli": "~7.2.3", "@angular/compiler": "~7.2.2", "@angular/compiler-cli": "~7.2.2", "@angular/language-service": "~7.2.2", "@ionic/angular-toolkit": "~1.3.0", "@types/node": "~10.12.0", "@types/jasmine": "~2.8.8", "@types/jasminewd2": "~2.0.3", "codelyzer": "~4.5.0", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~3.1.4", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~2.0.1", "karma-jasmine": "~1.1.2", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.4.0", "ts-node": "~8.0.0", "tslint": "~5.12.0", "typescript": "~3.1.6" }, "description": "An Ionic project", "cordova": { "plugins": { "cordova-plugin-uniquedeviceid": {}, "cordova-plugin-network-information": {}, "pushy-cordova": {}, "pushy-cordova-receiver": {}, "cordova-plugin-geolocation": {}, "cordova-plugin-whitelist": {}, "cordova-plugin-statusbar": {}, "cordova-plugin-device": {}, "cordova-plugin-splashscreen": {}, "cordova-plugin-ionic-webview": { "ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+" }, "cordova-plugin-ionic-keyboard": {} }, "platforms": [ "android" ] } }

same problem here with a similar standard configuration

import {fetch as fetchPolyfill} from 'whatwg-fetch';
window.fetch = fetchPolyfill;

this works for me

@icedman In which file we need to place this code snippet ?

@icedman The above solution working fine. Thanks a lot. I followed the below procedure.

  • Install whatwg-fetch npm
  • I just assumed and placed the above code in appcomponent.ts. It works like a charm.

I know guys this issue is about Android, but I think I might have hit a similar situation in browser applications when target is set to es5. In localhost testing with the built in Angular server the application loads all the icons and I see it is using the fetch API to load icon. However, our build target is es5 to support IE11 and the icons do not load at all. Of course the application uses nginx as reverse proxy so I immediately suspected nginx being the culprit. However, I realized the browsers are not at all making any request for the icons no 404 in network tab. So I suspected the fetch API is not working at all when target is es5. Can someone confirm.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cmtonkinson picture cmtonkinson  路  6Comments

tgangso picture tgangso  路  10Comments

anthowm picture anthowm  路  11Comments

muuvmuuv picture muuvmuuv  路  24Comments

adamdbradley picture adamdbradley  路  32Comments