Behind AimiRun
From waiting for GPS to sensor-assisted distance tracking in AimiRun
From a smooth start on iOS to delayed, drifting and interrupted location updates on Android, follow how AimiRun improved its start logic, location sources and distance estimates.
When we first started building AimiRun, tracking runs on iOS was straightforward. Once location tracking was enabled, updates generally arrived as expected, and we needed very little additional GPS processing. It was easy to think that recording a run simply meant receiving positions continuously and joining them into a route.
The harder problems gradually appeared on Android. Each time we addressed one issue, real runs revealed another: first we had to wait for a position, then we found that the positions could drift, arrive in clusters or disappear for a while. What began as waiting for GPS became a broader question of when to start a run, which positions to trust and how to record distance during gaps in location data.
The first Android problem: tracking was on, but no updates arrived
On some Android phones, the app often had to wait a long time for its first location update after tracking was enabled. Sometimes there were no updates at all for a while. If timing and distance recording started only when the first GPS position arrived, the runner could be ready to go while the recording had yet to begin.
We first added a GPS gate: after entering the running screen, the app would wait for location information good enough to start before moving into the active run state. A fixed wait of a few seconds could not tell us whether positioning was ready, so we later made waiting a separate state and added a message when it took too long. At this stage, we were addressing when recording should begin. Position accuracy was still another problem to solve.
A location update could still be far from the actual position
As we reviewed more recordings from real devices, we found that Android location points could drift. Sometimes the phone would first deliver a cached last known location. It arrived quickly, but it could be outdated and far from the runner's current position. Treating it as a current position could move both the starting point and the first section of the route to the wrong place.
The problem was more noticeable in parks and residential areas. Trees, buildings and the surrounding environment could shift reported positions away from the path or road. In some recordings, the error reached about 110–220 yards. At other times, points bunched up in one area before suddenly jumping elsewhere, rather than following the route evenly. On the map, it looked as though the runner had made a sudden turn or cut across the park, when the positions supplied by the device were simply unstable.
The image below comes from a run in a park. The orange line connects the raw locations, while the blue line shows the processed route. Sharp corners and long diagonal lines made an ordinary run around a loop difficult to recognise.

Figure 1: The raw location path and processed route from the same recording.
We realised that receiving a location did not automatically mean receiving a trustworthy running position. The start logic needed to consider whether the position was fresh, and the route needed to tolerate some drift and outliers. At the same time, processing had to preserve bends and actual turns instead of flattening the route just to make the line look smoother.
Replaying raw positions made the problems easier to see
To understand what the phone had actually supplied during each run, we replayed the raw location points alongside the processed route. In the video below, yellow points appear as the recording progresses, while the green line shows the corresponding route. Reviewing the data this way made it easier to find jitter and abnormal positions than looking only at the final route.
Video: Raw location points and a route taking shape during a real recording.
With a poorer signal, the result could look like the next image. Raw positions were scattered on both sides of the route, with some far outside the usual loop. Connecting them produced long lines cutting across the whole area. By repeatedly reviewing these recordings, we gradually adjusted how we handled drift, sudden jumps and clusters of points.

Figure 2: Another recording with less stable positioning. Yellow marks the raw positions; green shows the processed route.
Then we encountered gaps in the signal
Positioning problems in parks and residential areas went beyond large errors. During some runs, usable location updates stopped for a stretch and then suddenly returned. That could leave gaps in the route and undercount the distance. If the returning position was far away, a straight line between cached positions could also be mistaken for actual movement.
For comparison, we also recorded the same run at the same time with another running app. Its recording showed similar route problems, and the reported distance differed greatly from our estimate based on the actual route. This was one comparison on a particular device and route, so it does not describe how other apps perform in general. It did remind us that switching running apps would not automatically remove instability in the phone's positioning or system services.
After a system update, changing the location source did not solve it immediately
Later, after a system update on one phone, GPS responses became even slower. We could wait more than ten minutes and still have no usable position. We tried integrating Amap's location SDK, hoping another source would provide a position sooner.
During debugging, Amap also kept returning positions with very poor accuracy. Looking back, the main problem lay in that phone's system environment. Changing the location SDK alone did not make the raw positions reliable. The attempt still helped us understand the limits of what the app could do: it could evaluate and process the positions it received, but it could not guarantee that the phone would promptly supply good location data.
Letting two location sources compete before an Android run
We then introduced competition between two location sources. Before a run, we would request location information from both in parallel and use the incoming data and its quality to decide whether recording could begin. Once one source provided stable, usable positions, we could select it for the rest of the run. The aim was to reduce waiting when one source was slow to respond.
This improved our chances of getting usable information sooner; it did not guarantee GPS accuracy. Both sources could still give poor positions in the same weak-signal environment. We gradually stopped making an ideal GPS fix the only condition for starting a run and recording distance.
Distance no longer depended only on changes between GPS points
The final shift came from gaps in location data. A runner might still be moving when no reliable GPS points were available, but the positions before and after a gap could not tell us how far they had actually travelled in between. We began using motion information from the phone's sensors to help estimate distance, together with the running activity recorded before the gap, so that movement could be recorded more continuously.
GPS remained important. Usable positions still helped us draw the route and understand the run. During gaps, sensor information and the motion data already available could help estimate distance. Those estimated sections were not GPS positions actually received during that time, so they needed to be distinguished from measured positions in the replay.
Looking back, we began by waiting for GPS updates. We then learned that an update could be unreliable, and that reliable positioning could still stop for a while. Each real run made the problems more concrete. Our approach gradually moved from waiting for a GPS point to treating the start of a run, its route and its distance as separate questions.
To learn how to review a route and gaps in its location data after a run, read about running route replay.