Leaflet map not working in emulator, does work in browser

Hello,

I am using the Ionic framework for about one day and I absolutely love it already. I started building an App that uses the leaflet framework for it’s maps; but I’ve hit a problem.

The leaflet map is working in the browser (ionic serve) on iOS, Android and OSX; but when I build the app and run it as a native app on iOS it doesn’t work anymore. The map simply becomes gray. I have a screenshot here:

The view

<ion-tab title="Tab 3" icon-on="ion-ios7-location" icon-off="ion-ios7-location-outline">
        <ion-content has-header="true" scroll="false" data-tap-disabled="true">
            <leaflet center="center" class="superfill"></leaflet>
        </ion-content>
</ion-tab>

The controller

angular.extend($scope, {
center: {
	lat: 52.35,
	lng: 4.91,
	zoom: 12
 },
legend: {
	position: 'bottomleft',
	colors: [ '#ff0000', '#28c9ff', '#0000ff', '#ecf386' ],
	labels: [ 'National Cycle Route', 'Regional Cycle Route', 'Local Cycle Network', 'Cycleway' ]
},
defaults: {
	tileLayer: "http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png",
	scrollWheelZoom: false
}
});

It got even more strange now, since the markers are being added at the right location; and you can zoom in and out, which means that all the logic is working. Only the tiles seem to cause problems.

I’m having the same issue using Android. I’ll continue investigating and post here. Let us know if you’ve had any luck.

@Woutwo @andygimma Did you manage to find out what was wrong? Running into the same issue here…

When using the inspector I’m noticing the tiles are using the following markup:

<img class="leaflet-tile leaflet-tile-loaded" src="//c.tile.openstreetmap.org/12/2103/1346.png" style="height: 256px; width: 256px; left: -61px; top: -102px;">

Notice the protocol isn’t defined in src tag. The browser assumes http://, but within the iOS simulator at least file:// is assumed. Anybody else has this problem? And found a fix?

I am having the same issue where what should be http is being changed to file when you run locally.

Hi all,

I just want to say that I have solved the problem and I will try to explain what I did here. First, I changed the view to this:

<leaflet id="map_wandeling" class="superfill" tiles="tiles" ng-init="doMapInit()"></leaflet>

(Especially the ng-init is important here)

Then I changed the controller to have a function called doMapInit, with the following content:

$scope.doMapInit = function() {

	angular.extend($scope, {
		tiles: {
			url: 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png'
		},
		defaults: {
			scrollWheelZoom: false
		}
	});

	leafletData.getMap('map_wandeling').then(function(map) {
		$scope.map = map;
	});
};

I hope this helps, it did work for me! Note that you need the Angular-Leaflet-plugin for this :wink:
I think because I now use a specific “url = http://…”, leaflet knows that I am talking about external links and thus doesn’t change them to file://

Well, your solution didn’t work for me, but based on your solution i think i found the way to deal with it.
Here is how i initiate my map inside the controller based on leaflet docs.

angular.extend($scope, {
    tiles: {
            url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
          },
          osloCent

er: {
        lat: 32.07883,
        lng: 34.773259,
        zoom: 12
      },
      markers: {
        osloMarker: {
          lat: 32.07883,
          lng: 34.773259,
          message: "I want to travel here!",
          focus: true,
          draggable: false
        }
      },
      defaults: {
        scrollWheelZoom: false
      }
    });

And here is how i use the directive inside my html file

<leaflet markers="markers" center="osloCenter" tiles="tiles" ></leaflet>

I think the solution was not actually found here, but a hack was created. “Whatever works” is sometimes okay, but when you don’t understand why something doesn’t work it can give you headaches later.

From what I’ve found, the problem of why the tiles show in a browser but not when deployed to a device is caused by the Content-Security-Policy (CSP) of the WebView used in the native applications. A plugin has been developed to address this, but I have not yet figured out how to configure it 100%.

https://cordova.apache.org/docs/en/4.0.0/guide_appdev_whitelist_index.md.html

When I simply install the plugin

ionic plugin add cordova-plugin-whitelist

it seems to work both in the browser and on my Samsung Galaxy S4 (Android 5.0). The hack described above probably works because it meets the default CSP requirements. Looking at the documentation for the plugin it is simple to add specific domains that should be trusted (the tile service), but it is not very easy to figure out what (sub)domains to include.

If you install the plugin, without adding anything, it seems to run… for some reason, but you will get a bunch of warning in your console saying “No Content-Security-Policy meta tag found. Please add one when using the cordova-plugin-whitelist plugin.” With these services like Google maps or Leaflet, it isn’t straightforward figuring out what domains to include, because they seem to call several different sub-domains. I still have yet to try out wild-cards to make it work how it is supposed to.

After installing white-list-plugin, you have to add CSP (Content-Security-Policy) to your index.html , something like this:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com *.ionic.io *.openstreetmap.org; style-src 'self' 'unsafe-inline'; media-src *; img-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval'">

obs:
data: gap: https://ssl.gstatic.com -> white-list-plugin recommendation. ref: https://github.com/apache/cordova-plugin-whitelist#content-security-policy

*.ionic.io -> allow access to ionic services

*.openstreetmap.org -> allow access to openstreetmap (of course :stuck_out_tongue:)

For test purpose (all access allowed, bad to use as production mode):
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src * 'unsafe-inline'; media-src *; img-src *; script-src * 'unsafe-inline' 'unsafe-eval'">

Don’t forget to add permission to your config.xml:

<access origin="*.ionic.io"/>
<access origin="*.openstreetmap.org"/>

What release of angular-leaflet-directive are you using?

testing again 0.8.2 didnt work.

Returning to 0.7.7. Everything works so far

Sorry @vpease for my delay in answering you. I don’t which version I was using at that time, but now I’m using angular-leaflet-directive#0.8.3 .

I am having the same problem as well but none of the above solved the problem for me…
Are there any workarounds?

I don’t manage to make leaflet work on device with Content Security Policy but it works on browser. Have you found a CSP that works on device ?

HI dionesandrade, i tried every step. When i run ionic app in device, it give error data: gap: https://ssl.gstatic.com in Chrome inspect console.
Kindly help me out, i am stuck in this for 2 days
Regards

it happened to me these 2 days, so it was a stupid bug , that the cold didn’t load the map function , please double check ,debugging use some alert to find out that your map is already loaded
and second thing is , if you set load map function in side the other promise function , like get location , so be careful about that