web-dev-qa-db-fra.com

navigator.geolocation.getCurrentPosition fonctionne parfois parfois ne fonctionne pas

J'ai donc un morceau assez simple de JS en utilisant le jammy navigator.geolocation.getCurrentPosition.

$(document).ready(function(){
  $("#business-locate, #people-locate").click(function() {
    navigator.geolocation.getCurrentPosition(foundLocation, noLocation);
  });

  navigator.geolocation.getCurrentPosition(foundLocation, noLocation);

  function foundLocation(position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var userLocation = lat + ', ' + lon;
    $("#business-current-location, #people-current-location").remove();
    $("#Near-Me")
      .watermark("Current Location")
      .after("<input type='hidden' name='business-current-location' id='business-current-location' value='"+userLocation+"' />");
    $("#people-Near-Me")
      .watermark("Current Location")
      .after("<input type='hidden' name='people-current-location' id='people-current-location' value='"+userLocation+"' />");
  }
  function noLocation() {
    $("#Near-Me").watermark("Could not find location");
    $("#people-Near-Me").watermark("Could not find location");
  }
})//end DocReady

Ce qui se passe ici, c’est que nous obtenons la position actuelle. Si elle est obtenue, deux "filigranes" sont placés dans deux champs indiquant "Position actuelle" et deux champs masqués sont créés avec les données lat-long comme valeur (elles sont supprimées). au début afin qu’ils ne soient pas dupliqués à chaque fois). Il y a aussi deux boutons qui ont une fonction de clic qui fait la même chose. Malheureusement, à peu près toutes les trois fois, cela fonctionne. Quel est le problème ici ???

202
theassociatedweb

J'ai eu exactement le même problème et je n'ai trouvé presque aucune information en ligne à ce sujet. Rien du tout dans les livres. Enfin, j'ai trouvé cette requête sobre sur stackoverflow et (ha!) C'était l'impulsion finale dont j'avais besoin pour créer un compte ici.

Et j'ai une réponse partielle, mais hélas pas complète.

Tout d'abord, sachez que le délai d'attente par défaut pour getCurrentPosition est infini (!). Cela signifie que votre gestionnaire d'erreurs ne jamais être appelé si getCurrentPosition se bloque quelque part sur le back-end.

Pour garantir l'expiration du délai, ajoutez le troisième paramètre facultatif à votre appel à getCurrentPosition. Par exemple, si vous souhaitez que l'utilisateur n'attende pas plus de 10 secondes avant de lui donner un indice de ce qui se passe, utilisez:

navigator.geolocation.getCurrentPosition(successCallback,errorCallback,{timeout:10000});

Deuxièmement, ma fiabilité a été très différente dans différents contextes. Ici à la maison, je reçois un rappel en une seconde ou deux, bien que la précision soit médiocre.

Au travail, cependant, j'éprouve des variations de comportement assez bizarres: la géolocalisation fonctionne tout le temps sur certains ordinateurs (sauf IE, bien sûr), d'autres ne fonctionnent que dans chrome et safari mais pas firefox (problème de gecko?), d'autres travaillent une fois, puis échouent par la suite - et le schéma change d'heure en heure, de jour en jour. Parfois, vous avez un ordinateur "chanceux", parfois non. Peut-être que tuer des chèvres à la pleine lune pourrait aider?

Je n'ai pas été capable de comprendre cela, mais je soupçonne que l'infrastructure principale est plus inégale que celle annoncée dans les différents livres et sites Web Gung-ho qui proposent cette fonctionnalité. Je souhaite vraiment qu'ils soient un peu plus clairs sur la complexité de cette fonctionnalité, et quelle est l'importance de ce paramètre de délai d'attente, si vous voulez que votre gestionnaire d'erreurs fonctionne correctement.

J’essaie d’enseigner ce genre de choses aux étudiants aujourd’hui et j’ai eu la situation embarrassante où mon propre ordinateur (sur le projecteur et plusieurs écrans grand format) échouait en silence, alors qu’environ 80% des étudiants obtenaient un résultat presque instantanément (avec exactement le même réseau sans fil). Il est très difficile de résoudre ces problèmes lorsque mes étudiants créent également des fautes de frappe et d’autres gaffes, et que mon propre ordinateur est également en panne.

