geolocation doesn't work with iOS 6 web apps!

The javascript geolocation service doesn't work with iOS 6 web apps. We have a web app that works fine in iOS 5 and it works fine in iOS 6 in Safari. But in iOS 6 if you create a web app by adding clicking on the middle icon at the bottom of Safari and adding the app to your home screen it doesn't work anymore. The geolocation call simply hangs.


I created a really simple test problem. Simply go to http://stroll.nextbus.com/webkit/test.jsp in Safari to try it out. Then create a Home Screen icon for it and click on the icon and you can see that your position is never displayed. You can look at the html to understand this trivial application.


So how does one contact Apple to get them to investigate this issue?


And by the way, we have already gotten a huge number of complaints about this problem!


-- Mike

iPhone 4S, iOS 6

Posted on Sep 19, 2012 8:50 PM

Reply
Question marked as Top-ranking reply

Posted on Dec 22, 2012 12:01 AM

I have found a workaround for this. It turns out that you can implement the functionality of watchposition by repeatedly polling navigator.geolocation.getCurrentPosition. Set maximumAge to 0 so that you don't get a cached result. This should keep the GPS "hot".


In my implementation, function getLocation sets everything up (including saving a global callback function) and ends by calling getLocation0. Helper function getLocation0 has a single line that calls navigator.geolocation.getCurrentPosition, with getLocation1 as the immediate callback. This third function, getLocation1, checks to see if the accuracy is within the specified threshold or if we are past the specified timeout. If either of these conditions is true, we are done. Otherwise, we set a timeout that will go to getLocation0 after a specified time period, such as 500 ms.


This is simplified from code that is considerably more complex, and it is likely that I have broken it in the process, but hopefully you can get the general idea and adapt for your own use.


