5

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>
locknies
  • 1,345
  • 3
  • 15
  • 36
FabianE
  • 63
  • 1
  • 10
  • Does the map look like a grey-rectangle? What can you see specifically? Can you take a snapshoot of your page on mobile. – Blauharley Feb 09 '15 at 12:43
  • It is just a white rectangle where the map shdould be. I asume the code isnt loading anything for some reason. Here is a screenshot of it: http://imgur.com/gOmU1Bf – FabianE Feb 09 '15 at 13:38

2 Answers2

3

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:

enter image description here

Blauharley
  • 4,186
  • 6
  • 28
  • 47
  • Hello first off all i want to thank you for this long and well documented answere, I really appreciate it! But sadly after implementing your methodes and copying them into my original .html it still wont load the map and i really dont know why. All i did is copying the code you gave me and implemting it where i think i needed it. Is there something else i need like the cordova.js? And where can i get it from? – FabianE Feb 11 '15 at 09:53
  • I uploaded my code as answere to the question. I know i am asking for mutch, but would you mind checking it out and looking where my problem is? – FabianE Feb 11 '15 at 10:05
  • When you try to build android-cordova project with help of cordova-commands and running it via eclipse then it should work right away. Please try it first this way. – Blauharley Feb 11 '15 at 10:20
  • The cordova.js file is put into index.html automatically, you should not be bothered to take care of it. – Blauharley Feb 11 '15 at 10:28
  • The problem is i dont use Eclipse to programm. I am using Notpad++ and when iwant to test the code i upload it directly on my phone. But i will download it now and test it on there. – FabianE Feb 11 '15 at 17:28
  • Hello it is me once again :x i just tried to run the code above exactly how you posted it and i didnt change anything and it still wont load the map. do you have any ideas what could be wrong? – FabianE Feb 15 '15 at 12:11
  • Can you post some panel-printings(console-logs)? It's hard to tell without them. – Blauharley Feb 15 '15 at 12:17
  • I will try to get this running. Which Eclipse are you using so we have the same conditions? What i downloaded last time is Eclipse for webdevelopers and for php is one of these two useable? – FabianE Feb 15 '15 at 12:21
  • The following article describes step by step of how to setup a cordova project. I use Eclipse-Juno but there are different kinds of eclipse you can use. http://codingsquare.blogspot.co.at/2013/08/creating-cordova-3-android-project.html – Blauharley Feb 15 '15 at 12:31
  • Thanks for the articel, but i already set this up! Do you use the Classic version of Eclipse juno or should i use the one for EE-Developers or the one for mobile developers? – FabianE Feb 15 '15 at 13:07
  • There is no right or wrong about what eclipse version should be used. It should support ADT, which acually means that you should be able to build andoirs/cordova app-ui with it. Just download eclipse from an trustful android/cordova site and do not worry because eclipse is never installed on your system that means you can easily remove it when you do not need it anymore. This looks promising to me: http://developer.android.com/sdk/index.html – Blauharley Feb 15 '15 at 13:26
  • Okey lukily it apeared that one of the Eclipses i have downloaded previously is support ADT. I oped the .html file and it loads the page(without the map ofc), but the console isnt saying anything about the page. All i am getting are errors from a previouse projekt. Here is a screenshot of how it all looks: http://i.imgur.com/OKmjwCx.png – FabianE Feb 15 '15 at 13:40
  • Try to run the project with an emulator or device. Just calling index.html is no use, When you run your project as android-application you should get a popup-window with a list of all devices virtually or physically. When you do not have got one real device create a virtual one ;) – Blauharley Feb 15 '15 at 16:29
  • I've uploaded an evidence. I forgot to mention that you need this plugin as well to check for internet connectivity: https://github.com/apache/cordova-plugin-network-information/blob/master/doc/de/index.md – Blauharley Feb 15 '15 at 16:43
  • okey i just added the plugin as well, but the map still wont load and the console doesnt write out anything. Although Logcat is giving me an error that says "unable to find stats for iface rmnt0" – FabianE Feb 15 '15 at 17:30
  • Sorry but this exents by far your original problem. It seems there is something wrong with network-plugin: http://stackoverflow.com/questions/13524514/throttleservice79-unable-reading-network-stats Do not get me wrong but now I've got to put an end to this. – Blauharley Feb 15 '15 at 17:41
  • Yeah ofc i can totally understand. Thanks for your help i really really apreciate the time you spent for me! – FabianE Feb 15 '15 at 17:45
  • You are welcome....last advice: making some plugins working locally is sometimes pretty tricky and annoying, so you can omit it because it is not needed for maps to be shown but then you have to comment relevant code out. – Blauharley Feb 15 '15 at 17:54
1

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:

http://plugreg.com/

mentat
  • 2,748
  • 1
  • 21
  • 40
  • So i would just use this .js plugin instead of my link? – FabianE Feb 09 '15 at 13:26
  • plugin is well documented and pretty powerful, I would check it for real native map support. – mentat Feb 10 '15 at 13:37
  • Okey thanks, but i still have some remaining questions left. Do you know if there is an more updated version of this? Because I am using Google Maps api v3 and it also says when i try to run the command in my cmd that the apk file is invalide. – FabianE Feb 11 '15 at 10:00
  • 1
    the plugin does not work with the latest Cordova Android (4.0) unfortunately – Paranoid Android May 08 '15 at 12:35