Quoi qu'il en soit, j'espère que cela aidera certains d'entre vous. Merci pour la vérification de la santé mentale!

324
brennanyoung

C’est ainsi que je décris ce problème, du moins cela fonctionne dans tous les navigateurs actuels (sous Windows, je ne possède pas de Mac):

if (navigator.geolocation) {
    var location_timeout = setTimeout("geolocFail()", 10000);

    navigator.geolocation.getCurrentPosition(function(position) {
        clearTimeout(location_timeout);

        var lat = position.coords.latitude;
        var lng = position.coords.longitude;

        geocodeLatLng(lat, lng);
    }, function(error) {
        clearTimeout(location_timeout);
        geolocFail();
    });
} else {
    // Fallback for no geolocation
    geolocFail();
}

Cela fonctionnera également si quelqu'un clique sur la fermeture, choisit non ou choisit l'option Ne jamais partager sur Firefox.

Clunky, mais ça marche.

65
going

Cela fonctionne pour moi à chaque fois:

navigator.geolocation.getCurrentPosition(getCoor, errorCoor, {maximumAge:60000, timeout:5000, enableHighAccuracy:true});

Bien que ce ne soit pas très précis. La chose amusante est que sur le même appareil, si je lance ceci, cela me met environ 100 mètres (à chaque fois), mais si je vais sur les cartes de Google, il trouvera exactement ma position. Donc, bien que je pense que enableHighAccuracy: true l’aide à fonctionner de manière cohérente, elle ne semble pas la rendre plus précise ...

37
K'shin Gendron

Même chose ici, ça marche parfaitement dans Chrome (stable, dev et canari) mais pas dans FF et Safari. Cela fonctionne également parfaitement sur mon iPhone et mon iPad (Safari!). Cela peut être dû à la nouveauté relative de cette fonctionnalité (c’est-à-dire qu’il s’agit d’un bogue). Je passe presque une semaine là-dessus et je n'arrive pas à le faire fonctionner avec ces navigateurs.

Voici ce que j'ai trouvé:

La première fois que vous appelez getCurrentPosition, cela fonctionne parfaitement. Aucun appel suivant ne retourne jamais, c’est-à-dire qu’il ne déclenche pas les fonctions successCallback ou errorCallback. J'ai ajouté quelques options de position à mon appel pour prouver mon point:

 navigator.geolocation.getCurrentPosition(successCallback, errorCallback,  {timeout: 10000});

et il expire à chaque fois (après le premier appel réussi). Je pensais pouvoir résoudre le problème avec maximumAge, mais cela ne semble pas fonctionner, car cela est supposé fonctionner:

navigator.geolocation.getCurrentPosition(successCallback, errorCallback,  {maximumAge:60000, timeout: 2000});

cela devrait empêcher d’appeler réellement la fonction getCurrentPosition si vous l’appelez dans les 60 secondes, mais il l’ignore (cependant, cela pourrait être dû au fait que j’actualise ma page pour déclencher le deuxième appel, sans savoir si cela est persistant entre les appels)

btw, même exemples de Google échouent sur ces navigateurs, ce qui me laisse supposer qu'il s'agit bien de bogues de navigateur. Essayez-le, chargez-le deux fois dans Safari et cela ne fonctionnera pas la deuxième fois.

Si quelqu'un trouve une solution pour cela, faites-le moi savoir :-)

À votre santé.

13
mvilrokx

C'est déjà une vieille question, mais toutes les réponses n'ont pas résolu mon problème, ajoutons donc celle que j'ai finalement trouvée. Ça sent le hack (et c’est le cas), mais ça marche toujours dans ma situation. J'espère aussi dans votre situation.

//Dummy one, which will result in a working next statement.
navigator.geolocation.getCurrentPosition(function () {}, function () {}, {});
//The working next statement.
navigator.geolocation.getCurrentPosition(function (position) {
    //Your code here
}, function (e) {
    //Your error handling here
}, {
    enableHighAccuracy: true
});
12
Niels Steenbeek