geolocate = (function () { // PRIVATE var lat, // Current latitude ***, // Current longitude acc, // Most recent accuracy reading callback, // Call this external function after updating location thresh, // accuracy threshhold for watchPosition, in meters giveUp; // Time at which to quit trying to get a more accurate geolocation reading // This function is called to report any geolocation errors we may get from our requests function displayError (error) { // Display error and cancel watch, if applicable alert ('Geolocation error [code=' + error.code + ', message="' + error.message + ']"'); }; // PUBLIC var geolocate = {}; geolocate.lat = function () { return lat; }; geolocate.*** = function () { return ***; }; geolocate.getLocation0 = function () { navigator.geolocation.getCurrentPosition( geolocate.getLocation1, displayError, {enableHighAccuracy:true, maximumAge:0} ); } geolocate.getLocation1 = function (position) { var now = new Date(); if (Math.round(position.coords.accuracy) <= thresh || now >= giveUp) { // display.message('Got it! Accuracy = ' + Math.round(position.coords.accuracy) + 'm'); lat = position.coords.latitude; *** = position.coords.longitude; acc = position.coords.accuracy; callback(); // Success! Now do whatever we were supposed to do next } else { setTimeout(geolocate.getLocation0, 500); timeLeft = Math.round((giveUp.getTime() - now.getTime()) / 1000), // display.message('Accuracy = ' + Math.round(position.coords.accuracy) + 'm; ' + timeLeft + 's left'); } } geolocate.getLocation = function (hook, accuracy, timeout) { if (navigator.geolocation) { // Process parameters and initialize variables callback = hook; giveUp = new Date(); giveUp.setTime(giveUp.getTime() + timeout*1000); // Give up after 'timeout' seconds geolocate.getLocation0(); } }; return geolocate; }() );


Example call:

geolocate.getAccurateLocation(myFunction, 50, 10);

71 replies
Question marked as Top-ranking reply

Dec 22, 2012 12:01 AM in response to MikeAtNextBus

I have found a workaround for this. It turns out that you can implement the functionality of watchposition by repeatedly polling navigator.geolocation.getCurrentPosition. Set maximumAge to 0 so that you don't get a cached result. This should keep the GPS "hot".


In my implementation, function getLocation sets everything up (including saving a global callback function) and ends by calling getLocation0. Helper function getLocation0 has a single line that calls navigator.geolocation.getCurrentPosition, with getLocation1 as the immediate callback. This third function, getLocation1, checks to see if the accuracy is within the specified threshold or if we are past the specified timeout. If either of these conditions is true, we are done. Otherwise, we set a timeout that will go to getLocation0 after a specified time period, such as 500 ms.


This is simplified from code that is considerably more complex, and it is likely that I have broken it in the process, but hopefully you can get the general idea and adapt for your own use.


geolocate = (function () { // PRIVATE var lat, // Current latitude ***, // Current longitude acc, // Most recent accuracy reading callback, // Call this external function after updating location thresh, // accuracy threshhold for watchPosition, in meters giveUp; // Time at which to quit trying to get a more accurate geolocation reading // This function is called to report any geolocation errors we may get from our requests function displayError (error) { // Display error and cancel watch, if applicable alert ('Geolocation error [code=' + error.code + ', message="' + error.message + ']"'); }; // PUBLIC var geolocate = {}; geolocate.lat = function () { return lat; }; geolocate.*** = function () { return ***; }; geolocate.getLocation0 = function () { navigator.geolocation.getCurrentPosition( geolocate.getLocation1, displayError, {enableHighAccuracy:true, maximumAge:0} ); } geolocate.getLocation1 = function (position) { var now = new Date(); if (Math.round(position.coords.accuracy) <= thresh || now >= giveUp) { // display.message('Got it! Accuracy = ' + Math.round(position.coords.accuracy) + 'm'); lat = position.coords.latitude; *** = position.coords.longitude; acc = position.coords.accuracy; callback(); // Success! Now do whatever we were supposed to do next } else { setTimeout(geolocate.getLocation0, 500); timeLeft = Math.round((giveUp.getTime() - now.getTime()) / 1000), // display.message('Accuracy = ' + Math.round(position.coords.accuracy) + 'm; ' + timeLeft + 's left'); } } geolocate.getLocation = function (hook, accuracy, timeout) { if (navigator.geolocation) { // Process parameters and initialize variables callback = hook; giveUp = new Date(); giveUp.setTime(giveUp.getTime() + timeout*1000); // Give up after 'timeout' seconds geolocate.getLocation0(); } }; return geolocate; }() );


Example call:

geolocate.getAccurateLocation(myFunction, 50, 10);

Mar 8, 2013 10:52 AM in response to MikeAtNextBus

Seems to be working fine with the 6.1.2 update. Once the website is loaded, the watch fires right away, and keeps updating the location accordingly. When the safari window is closed, the location service seems to go into some kind of idle status. When you expand the Safari window again, the location service resume the updating... I had the same issues as described in the above posts, but installing iOS 6.1.2 first on iPhone4, then on iPad2 was the trick 🙂 Enjoy folks!

Dec 22, 2012 8:33 PM in response to Thomas Quartus

Update: The above "workaround" requires removing

<meta name="apple-mobile-web-app-capable" content="yes" /> or changing this setting to "no". Otherwise subsequent calls to navigator.geolocation.getCurrentPosition never invoke the callback.


It also requires calculating speed directly from observations.


Agree with all that this is a huge, awful, major bug. And another reminder that poor Apple just can't seem to get geolocation right these days. (In working on this, I keep linking to Apple maps and can't help but notice that somehow they have got the cul-de-sac running right through our neighbor's house...) (Sigh.)

Feb 6, 2013 6:26 AM in response to XCTrails

Ok, I now tried the approach with the timer controlled getCurrentPosition instead of watchPosition, same effect. Works for the first time, on subsequent calls (i.e. to refresh a changed position) it delivers results with a bad accuracy.


There is something else I observed, though: If I task switch to the builtin maps app in that situation, maps freezes for some seconds, then has a proper position. Switching back to the webapp, I can now retrieve a valid position again.


If I run an app like MotionX-GPS in the background and set it to not turn of the GPS at all when backgrounded, all is fine, I can update the position in the webapp as often as I want.


So it seems to me as if the JS calls somehow leave the GPS in a strange state or fail to "wake it up" - apparently native apps or a browser restart reinitialize it but repeated calls via the navigator.geolocation interface don't.


So as far as I'm concerned this interface is still broken unless you only call it once (or maybe a couple of times, eventually it will fail).


Message was edited by: XCTrails

Mar 11, 2013 4:22 AM in response to MikeAtNextBus

This issue seems to be a real disaster for anyone writing webbased geolocation applications. Please all make sure you have submitted a bug report to apple at bugreport.apple.com! (I have also submitted a TDS ticket).


Has anyone tested this with iOS 6.1.3 beta?


The discussion here as well as these two SO posts seems to be the same problem:

http://stackoverflow.com/questions/12503815/ios-6-breaks-geolocation-in-webapps- apple-mobile-web-app-capable

http://stackoverflow.com/questions/12553910/ios6-geolocation-watchposition-callb acks-fail


I have put together a testpage that you can use if you want to investigate this problem:


Open http://jsbin.com/esasix/16/ in your iPhone or iPad.

Walk around outside, refresh the page and try other test scenarious.

Watch how your position is being reported.


I have done a lot of testing myself with the following results:


Tests performed:

Own tests using this simple test page: jsbin.com/esasix/16/

Own tests using maps.google.com mobileweb map

Own tests using my application

Many logs from external users of my application

Tested using different devices


My findings:


At the same testsituation I often get perfect positioning regularly with 5m accuracy as well as poor reception caused by the bug. This means that the device, location, weather, time of day etc. is the same in both situations.


Sometimes only one position is returned after loading page.

Sometimes a few positions are returned after loading page.

Sometimes a number of good positions are returned then suddenly it stops returning positions (sometimes this occurs after standing still for a while) and it goes into a bad state, possibly returning positions again but often bad ones.

Sometimes many positions are returned with accuracy 65m.

Sometimes many positions are returned with varying bad accuracy (typically 50-300m).

These series of positions with bad accuracy are sometimes close to series of perfect ones with 5m accuracy (after it has entered the bad state?).

Sometimes everything works fine for many tests in succession...


These behaviours seems to appear in various combinations.


In some situations re-opening Safari seems to re-set something and it starts working again. However, in some of those situations it then only worked for a while and in other situations it had no effect att all so it can be used as a reliable work-around(?). The same behaviour is shown when opening the built in maps application, sometimes it helps, sometimes it does not...


Have tested with code that uses navigator.geolocation.watchPosition as well as code that calls navigator.geolocation.getCurrentPosition in a loop at regular intervalls and it has not made any difference, same type of problems can be seen in both cases.


Seems to occur for iOS version 6.0 to 6.1.2 I am not using the apple-mobile-web-app-capable meta tag.


I have found that sometimes a particular testsituation appears to show a specific behaviour leading to conclusions being made but then another test proves that conclusion wrong. I have not yet been able to find any behaviour (nor solution) that is reliably reproducable.

Mar 11, 2013 12:08 PM in response to alstorp

I still really think nothing has been done to fix this issue. This has been introduced in iOS6 since now apps prompts user for permission to do something locally (which is good, i guess). Since a chromeless HTML view is not inside Safari, it can't inherit its geolocation access permission. But since it's not an installed app neither, i does not exists in Settings, neither registered in iOS as an app.


That's why i really think the geolocation API asks for a permission to get this data, but can't figure out which app is asking for it (no app unique identifier) so the process kinda fail. I guess if Safari has been opened in the last few seconds, its "session" makes the chromeless app inherits its permission.


Just my $0.00002...

Jul 31, 2013 4:56 AM in response to XCTrails

I can no longer get this issue using iOS 7 beta 4 - 11A4435d (seems like it was fixed in beta 2). I've tried hard to provoke it but everything seems to work fine (on iOS 6 it was easy to reproduce).


I encourage everyone using iOS 7 to test and confirm that this bug is fixed or submit bug rapports to apple if problems are still found. We need many positive confirmations or an official statement from Apple before we can conclude that it has really been fixed.


Test using the following links (note: a few positions with cell or wifi type accuracy in the beginning until the gps get it's position is ok):


http://jsbin.com/acokaj/8 (plots your position, code available)

http://maps.google.com (web version of maps should show correct pos as you walk around)

(XCTrails - I tested using your link as well and it seems to work fine).


Updated my own bug report with this information but I have not received any response or confirmation from apple (ask them to check a bug submitted by Alstorp).


Unfortunately we will have to wait until beginning of October until iOS 7 is in widespread use. I wish Apple would release an 6.X update with this fix but it does not seem likely as they have ignored it for so long already...

Jan 18, 2013 5:12 PM in response to MikeAtNextBus

The good news is: I've done it... I've figured it out. The bad news is: somebody smarter than me is going to have to tell you why this works, whereas any other variation of this solution or any of the other solutions offered don't work. This was a hard-fought victory but I'm too embarrassed to say how many hours (days) it took me to figure this out. Without further ado, here's a link to the solution. http://stackoverflow.com/a/14410106/818266

Feb 7, 2013 5:43 AM in response to aesculus

Ok, I created a basic UI for the code in http://stackoverflow.com/a/14410106/818266. It acquires the position on page load and has a refresh button for position updates on the open page. See here: http://xctrails.org/gc/locTest.html


After the page load, wait a bit, or task switch to another app and back, then press refresh, sooner or later, in my tests on a 6.1 4S and a 6.1 3GS the accuracy will increase significantly and the position data will be basically be worthless. At that point, the browser needs to be terminated and restarted to get out of that state. This goes in line with what the author of the above code said in his post: "this doesn't seem to work as consistently if the execution of this code it delayed at some point after initially launching the app".


As mentioned, running a native app with continuous GPS access in the background "solves" this problem.

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

geolocation doesn't work with iOS 6 web apps!

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.