cordova-android icon indicating copy to clipboard operation
cordova-android copied to clipboard

Failed to load assets image with Version > 10

Open EinfachHans opened this issue 4 years ago • 9 comments

Bug Report

Problem

I'm currently migrating my project to cordova-android@10. In my Project i'm using Googlemaps and Markers that icons are in my assets Folder. These are not working anymore and displays the default Google Map Marker.

Information

I see the following Error when i run my App via debugger:

E/AsyncLoadImage: can not connect to https://localhost/assets/imgs/map/mapPinGreen/mapPinGreen.png
    java.net.ConnectException: Failed to connect to localhost/127.0.0.1:443
        at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:147)
        at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
        at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
        at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
        at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:542)
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:106)
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:30)
        at plugin.google.maps.AsyncLoadImage.doInBackground(AsyncLoadImage.java:299)
        at plugin.google.maps.AsyncLoadImage.doInBackground(AsyncLoadImage.java:27)
        at android.os.AsyncTask$3.call(AsyncTask.java:394)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

Maybe the migration from the whitelist Plugin is not correctly working?

Environment, Platform, Device

Google Pixel 4, Android 10

Version information

Ionic:

   Ionic CLI                     : 6.16.3 (/usr/local/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.6.12
   @angular-devkit/build-angular : 12.1.4
   @angular-devkit/schematics    : 12.1.4
   @angular/cli                  : 12.1.4
   @ionic/angular-toolkit        : 4.0.0

Cordova:

   Cordova CLI       : 10.0.0
   Cordova Platforms : android 10.0.1
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 5.0.0, (and 50 other plugins)

Utility:

   cordova-res (update available: 0.15.3) : 0.15.1
   native-run (update available: 1.4.0)   : 1.0.0

System:

   Android SDK Tools : 25.2.3 (/Users/hanskrywalsky/Library/Android/sdk)
   ios-deploy        : 1.10.0
   ios-sim           : 8.0.2
   NodeJS            : v14.15.4 (/usr/local/bin/node)
   npm               : 7.17.0
   OS                : macOS Big Sur
   Xcode             : Xcode 12.5.1 Build version 12E507

Checklist

  • [X] I searched for existing GitHub issues
  • [X] I updated all Cordova tooling to most recent version
  • [X] I included all the necessary information above

EinfachHans avatar Aug 09 '21 07:08 EinfachHans

ooph...

I think this might be because native code is external from the webview, and localhost server doesn't actually exist to anything outside the webview (I think...). Not 100% sure, but a theory.

There are two workarounds you can try...

Remapping https:// paths to local file:// paths

Anything you tell google maps to load can probably be remapped from https://localhost/assets/imgs/map/mapPinGreen/mapPinGreen.png to file:///android_assets/imgs/map/mapPinGreen/mapPinGreen.png

Basically replace https://localhost/assets with file:///android_assets/

Not really sure if this will work, but it's worth a try.

Opting out of WebAssetLoader

You can tell cordova to opt out of using the WebAssetLoader system by enabling the AndroidInsecureFileModeEnabled preference, which will make it use file based paths just like cordova-android@9. I'm pretty sure this will work.

breautek avatar Sep 03 '21 21:09 breautek

Currently i'm giving the Google Maps Plugin a Url like ./assets/imgs/...someFile.png and i'm unsure about what is done then. To make iOS work and as i don't want to adjust all icons to android vs iOS the first option is not an option for me.

The second option, setting the AndroidInsecureFileModeEnabled Preference, seems to work, but does this will have any side effects?

Is this something that the Google Maps Plugin has to fix/migrate?

EinfachHans avatar Sep 06 '21 07:09 EinfachHans

Cordova Android 10.x by default will use scheme+hostname. And Cordova-iOS 6.x I believe will always use scheme+hostname.

The scheme can not match exactly because of limitations between each platform but the following example should work.

But needs to be tested as I do not use this plugin.

Setup:

Let’s say you have an image uploaded at this directory path.

<project-root>/www/assets/image.png

WebView Paths:

With Cordova iOS 6.x default settings, the path would be: app://localhost/assets/image.png.

With Cordova Android 10.x and default settings, the path would be: https://localhost/assets/image.png

Recommendation:

Would be recommended to pass in the absolute path, /assets/image.png.

You might also be able to use //localhost/assets/image.png. With this pattern is should automatically detect the scheme but the hostname setting must be identical.

Catches:

Now, not everyone can use the https protocol because they might load external third party resources or api requests to the http scheme and these can’t mix. At least https, a secure protocol can not call and insecure protocol. If you are faced with this issue, in case of Android, you can change the scheme to http.

Now for the AndroidInsecureFileModeEnabled setting… This preference is for people who want to revert to the file protocol which 9.x and earlier used. It’s not recommended to serve from the file protocol as there can be security concerns. But depending on how the app is written and if the third party scripts is coming from a trusted source, and you know everything that is executed, then maybe it’s less of a problem.

First try the above recommendation: Remove the . and make your path absolute, with default android and iOS settings for scheme+hostname, and see how that turns out.

erisu avatar Sep 06 '21 10:09 erisu

Passing the absoulte Path like /assets/image.png or like //localhost/assets/image.png both doesn't work:

W/System.err: java.io.FileNotFoundException: /assets/imgs/map/mapPinGreen/mapPinGreen.png: open failed: ENOENT (No such file or directory)
W/System.err: java.io.FileNotFoundException: /localhost/assets/imgs/map/mapPinGreen/mapPinGreen.png: open failed: ENOENT (No such file or directory)

EinfachHans avatar Sep 06 '21 11:09 EinfachHans

Sorry, I was mistaken about where the error was. I thought it was from the WebView side but, I see it was the native side of the plugin.

It will need to be the path that @breautek suggested.

file:///android_assets/imgs/map/mapPinGreen/mapPinGreen.png

But, this path will not work for iOS.

Try his other suggestion, to confirm that it will work: AndroidInsecureFileModeEnabled

Maybe the correct solution would involve a change/feature request to the plugin developers. Since you are passing the path to the plugin, and the plugin is trying to fetch the file with native code, maybe the plugin should accept various string values and determine the correct path.

E.g. Various String Values:

  • The new scheme+hostname value, which the native side will need to map to the native file path.
  • The exact native file path.
  • A partial path that of either:
    • native file path
    • scheme+hostname

Maybe, there could be something implemented on our platform's code to help translate the file paths to native paths, etc, but then it would include app developers updating the app code and wrap file paths. For some reason, I would feel that this isn't the best solution compared with the plugin change.

@breautek any thoughts?

erisu avatar Sep 06 '21 12:09 erisu

Yeah the AndroidInsecureFileModeEnabled Preference seems to work so far. I think at the end of the day the plugin needs to update this 🤔

EinfachHans avatar Sep 06 '21 13:09 EinfachHans

Thanks for confirming, i think my suspicions are accurate.

When using the web asset loader, the only thing that understands the https://localhost url is the webview itself. Anything external won't be able to use this url.

I think at the end of the day the plugin needs to update this

I think so too, but I'm not quite sure what the solution would be. Native could probably parse the url and transform it to a regular file:// url. I think the cordova plugin class could also provide this url transform implementation. I think this is what @erisu was hinting but wasn't quite recommending. Obviously the problem is plugins will need to be updated, but I'm not sure if there is a way around that.

Do you have a similar issue with iOS? I have one app that uses gmaps & custom markers, but it hasn't been updated. If necessarily I can find time to get the latest platforms installed to confirm

breautek avatar Sep 06 '21 15:09 breautek

iOS works fine with latest cordova-ios version

EinfachHans avatar Sep 06 '21 16:09 EinfachHans

@EinfachHans I've made a fix for myself. I've created PR https://github.com/mapsplugin/cordova-plugin-googlemaps/pull/2887 if you want to use it.

ebhsgit avatar Oct 23 '21 03:10 ebhsgit

@EinfachHans I've made a fix for myself. I've created PR mapsplugin/cordova-plugin-googlemaps#2887 if you want to use it.

This helps

and include to install this also

https://www.npmjs.com/package/cordova-plugin-file/v/8.0.1

nanaykubo avatar Dec 31 '23 05:12 nanaykubo

This is something the plugin needs to handle, not a cordova-android bug

jcesarmobile avatar Jan 28 '24 22:01 jcesarmobile