-
Notifications
You must be signed in to change notification settings - Fork 313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Offline routing #1808
Offline routing #1808
Conversation
Some thoughts on a few of the remaining checklist items:
Should this be a gating feature at this point? I'm not entirely convinced but it should be open to debate. Also, if we are going to do this we should have a small group design discussion about the mechanism. I could see this being a candidate for a boolean delegate method or configuration option.
As we discussed, if we're going to use an
I have a feeling this will punt to a further iteration. Especially considering that there are other potential changes to tile transport currently under debate which could change the scope of this. |
I've given a 👍 - @mapbox/navigation-ios any other feedback? |
Example/OfflineViewController.swift
Outdated
Directions.shared.fetchAvailableOfflineVersions { [weak self] (versions, error) in | ||
|
||
let nonEmptyVersions = versions?.filter { !$0.isEmpty } | ||
guard let version = nonEmptyVersions?.first else { return } |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Example/ResizableView.swift
Outdated
return self / 2 | ||
} | ||
|
||
func distance(_ to: CGFloat) -> CGFloat { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calculations in the pan gesture recognizer were getting unreadable but it has been cleaned up since then so it makes sense to remove this simple distance.
Example/SettingsItems.swift
Outdated
|
||
let offlineItem = Item(title: "Download arbitrary region", viewControllerType: OfflineViewController.self, payload: nil) | ||
let offlineSection = Section(title: "Offline Examples", items: [offlineItem]) | ||
let versionSection = Section(title: "Downloaded versions", items: versionDirectories()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: use title case consistently for section titles:
let versionSection = Section(title: "Downloaded versions", items: versionDirectories()) | |
let versionSection = Section(title: "Downloaded Versions", items: versionDirectories()) |
Example/SettingsViewController.swift
Outdated
let tilesURL = Bundle.mapboxCoreNavigation.suggestedTilePathURL(for: selectedOfflineVersion) | ||
|
||
Settings.directions.configureRouter(tilesURL: tilesURL!) { [weak self] (numberOfTiles) in | ||
let message = "Router configured w/ \(numberOfTiles) tiles." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let message = "Router configured w/ \(numberOfTiles) tiles." | |
let formattedTileCount = NumberFormatter.localizedString(from: numberOfTiles as NSNumber, number: .decimal) | |
let message = "Router configured with \(formattedTileCount) tiles." |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was under the impression that our Examples should only be in English while having empty languages added to test all supported languages in the SDK to mitigate translators fatigue. However, it's only a few localizable strings in the examples so far so I added this one as well.
|
||
func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool { | ||
|
||
let shouldUseOfflineRouting = Settings.selectedOfflineVersion != nil |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
OfflineDirectionsConstants.offlineSerialQueue.async { [weak self] in | ||
|
||
guard let result = self?.navigator.getRouteForDirectionsUri(url.absoluteString) else { | ||
let error = OfflineRoutingError.unexpectedRouteResult("Unexpected routing result") |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
let calculateRouteExpectation = expectation(description: "Calculate route offline") | ||
var route: Route? | ||
|
||
directions.calculate(options, offline: true) { (waypoints, routes, error) in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we verify somehow that nothing is fetched from an online source?
|
||
progressUpdates += 1 | ||
|
||
if (progressUpdates >= 2) { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@@ -1182,6 +1202,19 @@ | |||
name = Resources; | |||
sourceTree = "<group>"; | |||
}; | |||
3529FCEE21A5C52C00AEA9AA /* Recovered References */ = { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
} | ||
|
||
/** | ||
Defines additional functionality similar to `Directions` with support for offline routing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this protocol differ from the OfflineDirectionsProtocol defined by MapboxDirections.swift? I think this could become a source of confusion among developers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it can cause confusion, however, NavigatorDirectionsProtocol
depends on nav-native so it should be defined here, while OfflineDirectionsProtocol
is a good fit for MapboxDirections since it's only adding additional directions related API calls. Do you have an idea how to simplify it? The protocol could be moved to MapboxDirections’s OfflineDirectionsProtocol
but the implementation must reside in MapboxCoreNavigation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the confusion would stem from how this protocol is described as “similar to Directions
with support for offline routing”. So if we need to keep it as a separate protocol, then can we frame it as a kind of NavigationService that has Directions functionality built in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments about user-facing strings and localization fit-and-finish. Also, there needs to be at least one changelog entry about the new stuff. I can take it from here.
OfflineDirectionsConstants.offlineSerialQueue.async { [weak self] in | ||
|
||
guard let result = self?.navigator.getRouteForDirectionsUri(url.absoluteString) else { | ||
let message = NSLocalizedString("OFFLINE_NO_RESULT", bundle: .mapboxCoreNavigation, value: "No result", comment: "No result from offline route request") |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Example/SettingsViewController.swift
Outdated
|
||
Settings.directions.configureRouter(tilesURL: tilesURL!) { [weak self] (numberOfTiles) in | ||
let formattedTileCount = NumberFormatter.localizedString(from: numberOfTiles as NSNumber, number: .decimal) | ||
let message = String.localizedStringWithFormat(NSLocalizedString("Router configured with %@ tile(s).", comment: "Alert message when a router has been configured"), formattedTileCount) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
} | ||
|
||
guard let data = result.json.data(using: .utf8) else { | ||
let message = NSLocalizedString("OFFLINE_CORRUPT_DATA", bundle: .mapboxCoreNavigation, value: "Corrupt route data", comment: "Unable to deserialize the offline route response") |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Example/UIViewController.swift
Outdated
|
||
func presentAlert(_ title: String? = nil, message: String? = nil) { | ||
let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) | ||
controller.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Example/OfflineViewController.swift
Outdated
|
||
view.addSubview(resizableView) | ||
|
||
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Download", style: .done, target: self, action: #selector(downloadRegion)) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Example/OfflineViewController.swift
Outdated
|
||
view.addSubview(resizableView) | ||
|
||
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Download", style: .done, target: self, action: #selector(downloadRegion)) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Example/OfflineViewController.swift
Outdated
NavigationDirections.unpackTilePack(at: url, outputDirectoryURL: outputDirectoryURL!, progressHandler: { (totalBytes, bytesRemaining) in | ||
|
||
let progress = (Float(bytesRemaining) / Float(totalBytes)) * 100 | ||
self?.updateTitle("Unpacking \(Int(progress))%") |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
I’m seeing tons of console spew along these lines, seemingly in a hot loop, while displaying a visual instruction that should include shields in the simulator. The shields never load, but more importantly, I think the level of spew would quickly consume battery and storage.
|
Copyedited various strings in the example application and gave them all stable IDs. Made some additional strings localizable. Removed a redundant Base.lproj folder from the example project structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks ready to go, but I’m concerned about the console spew in #1808 (comment).
These methods return file URLs, not path strings. Also added documentation and Objective-C compatibility.
Also fixed some copypasta in documentation comments.
public class NavigationDirections: Directions { | ||
|
||
public typealias UnpackProgressHandler = (_ totalBytes: UInt64, _ remainingBytes: UInt64) -> () | ||
public typealias UnpackCompletionHandler = (_ result: UInt64, _ error: Error?) -> () |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
public class NavigationDirections: Directions { | ||
|
||
public typealias UnpackProgressHandler = (_ totalBytes: UInt64, _ remainingBytes: UInt64) -> () | ||
public typealias UnpackCompletionHandler = (_ result: UInt64, _ error: Error?) -> () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does result
represent a status code? What codes can be returned, and under what circumstances?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed to numberOfTiles
since it corresponds to the number of unpacked tiles.
This turned out to be infinite recursion: #1887. |
The infinite recursion will be fixed by #1888. Locally, with that patch applied, I see generic shields as expected, though I don’t see exit number tabs as I do with server-side routing. The exit number is included in spoken instructions, and the exit number tabs do show up when performing server-side routing on this same branch. Unless an obvious cause materializes very shortly, I think it’s fine to treat that issue as tail work. |
This PR brings offline routing to the Navigation SDK
Automatic failoverWrapNavigationDirections.calculate(_:offline:completionHandler:)
in aURLSessionDataTask
or another operation that supports cancelingPause/Resume a download operationcc @akitchen @1ec5 @JThramer @vincethecoder