Vous ne recevez pas de message d'erreur car il n'a pas de délai d'attente par défaut (au moins, je pense). J'ai eu le même problème avec Firefox, mais pour moi, Firefox donne toujours un délai d'attente. Vous pouvez définir un délai d'attente comme celui-ci.

J'ai réglé l'âge maximum sur Infinity pour m'assurer que ce n'est pas un problème. Ma fonction fonctionne très bien dans chrome mais je reçois un dépassement de temps à chaque fois dans Firefox.

    navigator.geolocation.getCurrentPosition(
        function(position) {
            //do succes handling
        },
        function errorCallback(error) {
            //do error handling
        },
        {
            maximumAge:Infinity,
            timeout:5000
        }
    );

Je recommande de surveiller vos erreurs avec soin. Être attendu pour tout. Avoir un plan de sauvegarde pour tout. J'utilise moi-même des valeurs par défaut ou des valeurs de ma base de données au cas où les géolocalisations de Google et du navigateur échouent.

6
Mark Baijens

voici ma solution grâce à une fermeture:

  function geoloc(success, fail){
    var is_echo = false;
    if(navigator && navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        function(pos) {
          if (is_echo){ return; }
          is_echo = true;
          success(pos.coords.latitude,pos.coords.longitude);
        }, 
        function() {
          if (is_echo){ return; }
          is_echo = true;
          fail();
        }
      );
    } else {
      fail();
    }
  }

  function success(lat, lng){
    alert(lat + " , " + lng);
  }
  function fail(){
    alert("failed");
  }

  geoloc(success, fail);
5
jbdemonte

J'obtiens toujours des résultats inégaux en 2017 et ma théorie est la suivante: la documentation de l'API indique que l'appel est désormais disponible uniquement "dans un contexte sécurisé", c'est-à-dire via HTTPS. Je ne parviens pas à obtenir un résultat dans mon environnement de développement (http sur localhost) et je crois que c'est pourquoi.

5
Coderer

Donc, je courais dans la même chose. J'ai essayé la solution de délai d'attente qui a fonctionné mais pas de manière fiable. J'ai trouvé que si vous appelez juste deux fois l'emplacement est rafraîchi correctement

function getLocation(callback)
{   
    if(navigator.geolocation)
    {
        navigator.geolocation.getCurrentPosition(function(position)
        {
            navigator.geolocation.getCurrentPosition(callback, function(){},{maximumAge:0, timeout:10000});
        },function(){}, {maximumAge:0, timeout:10000});
    }
    return true;
}

bien sûr, c'est un peu plus lent, mais je ne l'ai pas eu une fois pour me donner la mauvaise position. Je l'ai eu frappé le délai d'attente à quelques reprises et ne retourne rien mais autre que cela fonctionne très bien. Je sais que c'est encore un peu hacky et j'ai hâte que quelqu'un trouve la vraie solution.

Ou, si vous voulez être sûr qu'il va continuer à essayer jusqu'à ce que vous vouliez abandonner, vous pouvez essayer quelque chose comme ça.

//example
$(document).ready(function(){
    getLocation(function(position){
        //do something cool with position
        console.log(position);
    });
});


var GPSTimeout = 10; //init global var NOTE: I noticed that 10 gives me the quickest result but play around with this number to your own liking


//function to be called where you want the location with the callback(position)
function getLocation(callback)
{   
    if(navigator.geolocation)
    {
        var clickedTime = (new Date()).getTime(); //get the current time
        GPSTimeout = 10; //reset the timeout just in case you call it more then once
        ensurePosition(callback, clickedTime); //call recursive function to get position
    }
    return true;
}

//recursive position function
function ensurePosition(callback, timestamp)
{
    if(GPSTimeout < 6000)//set at what point you want to just give up
    {
        //call the geolocation function
        navigator.geolocation.getCurrentPosition(
            function(position) //on success
        {
                //if the timestamp that is returned minus the time that was set when called is greater then 0 the position is up to date
            if(position.timestamp - timestamp >= 0)
                {
                    GPSTimeout = 10; //reset timeout just in case
                    callback(position); //call the callback function you created
                }
                else //the gps that was returned is not current and needs to be refreshed
                {
                    GPSTimeout += GPSTimeout; //increase the timeout by itself n*2
                    ensurePosition(callback, timestamp); //call itself to refresh
                }
            },
            function() //error: gps failed so we will try again
            {
                GPSTimeout += GPSTimeout; //increase the timeout by itself n*2
                ensurePosition(callback, timestamp);//call itself to try again
            },
            {maximumAge:0, timeout:GPSTimeout}
        )
    }       
}

