Reputation: 63
currently i am trying to build a Cordova App that should be using google maps so i can show routes and stuffs. For testing reason i also have the code on a server and everything is working perfectly there, the map is loading probably. But when i convert the project into an Cordova app, the google map wont load and i dont know why.
This is how my JS code in the index.html looks like:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>-----</title>
</head>
<!-- jQuery Version 1.11.0 -->
<script type="application/javascript" src="./js/jquery-1.11.0.js"></script>
<!-- Google Maps API -->
<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?key=AIzaSyCr0wsx4a5_o03hPTpC_CtRARjzCnOEGX4&sensor=false&libraries=places">
</script>
<!-- Style CSS -->
<link href="./css/style.css" rel="stylesheet">
<script>
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var isMobile = {
Android: function() {
return navigator.userAgent.match(/Android/i);
},
BlackBerry: function() {
return navigator.userAgent.match(/BlackBerry/i);
},
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
},
Opera: function() {
return navigator.userAgent.match(/Opera Mini/i);
},
Windows: function() {
return navigator.userAgent.match(/IEMobile/i);
},
any: function() {
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
}
};
if(isMobile.any()) {
(function (global) {
"use strict";
function onDeviceReady () {
document.addEventListener("online", onOnline, false);
document.addEventListener("resume", onResume, false);
loadMapsApi();
}
function onOnline () {
loadMapsApi();
}
function onResume () {
loadMapsApi();
}
function loadMapsApi () {
if(navigator.connection.type === Connection.NONE || google.maps) {
return;
}
$.getScript('http://maps.googleapis.com/maps/api/js?key=AIzaSyCr0wsx4a5_o03hPTpC_CtRARjzCnOEGX4&sensor=false&libraries=places');
}
global.onMapsApiLoaded = function () {
// Maps API loaded and ready to be used.
var map = new google.maps.Map(document.getElementById("map"), {});
};
document.addEventListener("deviceready", onDeviceReady, initialize);
})(window);
alert("");
}
function initialize() {
var styles = [{"featureType":"water","elementType":"all","stylers":[{"hue":"#76aee3"},{"saturation":38},{"lightness":-11},{"visibility":"on"}]},{"featureType":"road.highway","elementType":"all","stylers":[{"hue":"#8dc749"},{"saturation":-47},{"lightness":-17},{"visibility":"on"}]},{"featureType":"poi.park","elementType":"all","stylers":[{"hue":"#c6e3a4"},{"saturation":17},{"lightness":-2},{"visibility":"on"}]},{"featureType":"road.arterial","elementType":"all","stylers":[{"hue":"#cccccc"},{"saturation":-100},{"lightness":13},{"visibility":"on"}]},{"featureType":"administrative.land_parcel","elementType":"all","stylers":[{"hue":"#5f5855"},{"saturation":6},{"lightness":-31},{"visibility":"on"}]},{"featureType":"road.local","elementType":"all","stylers":[{"hue":"#ffffff"},{"saturation":-100},{"lightness":100},{"visibility":"simplified"}]},{"featureType":"water","elementType":"all","stylers":[]}];
var styledMap = new google.maps.StyledMapType(styles, {name: ""});
directionsDisplay = new google.maps.DirectionsRenderer({polylineOptions: {
strokeColor: "red"
}});
var mapOptions = {
center: new google.maps.LatLng(47.6826215,13.0984208,17),
zoom: 15,
disableDefaultUI: true,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'map_style']
}
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
map.mapTypes.set('map_style', styledMap);
map.setMapTypeId('map_style');
map.setOptions({styles: styles});
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(47.67052,13.114028),
new google.maps.LatLng(47.6910273,13.1153865));
var options = {
bounds: defaultBounds,
};
var start_input = document.getElementById('start');
start_autocomplete = new google.maps.places.Autocomplete(start_input, options);
var end_input = document.getElementById('end');
end_autocomplete = new google.maps.places.Autocomplete(end_input, options);
directionsDisplay.setMap(map);
}
function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
var request = {
origin:start,
destination:end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
Upvotes: 5
Views: 7060
Reputation: 4246
There might be several reasons why your posted example did not work:
Google Map's Load Event:
google.maps.event.addDomListener(window, 'load', initialize);
right away seems a good idea in web-apps but even if I used domlistener within deviceready it did not work. But this might be a better solution for cordova-apps to load google-library asynchronously:
function loadAsynchronousScript() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp' +'&signed_in=true&callback=initialize';
document.body.appendChild(script);
}
I tested that you can even call initialize alone within deviceready but it is a lot better to use loadAsynchronousScript for it does the domlistener's job for you so it knows when the library is ready(Param: &callback=). In the example above loadAsynchronousScript loads the standard-library but you can also replace it with your concrete keyed library.
Reference: https://developers.google.com/maps/documentation/javascript/examples/map-simple-async
Inserting Google-Maps multiply times Error:
In your example you check whether the library exists but I had even problems with that so in my example I omitted the script-tag within index.html:
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=...."></script>
But in my example there is no need for this tag anyway.
And I did not see the div-tag(id: 'map-canvas') on which you call a map. But may be I overlooked it. I also omitted calcRoute-function because you did not call it anywhere and it was no part of the original problem.
Unfortunately I changed some code-snippets of yours and it works in my android-emulator but I could not test this on IOS-Devices:
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
document.addEventListener("online", onOnline, false);
document.addEventListener("resume", onResume, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicity call 'app.receivedEvent(...);'
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
console.log('Received Event: ' + id);
if(isMobile.any()) {
if(googleLibExists()){
initialize();
}
else{
loadMapsApi();
}
}
}
};
var isMobile = {
Android: function() {
return navigator.userAgent.match(/Android/i);
},
BlackBerry: function() {
return navigator.userAgent.match(/BlackBerry/i);
},
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
},
Opera: function() {
return navigator.userAgent.match(/Opera Mini/i);
},
Windows: function() {
return navigator.userAgent.match(/IEMobile/i);
},
any: function() {
return isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows();
}
};
function googleLibExists(){
return typeof(google) != "undefined" && google.maps;
}
function loadAsynchronousScript() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://maps.googleapis.com/maps/api/js?key=AIzaSyCr0wsx4a5_o03hPTpC_CtRARjzCnOEGX4&sensor=false&libraries=places&callback=initialize';
document.body.appendChild(script);
}
function loadMapsApi () {
if(navigator.connection.type === Connection.NONE) {
alert('google maps library not loaded');
return;
}
if(!googleLibExists()){
loadAsynchronousScript();
}
}
function onOnline () {
loadMapsApi();
}
function onResume () {
loadMapsApi();
}
var directionsDisplay;
var map;
function initialize() {
console.log('map init');
var styles = [{"featureType":"water","elementType":"all","stylers":[{"hue":"#76aee3"},{"saturation":38},{"lightness":-11},{"visibility":"on"}]},{"featureType":"road.highway","elementType":"all","stylers":[{"hue":"#8dc749"},{"saturation":-47},{"lightness":-17},{"visibility":"on"}]},{"featureType":"poi.park","elementType":"all","stylers":[{"hue":"#c6e3a4"},{"saturation":17},{"lightness":-2},{"visibility":"on"}]},{"featureType":"road.arterial","elementType":"all","stylers":[{"hue":"#cccccc"},{"saturation":-100},{"lightness":13},{"visibility":"on"}]},{"featureType":"administrative.land_parcel","elementType":"all","stylers":[{"hue":"#5f5855"},{"saturation":6},{"lightness":-31},{"visibility":"on"}]},{"featureType":"road.local","elementType":"all","stylers":[{"hue":"#ffffff"},{"saturation":-100},{"lightness":100},{"visibility":"simplified"}]},{"featureType":"water","elementType":"all","stylers":[]}];
var styledMap = new google.maps.StyledMapType(styles, {name: ""});
directionsDisplay = new google.maps.DirectionsRenderer({polylineOptions: {
strokeColor: "red"
}});
var mapOptions = {
center: new google.maps.LatLng(47.6826215,13.0984208,17),
zoom: 15,
disableDefaultUI: true,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'map_style']
}
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
map.mapTypes.set('map_style', styledMap);
map.setMapTypeId('map_style');
map.setOptions({styles: styles});
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(47.67052,13.114028),
new google.maps.LatLng(47.6910273,13.1153865));
var options = {
bounds: defaultBounds,
};
var start_input = document.getElementById('start');
start_autocomplete = new google.maps.places.Autocomplete(start_input, options);
var end_input = document.getElementById('end');
end_autocomplete = new google.maps.places.Autocomplete(end_input, options);
directionsDisplay.setMap(map);
}
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<title>Hello World</title>
</head>
<body>
<h1>Map:</h1>
<div id="map-canvas" style="width:200px; height:200px"></div>
<script type="application/javascript" src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();
</script>
</body>
</html>
Evidence Image:
Upvotes: 3
Reputation: 2768
For these tasks, I would try a cordova plugin to have native sdk's integrated. Here is one for google maps:
You can also search for other plugins at:
Upvotes: 1