mapbox / mapbox-navigation-ios

Turn-by-turn navigation logic and UI in Swift on iOS
https://docs.mapbox.com/ios/navigation/
Other
855 stars 299 forks source link

[QUESTION]: Serializing navigation routes #4675

Open lpeancovschi opened 3 weeks ago

lpeancovschi commented 3 weeks ago

Mapbox Navigation SDK version

3+

Steps to reproduce

In navigation map SDK 2+ it was possible to show navigation routes by providing Route array to it. It was useful because Route object is serializable and can be saved.

Navigation SDK 3+ changed this method to accept a NavigationRoutes struct instead, which is not Codable.

My question is: given I want to be able to store routes offline and also make sure I can store them in a future proof way, how can I serialize them? Also, NavigationRoutes doesn't seem to have public initializers.

Expected behavior

NavigationRoutes should be Codable or provide a simple API for constructing a route on a map.

Actual behavior

NavigationRoutes is not Codable.

Is this a one-time issue or a repeatable issue?

one-time

lpeancovschi commented 2 weeks ago

@azarovalex, do you know Mapbox Navigation SDK 3+ supports route serialization?

lpeancovschi commented 2 weeks ago

This is very disappointing. My application relies on saving Routes offline, which is achievable in Navigation SDK 2 because Route struct is Codable so I can easily store it. Now, in SDK v3 they abstracted it with NavigationRoutes which is not serializable. It breaks my whole app functionality. Time to check Apple's topographic maps in iOS 18. Before releasing new updates you should should account for backwards compatibility.

Udumft commented 1 week ago

Hi @lpeancovschi! NavigationRoutes are made intentionally non-storable as it is not recommended to use 'old' routes. The main reason for this is that the road network changes constantly, and stale route may utilize road which are no longer available, or which were updates, so the resulted navigation experience may become inadequate. So due to this fact that it is not guaranteed that even the basic properties like route geometry will not stay the same - NavigationRoutes are not serializable. As a recommended solution for the case when route need to be stored - it is advices to instead store the key waypoints and parameters (or you could even store the entire request URL), and do a fresh request when the route is actually needed. With onboard routing available - it'll also cover offline use-cases. Could you please expand more about your use-case and why you see storing of the routes as the only viable option?

lpeancovschi commented 1 week ago

Hi @Udumft!

Thank you for your reply! The app I'm building will provide functionality for users to create a trail: by dropping pins on the map and then other users would be able to find an existing trail and view its details: preview route, elevation, etc. (similar to what AllTrails does). With waypoint approach I can think of these limiations:

  1. Way more expensive. Now I have to pay not only once for route calculation on creator's side, but also for each view on the viewer side. I'm trying to be mindful about my spend as this is a self funded project, with this approach I can easily go off limits.
  2. How would a user access a map once their are in offline area? Do I need to pre-load offline maps for that?
  3. If I have to calculate the path every time, is it guaranteed that NavigationSDK's mainRoute will always be the same? Is this guaranteed to be future proof and also provide consistent results across different SDK versions / platforms. The app will be available on iOS and Android and obviously over time some users will be using older app version with older NavSDK versions.
Udumft commented 6 days ago

Hey! I could suggest you to evaluate the offline use-case for route building and previewing. Regarding your points:

  1. Offline route requests are not billed, so you won't get extra charges for route previews (see CoreConfig.routingConfig.routingProviderSource for configuration).
  2. By default, surrounding tiles are downloaded and cached automatically, so the user should always have some area around him which is navigatable offline. Anyway, if you want any user to be able to build any route offline, you can manually download the tiles required by that route (set of waypoints will work too). See the Offline Regions example to know how to manually download an arbitrary tiles region (keep in mind you would probably need to clean it up after preview or something).
  3. Routes are never guaranteed to be the same. This is the reason I've mentioned previously: road network is changing and each route may be potentially changed. The chances are low, but I have to mention it anyway. Also, route building depends on more variable conditions like, for example traffic conditions (if you are driving) or even user initial bearing. In general, route building is not dependent on platform or SDK version. All of them are relying on the directions endpoint (or it's local implementation in offline use-case), which, technically, may get it's routing engine updated, but these updates will be equally applied to all SDKs and platforms as long as they are requesting routes with the same parameters. One more thing you could look into to make sure route's geometry is not changed - add some silent waypoints (Waypoint.separatesLegs = false). Just make sure not to go over the maximum waypoints limit in a request.

To summarize: to build a new route, user may do a 'usual' online request (like it is implemented now). When saving the route for other users, you could store it's waypoints, optionally add several 'silent' waypoints along the route, and store the required metadata (elevation, distance, etc.). When browsing saved routes, users will have to first download the required offline regions using the route's waypoints (it won't result in additional costs, comparing to current implementation, as tiles would be downloaded anyway), and re-build the route using provided waypoints with an offline router. Users may then continue and navigate that offline route object, or do a fresh online request if needed.

lpeancovschi commented 2 days ago

Thanks, @Udumft!

I will try loading the tiles first and then calculating the path in off-line. However I don't really like the fact that UX of the app has to be adjusted because of SDK limitations. Basically, my user experience would be similar to AllTrails app. They allow recording a trail and then users can preview it. I want to allow similar experience, be it with recorded trail and with a calculated one. I think pre-loading tiles and calculating directions offline would result in delays and provide poor usability. Do you know how AllTrails solve this problem? They are using your map too.

Udumft commented 2 days ago

Hi! Well, the only way the UX may suffer is that indeed sometimes offline route calculation may take longer then online and it should download the tiles before starting the actual calculation, but in both ways user devices would have to download the tiles anyway. I am not aware of AllTrails details, perhaps they are still using V2. You could also check this docs section to help you setup and work with the tile regions. Keep me posted about your progress!