J'ai probablement des typos et des fautes d'orthographe ici, mais j'espère que vous avez compris l'idée. Faites-moi savoir si quelqu'un a des questions ou si quelqu'un trouve quelque chose de mieux.

5
Drew Calder

Pour tous ceux qui travaillent sur une application iPhone ...

Si votre code s'exécute dans UIWebView sur iOS 9+, vous devez définir NSLocationWhenInUseUsageDescription dans le répertoire de votre application.

Si vous ne le définissez pas, alors getCurrentPosition ne rappellera jamais et l'utilisateur ne sera jamais invité.

3
bendytree

La réponse de @ brennanyoung est excellente, mais si vous vous demandez quoi faire en cas d'échec, vous pouvez utiliser une API de géolocalisation IP telle que https://ipinfo.io (qui est mon service). Voici un exemple:

function do_something(coords) {
    // Do something with the coords here
    // eg. show the user on a map, or customize
    // the site contents somehow
}

navigator.geolocation.getCurrentPosition(function(position) { 
    do_something(position.coords);
    },
    function(failure) {
        $.getJSON('https://ipinfo.io/geo', function(response) { 
        var loc = response.loc.split(',');
        var coords = {
            latitude: loc[0],
            longitude: loc[1]
        };
        do_something(coords);
        });  
    };
});

Voir http://ipinfo.io/developers/replacing- navigator-geolocation-getcurrentposition pour plus de détails.

3
Ben Dowling

J'ai enfin trouvé une version fonctionnelle de Firefox, chrome et du navigateur par défaut dans Android (uniquement testé en 4.2):

function getGeoLocation() {
        var options = null;
        if (navigator.geolocation) {
            if (browserChrome) //set this var looking for Chrome un user-agent header
                options={enableHighAccuracy: false, maximumAge: 15000, timeout: 30000};
            else
                options={maximumAge:Infinity, timeout:0};
            navigator.geolocation.getCurrentPosition(getGeoLocationCallback,
                    getGeoLocationErrorCallback,
                   options);
        }
    }
2
surfealokesea

Le deuxième paramètre passé à Geolocation.getCurrentPosition() est la fonction que vous souhaitez gérer, quelle que soit l'erreur de géolocalisation. La fonction de gestionnaire d'erreurs reçoit elle-même un objet PositionError avec des informations détaillées sur l'échec de la tentative de géolocalisation. Je vous recommande de transmettre l'erreur à la console si vous rencontrez des problèmes:

var positionOptions = { timeout: 10000 };
navigator.geolocation.getCurrentPosition(updateLocation, errorHandler, positionOptions);
function updateLocation(position) {
  // The geolocation succeeded, and the position is available
}
function errorHandler(positionError) {
  if (window.console) {
    console.log(positionError);
  }
}

Faire cela dans mon code a révélé le message "Fournisseur d'emplacement réseau à ' https://www.googleapis.com/ ': Code d'erreur renvoyé 400". Il s'avère que Google Chrome utilise les API de Google pour obtenir un emplacement sur des appareils non équipés du GPS (par exemple, la plupart des ordinateurs de bureau). Google renvoie une latitude/longitude approximative basée sur l'adresse IP de l'utilisateur. Cependant , dans les versions de développeur de Chrome (telles que Chromium sur Ubuntu), aucune clé d'accès à l'API n'est incluse dans la version du navigateur. Cela entraîne l'échec silencieux de la demande d'API. Voir Numéro de chrome 179686: Géolocalisation donnant une erreur 4 pour plus de détails.

2
thirdender

J'ai trouvé que ça ne marche pas

navigator.geolocation.getCurrentPosition(function() {...}, function(err) {...}, {});

