mapbox / mapbox/mapbox-navigation-ios

[Bug] Offline guided navigation not working for some routes

Open
#4,419 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Swift
Stars
918
Forks
326
Avg merge
1h 16m
Merged PRs (30d)
3

Description

Hello,

I have been using MapBox guided navigation (turn-by-turn) successfully in my app for a while, and am now looking to implement offline guided navigation.

I have configured predictive caching for both map and navigation, and implemented the manual TileStore region caching following your [tutorial](https://docs.mapbox.com/ios/navigation/guides/advanced/offline/) and [example](https://docs.mapbox.com/ios/navigation/examples/offline-navigation/) code.

Unfortunately, I have not been able to get offline guided navigation to work consistently.

**Packages:**
MapboxNavigation `2.12.0-rc1`
MapboxMaps `10.12.1`
and all of their dependencies.

**Steps I take to encounter issue:**

1. Perform the TileStore caching for a route.
1. Run the guided navigation for a few minutes to let predictive caching do its thing.
1. Close the app.
1. Disconnect from the internet.
1. Reopen the app and attempt to start guided navigation again for a route which should now be cached.
1. Guided navigation will start for some routes, but for others I will receive an error when trying to calculate directions for the route.

I'm not sure why some routes will work offline but not others. It is easier to reproduce when using very long routes e.g. 50km, but can also happen on short routes e.g. 2km.

I know the caching is successful as I have logged the TileStore response from `tileStore.loadTileRegion(forId:loadOptions:)` and have looked into the apps documents and caches folders and can see the map and navigation data being created and updated.

I'm encountering this issue when attempting to calculate the directions for a route using `Directions.calculateWithCache(options:)`.

The error that I get back when the directions calculation fails for this route is always:

```
[Mapbox] [Error, nav-native]: getRoute("https://api.mapbox.com/directions/v5/mapbox/driving/144.966347,-37.815031%3B144.231977,-36.594836%3B143.756608,-35.545444?alternatives=true&continue_straight=true&roundabout_exits=true&exclude=unpaved&geometries=polyline6&overview=full&steps=true&language=en-US&voice_instructions=true&voice_units=imperial&banner_instructions=true&annotations=duration,maxspeed,congestion_numeric&waypoints=0;2&access_token=****sDBA") id 0 failed: RouterException No suitable edges near location
```

It sounds like it is saying that there is not enough cached data to calculate directions for this route, but all of the coordinates, including the users location are within the cached regions via TileStore caching.

For predictive caching, I have set it to be very generous on the radius it caches to see if that solves the problem, but it does not.

For TileStore region caching, I cache a bounding box which encompasses all of the relevant coordinates for the route including the users current location.

I'm not sure if I'm missing something, or if it's a bug in the SDK. I've gone through the tutorial and example code a bunch of times but it all seems fine.

I don't want to flood this ticket with tons of code, so I'm going to try to post only the relevant snippets of code that I'm using for the TileStore region caching.

```swift
let tileStore = TileStoreConfiguration.Location.default.tileStore
tileStore.setOptionForKey(
TileStoreOptions.mapboxAccessToken,
domain: .maps,
value: BuildConfig.mapBoxAccessToken
)
tileStore.setOptionForKey(
TileStoreOptions.mapboxAccessToken,
domain: .navigation,
value: BuildConfig.mapBoxAccessToken
)

// Set disk quota to 200MB.
tileStore.setOptionForKey(
TileStoreOptions.diskQuota,
value: 209715200
)

let offlineManager = OfflineManager(
resourceOptions: ResourceOptions(
accessToken: BuildConfig.mapBoxAccessToken,
tileStore: tileStore,
tileStoreUsageMode: .readOnly
)
)
```

[...] Style pack is then cached using offline manager [...]

```swift
let styleURI = StyleURI(rawValue: BuildConfig.mapBoxStyleUrl)!
let tilesetDescriptorOptions = TilesetDescriptorOptions(
styleURI: styleURI,
zoomRange: 5...12,
stylePackOptions: stylePackLoadOptions
)

// Create a bounding box encompassing all coordinates from all stages in this drive.
// All tiles within this bounding box will be cached.
let bboxNorth = allCoordinates.map(\.latitude).max()!
let bboxSouth = allCoordinates.map(\.latitude).min()!
let bboxEast = allCoordinates.map(\.longitude).max()!
let bboxWest = allCoordinates.map(\.longitude).min()!

// Coordinates in this outer ring must be counter-clockwise.
// https://www.rfc-editor.org/rfc/rfc7946#section-3.1.6
let outerRing = Ring(coordinates: [
LocationCoordinate2D(latitude: bboxNorth, longitude: bboxEast),
LocationCoordinate2D(latitude: bboxNorth, longitude: bboxWest),
LocationCoordinate2D(latitude: bboxSouth, longitude: bboxWest),
LocationCoordinate2D(latitude: bboxSouth, longitude: bboxEast),
LocationCoordinate2D(latitude: bboxNorth, longitude: bboxEast),
])
let polygon = Polygon(outerRing: outerRing)

let tilesetDescriptor = offlineManager.createTilesetDescriptor(for: tilesetDescriptorOptions)
let tileRegionLoadOptions = TileRegionLoadOptions(geometry: polygon.geometry, descriptors: [tilesetDescriptor], acceptExpired: false)!
let tileRegionId = "\(event.id.uuidString)_\(drive.id.uuidString)"

tileStore.tileRegion(forId: tileRegionId) { result in
switch result {
case .success(_):
log.info("Tile region is already cached.")
case .failure(_):
log.info("Caching tiles for \(drive.routes.count) stages in drive '\(drive.name)'...")
tileStore.loadTileRegion(forId: tileRegionId, loadOptions: tileRegionLoadOptions) { result in
[...]
}
}
}
```

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the offline flow with MapboxNavigation 2.12.0-rc1 and MapboxMaps 10.12.1, focusing on TileStore.loadTileRegion(forId:loadOptions:) and Directions.calculateWithCache(options:). Compare a working route with a failing route and inspect the reported “No suitable edges near location” error. Done means the cause of inconsistent offline route calculation is identified and the issue has a verified resolution or documented limitation.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.