Mais

de cette façon fonctionne parfaitement

function storeCoordinates(position) {
    console.log(position.coords.latitude, position.coords.longitude);
}    

function errorHandler() {...}

navigator.geolocation.getCurrentPosition(storeCoordinates, errorHandler, { enableHighAccuracy: true, timeout: 20000, maximumAge: 0 });
2
1nstinct

Je rencontre des problèmes similaires et j'étudie la possibilité que les navigateurs limitent la fréquence d'appels de getCurrentPosition. Il semble que je puisse souvent avoir un emplacement, mais si j'actualise immédiatement la page, le délai expire. Si j'attends un peu, je peux généralement retrouver un emplacement. Cela se produit généralement avec FF. Dans Chrome et Safari, je n’ai pas encore remarqué le dépassement du délai de getCurrentPosition. Juste une pensée...

Bien que je ne puisse trouver aucune documentation à ce sujet, c’est une conclusion à laquelle je suis arrivé après de nombreux essais. Peut-être que quelqu'un d'autre a des infos à ce sujet?

2
brewster

Je posterai ceci ici au cas où cela serait utile à quelqu'un…

Sur iOS Safari, les appels à navigator.geolocation.getCurrentPosition expirent si une fonction active navigator.geolocation.watchPosition est en cours d'exécution.

Démarrer et arrêter correctement la watchPosition en utilisant clearWatch() comme décrit ici, fonctionne: https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition

2
JoLoCo

Dans notre cas, cela fonctionne toujours la première fois mais si vous réexécutez la fonction plus de 3 ou 4 fois, cela échoue.

Solution simple: stockez sa valeur dans LocalStorage.

Avant:

navigator.geolocation.getCurrentPosition((position) => {
  let val = results[0].address_components[2].long_name;
  doSthWithVal(val);      
}, (error) => { });

Après:

if(localStorage.getItem('getCurrentPosition') !== null) {
  doSthWithVal(localStorage.getItem('getCurrentPosition'));
}
else {
  navigator.geolocation.getCurrentPosition((position) => {
      let val = results[0].address_components[2].long_name;
      localStorage.setItem('getCurrentPosition',val);
      doSthWithVal(val);      
  }, (error) => { });
}
1
David Vielhuber

J'ai ce problème dans Mozilla. Tous les temps: Erreur: Erreur inconnue lors de l’acquisition de la position .

Maintenant, j'utilise 47 Mozilla. J'ai tout essayé, mais toujours ce problème. MAIS alors j'ouvre à propos de: config dans ma barre d’address, go geo.wifi.ui et a changé sa valeur en " https://location.services.mozilla.com/v1/geolocate?) clé = test ". travaux!

Si vous avez une erreur d’acquisition de position a expiré , essayez d’augmenter la valeur du délai d’expiration:

var options = {
  enableHighAccuracy: true,
  timeout: 5000,
  maximumAge: 0       
};
navigator.geolocation.getCurrentPosition(success, error, options);
1
Vasyl Gutnyk

Il peut être judicieux d’utiliser un service de géolocalisation d’adresses IP comme méthode de secours en cas de défaillance de getCurrentPosition. Par exemple avec notre api https://ip-api.io

$.getJSON("http://ip-api.io/json/",
    function(result) {
        console.log(result);
    });
1
Andrey E

Cette bibliothèque ajoute les options desireAccuracy et maxWait aux appels de géolocalisation, ce qui signifie qu'il continuera d'essayer d'obtenir une position jusqu'à ce que la précision se situe dans la plage spécifiée.

0
Mike McKay

J'ai récemment remarqué ce problème moi-même, et je ne suis pas sûr de la façon dont cela se produit, mais il semblerait que parfois Firefox reste bloqué sur quelque chose qui est chargé dans le cache. Après avoir effacé le cache et redémarré Firefox, il semble fonctionner à nouveau.

0
Assimilater

Merci à tous pour leur contribution, cela m'a aidé.

En plus d'avoir à utiliser watchPosition () au lieu de getCurrentPosition (), j'ai également constaté que je devais déplacer l'appel de document.ready () vers la tête.

0
user2217751