diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..c52b57b80b9 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,68 @@ +version: 2.1 + +jobs: + build-job: + parameters: + xcode: + type: string + ios: + type: string + mac_runner: + type: string + macos: + xcode: << parameters.xcode >> + resource_class: << parameters.mac_runner >> + steps: + - checkout + - run: + name: Prepare .mapbox file + command: | + echo "pk.foo.bar" > ~/.mapbox + - run: + name: Prepare .netrc file + command: | + echo "machine api.mapbox.com" >> ~/.netrc + echo "login mapbox" >> ~/.netrc + echo "password $SDK_REGISTRY_TOKEN" >> ~/.netrc + chmod 600 ~/.netrc + - run: + name: Install iOS runtime if needed + command: | + xcrun simctl list runtimes + if ! xcrun simctl list runtimes | grep -q "<< parameters.ios >>"; then + brew install aria2 xcodesorg/made/xcodes + sudo xcodes runtimes install "iOS << parameters.ios >>" + else + echo "Runtime << parameters.ios >> is already installed, skipping..." + fi + - run: + name: Build Examples + command: | + samples=("UIKitExample" "CoreSDKExample" "AdditionalExamples") + + for sampleName in "${samples[@]}"; do + xcodebuild -project Examples/Examples.xcodeproj -scheme $sampleName \ + -sdk iphonesimulator -configuration Release \ + -destination 'platform=iOS Simulator,name=iPhone 11,OS=<< parameters.ios >>' \ + clean build \ + CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO + done + +workflows: + workflow: + jobs: + - build-job: + matrix: + parameters: + xcode: ["15.0.0", "15.3.0"] + ios: ["15.0", "17.2"] + mac_runner: ["macos.m1.medium.gen1"] + context: + - 'SDK Registry Token' + - build-job: + name: "build-job-17.0-macos.x86.medium.gen2-15.1.0" + xcode: "15.1.0" + ios: "17.0" + mac_runner: "macos.x86.medium.gen2" + context: + - 'SDK Registry Token' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 317ce930672..9a162258a7d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ Examples/Swift/Navigation_Example.mobileprovision vendor/bundle/ruby/ .vscode .swiftpm +XCFrameworks/ +Package.resolved diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..a3cd85589c0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2519 @@ +# Changes to the Mapbox Navigation SDK for iOS + +## v3.0.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v11.3.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v11.3.0). +* MapboxNavigation now requires [MapboxCommon v24.3.1](https://github.com/mapbox/mapbox-common-ios/releases/tag/v24.3.1). +* MapboxCoreNavigation now requires [MapboxNavigationNative v305._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/305.0.0). + +## v2.18.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.16.5](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.16.5). ([#4605](https://github.com/mapbox/mapbox-navigation-ios/pull/4605)) +* MapboxCoreNavigation now requires [MapboxDirections v2.12.0](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.12.0). ([#4605](https://github.com/mapbox/mapbox-navigation-ios/pull/4605)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v202._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/202.0.0). ([#4605](https://github.com/mapbox/mapbox-navigation-ios/pull/4605)) +* MapboxCoreNavigation is no longer dependent on MapboxMobileEvents. ([#4572](https://github.com/mapbox/mapbox-navigation-ios/pull/4572)) +* Added a Polish localization. ([#4582](https://github.com/mapbox/mapbox-navigation-ios/pull/4582)) + +### Routing + +* `NavigationRouteOptions` and `NavigationMatchOptions` no longer include `.numericCongestionLevel` attribute by default for profiles other than `.automobileAvoidingTraffic`. ([#4564](https://github.com/mapbox/mapbox-navigation-ios/pull/4564)) +* Fixed an issue where the `.speedLimitKey` key in the `.passiveLocationManagerDidUpdate` notification contained `0` on roads with no speed limit. The value is now correctly set to `Double.infinity`. ([#4584](https://github.com/mapbox/mapbox-navigation-ios/pull/4584)) + +### Map + +* Fixed a possible crash that could happen when displaying the route with the same source, midpoint, and destination. ([#4576](https://github.com/mapbox/mapbox-navigation-ios/pull/4576)) +* Fixed an incorrect viewport padding in the overview route camera. ([#4593](https://github.com/mapbox/mapbox-navigation-ios/pull/4593)) + +### User interface + +* `SpeedLimitView` now shows a special "Limits no longer apply" sign on roads where speed limit is known to not exist. ([#4584](https://github.com/mapbox/mapbox-navigation-ios/pull/4584)) +* `TopBannerViewController.delegate` and `TopBannerViewController.instructionsBannerView` are now public. ([#4595](https://github.com/mapbox/mapbox-navigation-ios/pull/4595)) +* `BottomBannerViewController.dateFormatter`, `BottomBannerViewController.dateComponentsFormatter`, `BottomBannerViewController.distanceFormatter` and `InstructionsBannerView.distanceFormatter` are now public. ([#4595](https://github.com/mapbox/mapbox-navigation-ios/pull/4595)) + +### CarPlay + +* Added the ability to configure `CPMapTemplate.guidanceBackgroundColor` via delegate method. ([#4620](https://github.com/mapbox/mapbox-navigation-ios/pull/4620)) +* Added the ability to configure waypoints via `CarPlayManagerDelegate` object. ([#4606](https://github.com/mapbox/mapbox-navigation-ios/pull/4606)) + +### Other changes + +* Added PrivacyInfo.xcprivacy support. ([#4573](https://github.com/mapbox/mapbox-navigation-ios/pull/4573)) +* Removed `NavigationEventsManager.init(activeNavigationDataSource:passiveNavigationDataSource:accessToken:mobileEventsManager:)` in favor of `NavigationEventsManager.init(activeNavigationDataSource:passiveNavigationDataSource:accessToken:)`. ([#4572](https://github.com/mapbox/mapbox-navigation-ios/pull/4572)) +* Fixed a rare issue that could lead to memory corruption under specific conditions. This was resolved by replacing the internal image downloader with brand new actor-based implementation. ([#4588](https://github.com/mapbox/mapbox-navigation-ios/pull/4588)) +* Fixed the possible situation when the upcoming route leg is rendered above the active route leg. ([#4588](https://github.com/mapbox/mapbox-navigation-ios/pull/4588)) +* Fixed a main thread hang on NavigationViewController creation. ([#4617](https://github.com/mapbox/mapbox-navigation-ios/pull/4617)) +* Fixed error reporting in `RouteController/reroute(from:along:)`. ([#4618](https://github.com/mapbox/mapbox-navigation-ios/pull/4618)) + +## v2.17.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.16.1](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.16.1). ([#4557](https://github.com/mapbox/mapbox-navigation-ios/pull/4557)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v160._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/160.0.0). ([#4559](https://github.com/mapbox/mapbox-navigation-ios/pull/4559)) + +### CarPlay + +* Fixed behavior when completion was not called in case of an error in CarPlayManager. ([#4548](https://github.com/mapbox/mapbox-navigation-ios/pull/4548)) + +### Location tracking +* Improved ramp detection and reduced unexpected jumps between parallel elevated roads. ([#4557](https://github.com/mapbox/mapbox-navigation-ios/pull/4557)) +* Fixed false-positive "exiting the tunnel" mapmatching errors. ([#4557](https://github.com/mapbox/mapbox-navigation-ios/pull/4557)) + +## v2.16.0 + +### Packaging + +* MapboxNavigation now requires Xcode 14.1 or newer. ([#4537](https://github.com/mapbox/mapbox-navigation-ios/pull/4537)) +* MapboxCoreNavigation now requires [MapboxDirections v2.11.1](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.11.1). ([#4543](https://github.com/mapbox/mapbox-navigation-ios/pull/4543)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v157._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/157.0.0). ([#4543](https://github.com/mapbox/mapbox-navigation-ios/pull/4543)) +* MapboxNavigation now requires [MapboxMaps v10.16.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.16.0). ([#4543](https://github.com/mapbox/mapbox-navigation-ios/pull/4543)) + +### Other changes + +* Added filling jartic traffic codes info reported `Incident`s while navigating. ([#4524](https://github.com/mapbox/mapbox-navigation-ios/pull/4524)) +* Fixed initial pan gesture in CarPlay. ([#4534](https://github.com/mapbox/mapbox-navigation-ios/pull/4534)) + +## v2.15.0 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v148._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/148.0.0). ([#4518](https://github.com/mapbox/mapbox-navigation-ios/pull/4518)) +* MapboxNavigation now requires [MapboxMaps v10.15.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.15.0). ([#4518](https://github.com/mapbox/mapbox-navigation-ios/pull/4518)) + +### Routing +* Route request timeout errors are now considered failures as opposed to cancellations. `RouterDelegate.router(_:didFailToRerouteWith:)` will be called in this case. ([#4490](https://github.com/mapbox/mapbox-navigation-ios/pull/4490)) + +### CarPlay + +* Added new `CarPlayManagerDelegate.carPlayManagerWillCancelPreview(_:configuration:)` delegate method to allow for customization of route cancellation behavior. If `configuration.popToRoot` is `true`, the `popToRootTemplate` method is called to navigate to the root template. This change enhances the flexibility of route cancellation in CarPlay. ([#4495](https://github.com/mapbox/mapbox-navigation-ios/pull/4495)) +* Added `CarPlayMapViewController.userInfo` property to pass optional metadata to telemetry. ([#4503](https://github.com/mapbox/mapbox-navigation-ios/pull/4503)) + +### Electronic horizon + +**Note:** The Mapbox Electronic Horizon feature of the Mapbox Navigation SDK is in public beta and is subject to changes, including its pricing. Use of the feature is subject to the beta product restrictions in the Mapbox Terms of Service. Mapbox reserves the right to eliminate any free tier or free evaluation offers at any time and require customers to place an order to purchase the Mapbox Electronic Horizon feature, regardless of the level of use of the feature. +* Added `RoadObjectKind.unknown` for an unknown type of road object. ([#4490](https://github.com/mapbox/mapbox-navigation-ios/pull/4490)) + +### Other changes + +* Fixed an issue when starting `NavigationViewController` with injected `NavigationService` (for example via CarPlay) could result in alternative routes not showing on the map. ([#4489](https://github.com/mapbox/mapbox-navigation-ios/pull/4489)) +* Fixed an issue where the `EndOfRouteViewController` was not properly localized. ([#4494](https://github.com/mapbox/mapbox-navigation-ios/pull/4494)) +* Fix sending events to Native Telemetry on application termination. ([#4508](https://github.com/mapbox/mapbox-navigation-ios/pull/4508)) + +## v2.14.0 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v137._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/137.0.0). ([#4483](https://github.com/mapbox/mapbox-navigation-ios/pull/4483)) +* MapboxNavigation now requires [MapboxMaps v10.14.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.14.0). ([#4483](https://github.com/mapbox/mapbox-navigation-ios/pull/4483)) + +### CarPlay + +* Fixed an issue where starting navigation while connected to CarPlay but not having window active resulted in CarPlay view to be stuck at preview screen. ([#4477](https://github.com/mapbox/mapbox-navigation-ios/pull/4477)) +* Fixed an issue where maneuver arrow was not changing color following day/night style automatic toggling. ([#4482](https://github.com/mapbox/mapbox-navigation-ios/pull/4482)) + +### Routing +* Fixed an issue where `NavigationSettings.tileStoreConfiguration.navigatorLocation.tileStoreURL` was used as a base url for route refresh requests instead of `NavigationSettings.directions.credentials.host`. ([#4483](https://github.com/mapbox/mapbox-navigation-ios/pull/4483)) + +### Other changes + +* Optimized performance of route response parsing for reroutes, continuous alternatives and similar use-cases. ([#4462](https://github.com/mapbox/mapbox-navigation-ios/pull/4462)) +* Fixed inconsistent time difference callouts positions for alternative routes. ([#4473](https://github.com/mapbox/mapbox-navigation-ios/pull/4473)) +* Fixed an issue with too high alternative route requests frequency in case of only one route being present in the route response. ([#4483](https://github.com/mapbox/mapbox-navigation-ios/pull/4472)) +* Fixed an issue with positioning lag in tunnels. ([#4483](https://github.com/mapbox/mapbox-navigation-ios/pull/4472)) + +## v2.13.0 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v132._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/132.0.0). ([#4437](https://github.com/mapbox/mapbox-navigation-ios/pull/4437)) +* MapboxNavigation now requires [MapboxMaps v10.13.0-rc.1](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.13.0-rc.1). ([#4437](https://github.com/mapbox/mapbox-navigation-ios/pull/4437)) + +### Map + +* Fixed an issue with route callouts being slightly displaced. ([#4427](https://github.com/mapbox/mapbox-navigation-ios/pull/4427)) + +### Other changes + +* Added support for Native Telemetry `Navigator.startNavigationSession()` and `Navigator.stopNavigationSession()` for correct report of navigation session type to telemetry. ([#4435](https://github.com/mapbox/mapbox-navigation-ios/pull/4435)) +* Fixed a possible crash that could happen while configuring predictive cache before navigation started. ([#4444](https://github.com/mapbox/mapbox-navigation-ios/pull/4444)) + +## v2.12.0 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v130._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/130.0.0). ([#4417](https://github.com/mapbox/mapbox-navigation-ios/pull/4417)) +* MapboxCoreNavigation now requires [MapboxDirections v2.11.0-rc.1](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.11.0-rc.1). ([#4417](https://github.com/mapbox/mapbox-navigation-ios/pull/4417)) +* MapboxNavigation now requires [MapboxMaps v10.12.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.12.0). ([#4417](https://github.com/mapbox/mapbox-navigation-ios/pull/4417)) + +### Routing + +* Added an optional `userInfo` argument to the `NavigationService(indexedRouteResponse:customRoutingProvider:credentials:locationSource:eventsManagerType:simulating:routerType:customActivityType:userInfo:)` and `NavigationService(history:customHistoryEventsListener:customRoutingProvider:credentials:eventsManagerType:routerType:customActivityType:userInfo:)`. ([#4395](https://github.com/mapbox/mapbox-navigation-ios/pull/4395)) + +### Visual instructions + +* Fixed duplication of the road name components in the road shield and the label. ([#4401](https://github.com/mapbox/mapbox-navigation-ios/pull/4401)) +* Added support for localized road shields. ([#4401](https://github.com/mapbox/mapbox-navigation-ios/pull/4401)) +* Added `localizedRouteShieldRepresentationKey` to the user info dictionary of `Notification.Name.passiveLocationManagerDidUpdate` posted by `PassiveLocationManager`, and the `Notification.Name.currentRoadNameDidChange` posted by `RouteController`. The corresponding value contains localized route shield data. ([#4401](https://github.com/mapbox/mapbox-navigation-ios/pull/4401)) + +### Electronic horizon + +**Note:** The Mapbox Electronic Horizon feature of the Mapbox Navigation SDK is in public beta and is subject to changes, including its pricing. Use of the feature is subject to the beta product restrictions in the Mapbox Terms of Service. Mapbox reserves the right to eliminate any free tier or free evaluation offers at any time and require customers to place an order to purchase the Mapbox Electronic Horizon feature, regardless of the level of use of the feature. +* Added`Interchange.identifier` and `Junction.identifier` fields. ([#4396](https://github.com/mapbox/mapbox-navigation-ios/pull/4396)) + +### Map + +* Fixed an issue when `NavigationMapView` would not display a map, when using CarPlay and custom tile storage location. ([#4399](https://github.com/mapbox/mapbox-navigation-ios/pull/4399)) +* Fixed non displayed alternative routes for multi legs routes. ([#4404](https://github.com/mapbox/mapbox-navigation-ios/pull/4404)) + +### Camera + +* Fixes an issue where the camera's position was not calculated correctly when banners fully overlapped the map. ([#4400](https://github.com/mapbox/mapbox-navigation-ios/pull/4400)) + +### Other changes + +* Fixed an issue where `ReplayLocationManager` init with `History` removed all custom history events. ([#4403](https://github.com/mapbox/mapbox-navigation-ios/pull/4403)) +* Fixed a potential issue where negative remaining distance values could be displayed. ([#4402](https://github.com/mapbox/mapbox-navigation-ios/pull/4402)) +* Fixed a problem where certain parameters were not being sent for the 'navigation.cancel' telemetry event. ([#4413](https://github.com/mapbox/mapbox-navigation-ios/pull/4413)) + +## v2.11.0 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v126._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/126.0.0). ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) +* MapboxCoreNavigation now requires [MapboxDirections v2.10.0-rc.1](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.10.0-rc.1). ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) +* MapboxNavigation now requires [MapboxMaps v10.11.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.11.0). ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) + +### Visual instructions +* `MapboxRoadNameView` now renders localized road names. ([#4375](https://github.com/mapbox/mapbox-navigation-ios/pull/4375)) +* Added `localizedRoadNameKey` to the user info dictionary of `Notification.Name.passiveLocationManagerDidUpdate` posted by `PassiveLocationManager`, and the `Notification.Name.currentRoadNameDidChange` posted by `RouteController`. The corresponding string value contains localized road name. ([#4375](https://github.com/mapbox/mapbox-navigation-ios/pull/4375)) + +### Camera + +* Fixes an issue where the camera padding was not calculated correctly when the map view didn't take the whole screen. ([#4350](https://github.com/mapbox/mapbox-navigation-ios/pull/4350)) + +### CarPlay + +* Added `CarPlayManagerDelegate.carPlayManagerDidCancelPreview(_:)` to notify developers after CarPlay canceled routes preview, and `CarPlayManager.cancelRoutesPreview()` method to cancel routes preview on CarPlay. ([#4311](https://github.com/mapbox/mapbox-navigation-ios/pull/4311)) +* Added `CPRouteChoice.indexedRouteResponse` property to allow developers to get access to the `IndexedRouteResponse` of `CPRouteChoice` on CarPlay. ([#4311](https://github.com/mapbox/mapbox-navigation-ios/pull/4311)) +* Added the ability to pan a map view on CarPlay. ([#4288](https://github.com/mapbox/mapbox-navigation-ios/pull/4288)) +* Added a new configuration property `CarPlayManager.startFreeDriveAutomatically` that controls whether `CarPlayManager` starts a Free Drive session automatically on map load. If you set this property to false, you can start a Free Drive session using `CarPlayMapViewController.startFreeDriveNavigation()` method. ([#4352](https://github.com/mapbox/mapbox-navigation-ios/pull/4352)) +* Added new `CarPlayManagerDelegate` methods `carPlayManager(_:didBeginPanGesture:)`, `carPlayManager(_:didEndPanGesture:)`, `carPlayManager(_:didShowPanningInterface:)`, `carPlayManager(_:willDismissPanningInterface:)`, and `carPlayManager(_:didDismissPanningInterface:)` to notify about pan gesture events. ([#4368](https://github.com/mapbox/mapbox-navigation-ios/pull/4368)) +* Added `CarPlayManagerDelegate.carPlayManager(_:willPresent:)` method to allow developers to query or customize properties of the `CarPlayNavigationViewController` before it is presented. ([#4376](https://github.com/mapbox/mapbox-navigation-ios/pull/4376)) + +### Electronic horizon + +**Note:** The Mapbox Electronic Horizon feature of the Mapbox Navigation SDK is in public beta and is subject to changes, including its pricing. Use of the feature is subject to the beta product restrictions in the Mapbox Terms of Service. Mapbox reserves the right to eliminate any free tier or free evaluation offers at any time and require customers to place an order to purchase the Mapbox Electronic Horizon feature, regardless of the level of use of the feature. + +* `RoadName` type changed from enum to struct with additional properties. ([#4333](https://github.com/mapbox/mapbox-navigation-ios/pull/4333)) +* Electronic Horizon Notifications (`Notification.Name.electronicHorizonDidUpdatePosition`, `Notification.Name.electronicHorizonDidEnterRoadObject`, `Notification.Name.electronicHorizonDidExitRoadObject`, `Notification.Name.electronicHorizonDidPassRoadObject`) are now called on the main thread. ([#4333](https://github.com/mapbox/mapbox-navigation-ios/pull/4333)) +* Added `RoadObjectKind.ic` and `RoadObjectKind.jct` for interchanges and junctions and the corresponding structs `Interchange` and `Junction`. ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) + +### Location tracking + +* Fixed a possible crash that could happen during route simulation. ([#4366](https://github.com/mapbox/mapbox-navigation-ios/pull/4366)) + +### Other changes + +* Added log messages about trip session events. ([#4363](https://github.com/mapbox/mapbox-navigation-ios/pull/4363)) +* Fixed an issue where an incorrect upcoming intersection index cause a crash. ([#4314](https://github.com/mapbox/mapbox-navigation-ios/pull/4314)) +* Fixed an issue where `RouteProgress.currentLegProgress.currentStepProgress.userDistanceToUpcomingIntersection` could be incorrectly calculated for folding back route steps. ([#4268](https://github.com/mapbox/mapbox-navigation-ios/pull/4268)) +* Ensure map-matching considers HOV-only roads as auto accessible. ([#4333](https://github.com/mapbox/mapbox-navigation-ios/pull/4333)) +* Added `ReplayManagerHistoryEventsListener` to receive events feed when replaying a `History` data. ([#4342](https://github.com/mapbox/mapbox-navigation-ios/pull/4342)) +* `UserPushedHistoryEvent` is now public. ([#4342](https://github.com/mapbox/mapbox-navigation-ios/pull/4342)) +* Fixed `NavigationViewController` instantiation from the Storyboard. ([#4356](https://github.com/mapbox/mapbox-navigation-ios/pull/4356)) +* Fixed a possibly broken roundabout maneuver icon for extremely sharp turn. ([#4359](https://github.com/mapbox/mapbox-navigation-ios/pull/4359)) +* Fixed not working Speech generation if no navigation session started. ([#4362](https://github.com/mapbox/mapbox-navigation-ios/pull/4362)) +* Limited number of reported alternatives to 2, i.e. the `updatedAlternatives` parameter in `RouterDelegate.router(_:didUpdateAlternatives:removedAlternatives:)` has maximum size of 2. ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) +* Increased terminal offboard route request timeout from 4 to 15 seconds. ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) +* Sped up onboard routing cancellation. ([#4367](https://github.com/mapbox/mapbox-navigation-ios/pull/4367)) +* Fixed an issue when a rerouting could cause a memory leak. ([#4380](https://github.com/mapbox/mapbox-navigation-ios/pull/4380)) +* Fixed usage of real GPS locations in simulated routes ([#4394](https://github.com/mapbox/mapbox-navigation-ios/pull/4394)) + +## v2.10.0 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v123._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/123.2.0). ([#4331](https://github.com/mapbox/mapbox-navigation-ios/pull/4331)) +* MapboxNavigation now requires [MapboxMaps v10.10._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.10.1). ([#4315](https://github.com/mapbox/mapbox-navigation-ios/pull/4315)) +* MapboxCoreNavigation now requires [MapboxDirections v2.9.1](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.9.1). ([#4336](https://github.com/mapbox/mapbox-navigation-ios/pull/4336)) +* Cocoapods podspec for MapboxCoreNavigation now references resources that will be copied into the application. ([#4280](https://github.com/mapbox/mapbox-navigation-ios/pull/4280)) + +### Routing + +* Added `RouterDelegate.router(:shouldProactivelyRerouteFrom:to:completion)`, `NavigationServiceDelegate.navigationService(:shouldProactivelyRerouteFrom:to:completion)` and `NavigationViewControllerDelegate.navigationViewController(:shouldProactivelyRerouteFrom:to:completion)` methods to inform and providing control over each individual proactive rerouting attempt. ([#4229](https://github.com/mapbox/mapbox-navigation-ios/pull/4229)) +* Added `RouteController.updateRouteLeg(to:completionHandler:)` method to allow switching route legs arbitrarily. ([#4261](https://github.com/mapbox/mapbox-navigation-ios/pull/4261)) +* Predictive cache optimization for reducing memory and CPU consumption on very long and complex routes. ([#4283](https://github.com/mapbox/mapbox-navigation-ios/pull/4283)) +* Fixed reset of DR driving out of the tunnel for a brief moment. ([#4283](https://github.com/mapbox/mapbox-navigation-ios/pull/4283)) +* Fix the issue where continuous alternative routes are not vanishied correctly. ([#4283](https://github.com/mapbox/mapbox-navigation-ios/pull/4283)) +* Fixed an issue where switching to a coincident online route sometimes resulted in using a route with different geometry than the original one. ([#4305](https://github.com/mapbox/mapbox-navigation-ios/pull/4305)) + +### Map + +* The maneuver arrow now extends 50 points along the route before and after an intersection, compared to 30 points previously. ([#4230](https://github.com/mapbox/mapbox-navigation-ios/pull/4230)) +* Fixed issue with simultaneous recognition of tap gesture. ([#4283](https://github.com/mapbox/mapbox-navigation-ios/pull/4283)) +* Fixed label localization to properly handle Simplified and Traditional Chinese. ([#4283](https://github.com/mapbox/mapbox-navigation-ios/pull/4283)) +* Allow simultaneous recognition of map- and annotation- handling gesture recognizers. ([#4283](https://github.com/mapbox/mapbox-navigation-ios/pull/4283)) +* Fixed an issue where text in the route duration annotation was not centered correctly on devices with different screen sizes. ([#4130](https://github.com/mapbox/mapbox-navigation-ios/pull/4130)) +* Added `CarPlayManagerDelegate.carPlayManager(_:willAdd:for:)`, `NavigationMapViewDelegate.navigationMapView(_:willAdd:)` and `NavigationViewControllerDelegate.navigationViewController(_:willAdd:)` to modify the properties of the default layer which will be added to the map view during navigation. ([#4277](https://github.com/mapbox/mapbox-navigation-ios/pull/4277)) +* Fixed issue where the traversed route layer doesn't share the same width with the main route casing layer after developers providing their own layer or midfying the layer properties. ([#4277](https://github.com/mapbox/mapbox-navigation-ios/pull/4277)) +* Added `NavigationMapView.showcase(_:routesPresentationStyle:legIndex:animated:duration:completion:)` and `NavigationMapView.show(_:layerPosition:legIndex:)` methods to draw `IndexedRouteResponse` data and populate view's `routes` and `continuousAlternatives` properties accordingly. ([#4294](https://github.com/mapbox/mapbox-navigation-ios/pull/4294)) +* Fixed an issue where map wouldn't be loaded in active navigation session on CarPlay. ([#4315](https://github.com/mapbox/mapbox-navigation-ios/pull/4315)) + +### Location tracking + +* Fixed a rare crash that could happen during route simulation. ([#4153](https://github.com/mapbox/mapbox-navigation-ios/pull/4153)) + +### CarPlay + +* Added the ability to display a junction image for the maneuver on CarPlay. ([#4324](https://github.com/mapbox/mapbox-navigation-ios/pull/4324)) + +### Other changes + +* Fixed potential issue when rerouting and route refreshing happen simultaneously which could lead to old route restoration or even a crash. ([#4238](https://github.com/mapbox/mapbox-navigation-ios/pull/4238)) +* Fixed an issue where the route progress could be incorrectly calculated for folding back route steps. ([#4234](https://github.com/mapbox/mapbox-navigation-ios/pull/4234)) +* `NavigationView.init(frame:tileStoreLocation:navigationMapView:)`, `NavigationView.navigationMapView`, `NavigationView.floatingStackView`, `NavigationView.floatingButtons`, `NavigationView.wayNameView`, `NavigationView.speedLimitView`, `NavigationView.topBannerContainerView` and `NavigationView.bottomBannerContainerView` are now publicly accessible. ([#4249](https://github.com/mapbox/mapbox-navigation-ios/pull/4249)) +* Fixed an issue where empty intersections of the current step could cause a crash. ([#4260](https://github.com/mapbox/mapbox-navigation-ios/pull/4260)) +* Deprecated `NavigationSettings.initialize(directions:tileStoreConfiguration:routingProviderSource:alternativeRouteDetectionStrategy:utilizeSensorData:navigatorPredictionInterval:liveIncidentsOptions:statusUpdatingSettings:)` method in favor of `NavigationSettings.initialize(with:)`. ([#4275](https://github.com/mapbox/mapbox-navigation-ios/pull/4275)) +* Added new parameter that allows configuring logging level for Mapbox SDKs. Checkout new `NavigationSettings.initialize(with:)` method for more information. ([#4275](https://github.com/mapbox/mapbox-navigation-ios/pull/4275)) +* Fixed an issue where the `UserHaloCourseView` will be shown under reduced location accuracy mode with `NavigationMapview.reducedAccuracyActivatedMode` as `false`. Right now `UserHaloCourseView` will be applied in only one case: when user explicitly sets `NavigationMapView.reducedAccuracyActivatedMode` to `true`, and the `Precise Location` property in the settings of current application is disabled by user. ([#4285](https://github.com/mapbox/mapbox-navigation-ios/pull/4285)) +* Fixed an issue where `ExitView` used dark style when using InstructionCardViewController instead of light style for both highlighted and default states of the instruction card. ([#4160](https://github.com/mapbox/mapbox-navigation-ios/pull/4160)) +* Added `ExitView.highlightColor` and `GenericShield.highlightColor` properties that allow users to customize the highlight color of `ExitView` and `GenericShield`s to better fit their application `Style`. ([#4160](https://github.com/mapbox/mapbox-navigation-ios/pull/4160)) +* `SimulatedLocationManager`'s initializer `SimulatedLocationManager.init(route:currentDistance:currentSpeed:)` is now public. ([#4276](https://github.com/mapbox/mapbox-navigation-ios/pull/4276)) +* Added a console message when a newer version of Navigation SDK is available. ([#4280](https://github.com/mapbox/mapbox-navigation-ios/pull/4280)) +* Fixed an issue where `Bundle.string(forMapboxNavigationInfoDictionaryKey:)` and `Bundle.string(forMapboxCoreNavigationInfoDictionaryKey` returned values from the application bundle instead of the Navigation SDK when statically linking using Cocoapods. ([#4280](https://github.com/mapbox/mapbox-navigation-ios/pull/4280)) +* Added `IndexedRouteReponse.parseAlternativeRoutes` method to extract `AlternativeRoute`s data from a response. ([#4294](https://github.com/mapbox/mapbox-navigation-ios/pull/4294)) + +## v2.9.0 + +### Packaging + +* This library now requires a minimum deployment target of iOS 12.0 or above. iOS 11._x_ is no longer supported. ([#4142](https://github.com/mapbox/mapbox-navigation-ios/pull/4142)) +* This library now requires a minimum Xcode version of 13.1.0 or above. ([#4239](https://github.com/mapbox/mapbox-navigation-ios/pull/4239)) +* MapboxCoreNavigation now requires [MapboxDirections v2.8._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.8.0). ([#4251](https://github.com/mapbox/mapbox-navigation-ios/pull/4251)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v119._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/119.0.2). ([#4239](https://github.com/mapbox/mapbox-navigation-ios/pull/4239)) +* MapboxNavigation now requires [MapboxSpeech v2._x_](https://github.com/mapbox/mapbox-speech-swift/releases/tag/v2.1.0). ([#4142](https://github.com/mapbox/mapbox-navigation-ios/pull/4142)) +* MapboxNavigation now requires [MapboxMaps v10.9._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.9.1). ([#4239](https://github.com/mapbox/mapbox-navigation-ios/pull/4239)) + +### Map + +* Traffic lights, stop signs, yield signs, and railroad crossings now appear along the route during turn-by-turn navigation. To disable these icons, set the `NavigationViewController.annotatesIntersectionsAlongRoute` and `CarPlayNavigationViewController.annotatesIntersectionsAlongRoute` properties to `false`. ([#4185](https://github.com/mapbox/mapbox-navigation-ios/pull/4185)) +* `NavigationMapView.removeAlternativeRoutes()` and `NavigationMapView.removeContinuousAlternativeRoutesDurations()` were made public to provide a way to remove previously shown alternative routes and alternative routes duration annotations, respectively. ([#4134](https://github.com/mapbox/mapbox-navigation-ios/pull/4134)) +* Fixed an issue where tapping on a route duration annotation that overlaps a different route would cause the wrong route to be passed into `NavigationMapViewDelegate.navigationMapView(_:didSelect:)` or `NavigationMapViewDelegate.navigationMapView(_:didSelect:)`. ([#4133](https://github.com/mapbox/mapbox-navigation-ios/pull/4133)) +* Fixed an issue where the shields in the instruction are using the style from last navigation session with the `NavigationMapView` injection used in the new session. ([#4197](https://github.com/mapbox/mapbox-navigation-ios/pull/4197)) +* Fixed an issue where the `NavigationMapView.localizeLabels()` method only localized map labels according to the user’s Preferred Language Order setting if the application also had a localization in the preferred language. ([#4205](https://github.com/mapbox/mapbox-navigation-ios/pull/4205)) +* Additional parameters were added to `FloatingButton.rounded(image:selectedImage:size:type:imageEdgeInsets:cornerRadius)` to be able to provide button type, button image edge insets and corner radius. ([#4060](https://github.com/mapbox/mapbox-navigation-ios/pull/4060), [#4157](https://github.com/mapbox/mapbox-navigation-ios/pull/4157)) +* `FloatingButton` no longer contains corner radius shadow, border is applied instead. ([#4060](https://github.com/mapbox/mapbox-navigation-ios/pull/4060)) +* Added the `NavigationViewControllerDelegate.navigationViewController(_:didSelect:)` and `NavigationViewControllerDelegate.navigationViewController(_:didSelect:)` methods that allow selection of the waypoint and continuous alternative. ([#4175](https://github.com/mapbox/mapbox-navigation-ios/pull/4175)) +* `NavigationMapView.showcase(_:routesPresentationStyle:legIndex:animated:duration:completion:)` now contains a `legIndex` parameter that allows highlighting one leg more prominently than other legs of the route. ([#4211](https://github.com/mapbox/mapbox-navigation-ios/pull/4211)) +* Fixed an issue where the route line with no traffic congestion data and multiple legs wasn't shown correctly. ([#4217](https://github.com/mapbox/mapbox-navigation-ios/pull/4217)) +* Fixed a crash when setting the `NavigationMapView.userLocationStyle` property to `UserLocationStyle.puck3D`. ([#4239](https://github.com/mapbox/mapbox-navigation-ios/pull/4239)) + +### Preview + +* Added the `PreviewViewController` that along with the ability to display a route preview map allows to present banners with additional information. Such banners should conform to `Banner` protocol. The Mapbox Navigation SDK also provides default banners that allow to present address of the final destination (`DestinationPreviewViewController`) and route information like estimated time of arrival, total duration and distance (`RoutePreviewViewController`). The `PreviewViewControllerDelegate` protocol allows to observe `Banner` presentation and dismissal events. Seamless transition between `PreviewViewController` and `NavigationViewController` can be reached by using `UIViewControllerTransitioningDelegate` and replacing existing `NavigationViewController.navigationMapView` instance with the one that is used in `PreviewViewController`. ([#4227](https://github.com/mapbox/mapbox-navigation-ios/pull/4227), [#4188](https://github.com/mapbox/mapbox-navigation-ios/pull/4188)) + +### Banners and guidance instructions + +* Added replacement for `VisualInstruction.maneuverImageSet(side:)` method to generate a maneuver image on iOS 13 and above. ([#4161](https://github.com/mapbox/mapbox-navigation-ios/pull/4161)) +* Road shield images are now cached and re-used across multiple application sessions. ([#3930](https://github.com/mapbox/mapbox-navigation-ios/pull/3930)) +* Fixed an issue where the CarPlay style change would affect the style of Mapbox designed shields on mobile. ([#3930](https://github.com/mapbox/mapbox-navigation-ios/pull/3930)) +* Fixed an issue where the Mapbox designed shields and generic shields have different sizes in instruction banner. ([#3930](https://github.com/mapbox/mapbox-navigation-ios/pull/3930)) +* Turn lane indications now appear even if they slightly differ from what the routing engine would have inferred from the road geometry, For example, turn lanes now appear where the user is expected to use a lane marked as as a right turn lane to make a slight right turn. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Route shields now respect language-specific route numbers in Japan. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Improved the timing of some spoken instructions. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where the current road name label appeared even while the user is not traveling on a known road. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where top and bottom banners were not presented when starting active navigation session. ([#4222](https://github.com/mapbox/mapbox-navigation-ios/pull/4222)) + +### Location tracking + +* Fixed an issue where the user’s location history was sometimes matched to unnavigable paths, leading to unreliable location snapping. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where the `RoadObjectMatcher.matchOpenLR(location:identifier:)` method would incorrectly match some TPEG OpenLR identifiers. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Added `HistoryReader` for parsing history files. ([#4194](https://github.com/mapbox/mapbox-navigation-ios/pull/4194)) + +### Routing + +* `IndexedRouteResponse` is now the preferred way for setting up routing information for navigation. `NavigationViewController`, `MapboxNavigationService`, `Router` and `RoutingProvider` are updated to accomodate this change. ([#4127](https://github.com/mapbox/mapbox-navigation-ios/pull/4127)) +* Added the `RouteController.prefersOnlineRoute` property, which lets you automatically switch from a route generated on the device to one generated by the Mapbox Directions API if the geometries match. Use `NavigationViewControllerDelegate.navigationViewController(_:didSwitchToCoincidentOnlineRoute:)`, `NavigationServiceDelegate.navigationService(_:didSwitchToCoincidentOnlineRoute:)`, `RouterDelegate.router(_:didSwitchToCoincidentOnlineRoute:)` or `.routeControllerDidSwitchToCoincidentOnlineRoute` notification to track such events. ([#4127](https://github.com/mapbox/mapbox-navigation-ios/pull/4127)) +* Added the `NavigationViewController(for:routeIndex:navigationOptions:)` initializer to start turn-by-turn navigation using map matching response. ([#4127](https://github.com/mapbox/mapbox-navigation-ios/pull/4127)) +* Fixed an issue where continuous alternative route lines and their corresponding callouts were misplaced on long routes. ([#4176](https://github.com/mapbox/mapbox-navigation-ios/pull/4176)) +* Added `ReplayLocationManager(history:)` and `MapboxNavigationService(history:customRoutingProvider:credentials:eventsManagerType:routerType:customActivityType:)` for replaying trips recorded by a history file. ([#4194](https://github.com/mapbox/mapbox-navigation-ios/pull/4194)) +* Fixed an issue where after route refresh, the `RouteStepProgress.userDistanceToUpcomingIntersection`, `RouteStepProgress.intersectionsIncludingUpcomingManeuverIntersection`, `RouteStepProgress.intersectionDistances` and `RouteStepProgress.intersectionIndex` are all set to default values. ([#4193](https://github.com/mapbox/mapbox-navigation-ios/pull/4193)) +* Route refreshing now respects current user progress on a leg to reduce update size and improve updating longer routes. ([#4111](https://github.com/mapbox/mapbox-navigation-ios/pull/4111)) +* Added `RoutingProvider.refreshRoute(indexedRouteResponse:fromLegAtIndex:routeShapeIndex:legShapeIndex:completionHandler:)` to request a refresh starting from specified shape index. Updated `RouteLegProgress` and `RouteProgress` initializers to include shape indices, and added `RouteProgress.refreshRoute(with:at:legIndex:legShapeIndex:)` to apply partial route refresh. ([#4111](https://github.com/mapbox/mapbox-navigation-ios/pull/4111)) +* Fixed an issue where some alternative routes did not begin at the user’s current location or did not end at the same location as the main route. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where some continuous alternative routes were unavailable or not consistently available when the user is traveling at low speed. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where the values of `RouteLeg.segmentDistances` and `RouteLeg.expectedTravelTime` did not add up to `RouteLeg.distance` and `RouteLeg.expectedTravelTime`, respectively. Each value of `RouteLeg.expectedTravelTime` that immediately follows an intersection now includes the time required to traverse the intersection. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where some [rat runs](https://en.wikipedia.org/wiki/Rat_running) were suggested as alternative routes that matched the main route. These alternative routes are no longer suggested at all. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where routes avoided roads with the deprecated tags [`hov=lane`](https://taginfo.openstreetmap.org/tags/hov=lane) and `hov:conditional=lane @ …` as restricted roads. ([#4191](https://github.com/mapbox/mapbox-navigation-ios/pull/4191)) +* Fixed an issue where the user’s location would get out of sync after traveling through short tunnels. ([#4239](https://github.com/mapbox/mapbox-navigation-ios/pull/4239)) +* Fixed a crash after changing `RouteController.prefersOnlineRoute` from `false` to `true`. ([#4239](https://github.com/mapbox/mapbox-navigation-ios/pull/4239)) + +### User feedback + +* The MapboxMobileEvents dependency is no longer used. Feedback events are now handled by MapboxCommon. ([#4011](https://github.com/mapbox/mapbox-navigation-ios/pull/4011)) +* Deprecated `NavigationEventsManager.init(activeNavigationDataSource:passiveNavigationDataSource:accessToken:mobileEventsManager:)` in favor of `NavigationEventsManager.init(activeNavigationDataSource:passiveNavigationDataSource:accessToken:)`. ([#4011](https://github.com/mapbox/mapbox-navigation-ios/pull/4011)) + +### Predictive caching + +* Implemented predictive cache with `TilesetDescriptor` so that volatile sources are not loaded unexpectedly. ([#4213](https://github.com/mapbox/mapbox-navigation-ios/pull/4213)) +* Deprecated `PredictiveCacheManager.init(predictiveCacheOptions:styleSourcePaths:)` and `PredictiveCacheManager.init(predictiveCacheOptions:mapOptions:)` in favor of `PredictiveCacheManager.init(predictiveCacheOptions:cacheMapOptions:)`. ([#4213](https://github.com/mapbox/mapbox-navigation-ios/pull/4213)) +* Added `PredictiveCacheMapsOptions` (map specific, that also allow to specify zoom levels for which the map tiles should be cached) and `PredictiveCacheNavigationOptions` (navigation specific) available through the `PredictiveCacheOptions`. ([#4213](https://github.com/mapbox/mapbox-navigation-ios/pull/4213)) +* Deprecated `PredictiveCacheOptions.currentLocationRadius`, `PredictiveCacheOptions.routeBufferRadius`, `PredictiveCacheOptions.destinationLocationRadius`, `PredictiveCacheOptions.maximumConcurrentRequests`. Use `PredictiveCacheOptions.predictiveCacheNavigationOptions` and `PredictiveCacheOptions.predictiveCacheMapsOptions` instead for separate predictive cache configuration for maps and navigation. ([#4213](https://github.com/mapbox/mapbox-navigation-ios/pull/4213)) +* Added `PredictiveCacheManager.updateMapControllers(cacheMapOptions:)` for cashing map styles after they are loaded. ([#4213](https://github.com/mapbox/mapbox-navigation-ios/pull/4213)) + +### Other changes + +* Added `NavigationViewController.usesNightStyleInDarkMode` property to control whether night style is used in dark mode. ([#4143](https://github.com/mapbox/mapbox-navigation-ios/pull/4143)) +* Fixed an issue where the rerouting audio cue stopped background audio. ([#3642](https://github.com/mapbox/mapbox-navigation-ios/pull/3642)) +* Fixed an issue where the rerouting audio cue played even if `RouteVoiceController.playRerouteSound` was set to `false`. ([#4214](https://github.com/mapbox/mapbox-navigation-ios/pull/4214)) +* Added `BorderCrossing.init(from:to:)` to allow creation of `BorderCrossing` publicly. ([#4226](https://github.com/mapbox/mapbox-navigation-ios/issues/4226)) + +## v2.8.1 + +* Fixed an issue where creating a `RouteController` with the result of `RouteResponse(matching:options:credentials:)` would cause route progress and guidance instructions to remain stuck at the beginning of the route. ([#4186](https://github.com/mapbox/mapbox-navigation-ios/pull/4186)) + +## v2.8.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.8._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.8.1). ([#4144](https://github.com/mapbox/mapbox-navigation-ios/pull/4144)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v115._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/115.0.0). ([#4144](https://github.com/mapbox/mapbox-navigation-ios/pull/4144)) +* MapboxCoreNavigation now requires [MapboxDirections v2.7._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.7.0). ([#4181](https://github.com/mapbox/mapbox-navigation-ios/pull/4181)) + +### Location tracking + +* Added `customActivityType` to `MapboxNavigationService` initialization to allow overriding default activity type for location updates during this navigation session. Changed default activity type from `automotiveNavigation` to `otherNavigation` for `.automobile` and `.automobileAvoidingTraffic` profiles. ([#4068](https://github.com/mapbox/mapbox-navigation-ios/pull/4068)) +* Added `NavigationSettings.navigatorPredictionInterval` to control how far ahead Navigator will predict user current position. ([#4072](https://github.com/mapbox/mapbox-navigation-ios/pull/4072)) +* Added the `RoadGraph.Edge.Metadata.isUrban` and `RoadObject.isUrban` properties and accompanying convenience initializers to indicate whether the edge or road object is in an urban area. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where some incidents in Japan were associated with two disconnected road edges, causing the `RoadGraph.Path` in `RoadObject.Location.openLRLine(path:shape:)` to have the wrong `RoadGraph.Path.edgeIdentifiers`. ([valhalla/valhalla#3667](https://github.com/valhalla/valhalla/issues/3667), [#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where the user location couldn't be determined on iOS 13 and older versions. ([#4113](https://github.com/mapbox/mapbox-navigation-ios/issues/4113)) + +### Map + +* Fixed an issue where the route line layer appears above point of interest labels. ([#4062](https://github.com/mapbox/mapbox-navigation-ios/pull/4062)) +* Fixed an issue where the destination building failed to highlight if the user has gotten rerouted at any time during the trip. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where the map would cut off a continuous alternative route to appear as if it began after the deviation point. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where the callout annotating a continuous alternative route appeared far away from the route and contained an inaccurate travel time. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where some roads were shown as restricted on the route line even if public access is allowed for “local traffic only”. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where the `NavigationMapView.traversedRouteColor` property had no effect on the traversed part of the route line. ([#4106](https://github.com/mapbox/mapbox-navigation-ios/pull/4106)) + +### Guidance instructions + +* Fixed an issue where the top banner and current road name label represented Mexican state highways with generic shields. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where the route would instruct the user to make a “U-turn” toward the passenger side wherever the user should actually make two successive turns toward the passenger side or take an exit ramp that curves 180°. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* `JunctionView` now appears after passing some toll booths or electronic toll collection points in Japan. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Improved the pronunciation of junction names in Japanese in Japan. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* At a fork or exit on an expressway in Japan, spoken instructions now mention the junction name and side of the road but no longer mention the expressway name or number that the user would stay on. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed confusing instructions to take the roundabout in the Russian localization. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed the crashes occured in guidance instructions during offline navigation. ([#4147](https://github.com/mapbox/mapbox-navigation-ios/pull/4147)) + +### Routing + +* After a fork in the road, if the user takes a different road than expected, RouteController now recognizes the actual road the user took more quickly than before. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed an issue where a route would U-turn outside the destination parking lot, avoiding a more direct parking lot entrance. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* If `RouteOptions.departAt` or `RouteOptions.arriveBy` is set, the resulting route now respects turn restrictions that depend on the date or time. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Eliminated the time penalty that was applied to barriers such as gates and border crossings, which was redundant to the effective time penalty from predicted speeds around the barrier. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* A multi-leg route that crosses an international border can now have alternative routes. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Curvy roads are penalized slightly more consistently. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* You can now set `Waypoint.allowsSnappingToStaticallyClosedRoad` to `true` to allow the waypoint to snap to a road that is fully closed for long-term construction. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Added `NavigationSettings.liveIncidentsOptions` to configure how incidents data is fetched. ([#4088](https://github.com/mapbox/mapbox-navigation-ios/pull/4088)) +* Added `NavigationSettings.statusUpdatingSettings` to configure navigator status polling options. ([#4135](https://github.com/mapbox/mapbox-navigation-ios/pull/4135)) +* Added `RouterDelegate.router(_:modifiedOptionsForReroute:)`, `NavigationServiceDelegate.navigationService(_:modifiedOptionsForReroute:)` and `NavigationViewControllerDelegate.navigationViewController(_:modifiedOptionsForReroute:)` methods to allow `RouteOptions` customization on reroutes. ([#4102](https://github.com/mapbox/mapbox-navigation-ios/pull/4102)) +* Fixed incorrect duration calculations and route refreshing when an arrival step’s geometry contained only one coordinate. Normally, an arrival step’s geometry is expected to be a zero-length `LineString`; that is, with two coincident coordinates. ([#4110](https://github.com/mapbox/mapbox-navigation-ios/pull/4110)) +* Routes now respect conditional access restrictions that depend on the year. ([#4144](https://github.com/mapbox/mapbox-navigation-ios/pull/4144)) +* Routes now respect conditional access restrictions that apply to [all vehicles](https://wiki.openstreetmap.org/wiki/Key:vehicle). ([#4144](https://github.com/mapbox/mapbox-navigation-ios/pull/4144)) +* Fixed an issue where the `Intersection.outletRoadClasses` and `Intersection.outletMapboxStreetsRoadClass` properties were set to `RoadClasses.restricted` for an entrance to a rest area because of its “[local traffic only](https://wiki.openstreetmap.org/wiki/Tag:access%3Ddestination)” restriction. ([#4144](https://github.com/mapbox/mapbox-navigation-ios/pull/4144)) +* Fixed an issue where continuous alternative time travel delta was displayed as 0 in a callout after manually switching to an alternative route. ([#4177](https://github.com/mapbox/mapbox-navigation-ios/pull/4177)) + +### CarPlay + +* Fixed an issue where navigation camera viewport padding was not taking into account `MapView` safe area insets on CarPlay. ([#4098](https://github.com/mapbox/mapbox-navigation-ios/pull/4098)) + +### Other changes + +* When launching the application, any stray files left over from old canceled offline tile downloads are cleaned up automatically to save storage space. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085)) +* Fixed a “dereference error” when passing certain OpenLR identifiers into the `RoadObjectMatcher.matchOpenLR(location:identifier:)` method. ([#4110](https://github.com/mapbox/mapbox-navigation-ios/pull/4110)) +* Fixed an issue where the `RoadObjectMatcher.matchOpenLR(location:identifier:)` method sometimes returned the wrong parallel roadway. ([#4110](https://github.com/mapbox/mapbox-navigation-ios/pull/4110)) +* Removed the `Hashable`-conforming extension for `CLLocationCoordinate2D` in `MapboxCoreNavigation` to fix a compiler error in applications that define their own `Hashable` conformance for this type. ([#4109](https://github.com/mapbox/mapbox-navigation-ios/pull/4109)) +* Fixed the crash that sometimes occurs when orientation of the view controller that contains `NavigationView` is being changed and `NavigationView`'s parent view is being deallocated at the same time. ([#4118](https://github.com/mapbox/mapbox-navigation-ios/pull/4118)) + +## 2.7.3 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v111._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/111.0.2). ([#4255](https://github.com/mapbox/mapbox-navigation-ios/pull/4255)) +* This release of MapboxNavigation requires MapboxDirections v2.7._x_ to prevent an iOS 11 support removal issue. If you use Carthage, it requires MapboxDirections v2.7.1 exactly. ([#4255](https://github.com/mapbox/mapbox-navigation-ios/pull/4255)) + +## v2.7.2 + +* Removed the `Hashable`-conforming extension for `CLLocationCoordinate2D` in `MapboxCoreNavigation` to fix a compiler error in applications that define their own `Hashable` conformance for this type. ([#4109](https://github.com/mapbox/mapbox-navigation-ios/pull/4109)) +* Fixed an issue where the user location couldn't be determined on iOS 13 and older versions. ([#4113](https://github.com/mapbox/mapbox-navigation-ios/issues/4113)) +* Fixed an issue where the `NavigationMapView.traversedRouteColor` property had no effect on the traversed part of the route line. ([#4106](https://github.com/mapbox/mapbox-navigation-ios/pull/4106)) + +## v2.7.1 + +* Added `NavigationSettings.liveIncidentsOptions` to configure how incidents data is fetched. ([#4088](https://github.com/mapbox/mapbox-navigation-ios/pull/4088)) + +## v2.7.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.7._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.7.0). ([#4044](https://github.com/mapbox/mapbox-navigation-ios/pull/4044)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v111._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/111.0.0). ([#4044](https://github.com/mapbox/mapbox-navigation-ios/pull/4044)) + +### Routing + +* Fixed lost target and name fields in waypoints after rerouting, and the bearing calculation error during tunnel dead reckoning. ([#4044](https://github.com/mapbox/mapbox-navigation-ios/pull/4044)) + +### Map + +* Fixed `MapView` rendering issues that occur after the application returns to the foreground. ([#1402](https://github.com/mapbox/mapbox-maps-ios/pull/1402)) +* Each alternative route shown during turn-by-turn navigation is now annotated with the amount of time it saves or adds to the trip. To hide these annotations, set the `NavigationMapView.showsRelativeDurationOnContinuousAlternativeRoutes` property to `false`. ([#3956](https://github.com/mapbox/mapbox-navigation-ios/pull/3956)) +* Fixed the issue where the route line endpoint is ahead of user location indicator on short straight-line route step when `NavigationViewController.routeLineTracksTraversal` enabled in active navigation. ([#3992](https://github.com/mapbox/mapbox-navigation-ios/pull/3992)) +* Added the ability to provide duration and completion handler while visualizing routes using `NavigationMapView.showcase(_:animated:duration:completion:)`. ([#4022](https://github.com/mapbox/mapbox-navigation-ios/pull/4022)) +* Fixed an issue where the maneuver arrow is not removed after arriving to the final destination. ([#4040](https://github.com/mapbox/mapbox-navigation-ios/pull/4040)) +* Fixed an issue where the destination building is not highlighted after rerouting. ([#4034](https://github.com/mapbox/mapbox-navigation-ios/pull/4034)) +* Fixed an issue where the incorrect destination building is highlighted after panning the correct building off screen. ([#4034](https://github.com/mapbox/mapbox-navigation-ios/pull/4034)) +* Fixed an issue where the maneuver arrow on the route line overlapped labels for points of interest. ([#4030](https://github.com/mapbox/mapbox-navigation-ios/pull/4030)) +* Fixed an issue where `NavigationMapView` injected with `NavigationOptions` isn't visible in active navigation. ([#4049](https://github.com/mapbox/mapbox-navigation-ios/pull/4049)) +* Fixed the crash caused by showing a route that doesn't contain coordinates. ([#4046](https://github.com/mapbox/mapbox-navigation-ios/pull/4046)) + +### CarPlay + +* During active navigation, the user can tap the "Alternatives" button in the navigation bar to switch to an alternative route. ([#3956](https://github.com/mapbox/mapbox-navigation-ios/pull/3956)) + +### Banners and guidance instructions + +* Added the `WayNameView.cornerRadius` property for customizing how the current road name is labeled. ([#4004](https://github.com/mapbox/mapbox-navigation-ios/pull/4004)) +* Reduced memory footprint while downloading road shield images. ([#4020](https://github.com/mapbox/mapbox-navigation-ios/pull/4020)) + +### Location tracking + +* Fixed an error when rerouting the user with `NavigationRouteOptions.profileIdentifier` set to `ProfileIdentifier.walking` or `ProfileIdentifier.cycling`. ([#4024](https://github.com/mapbox/mapbox-navigation-ios/pull/4024)) +* Fixed an issue where the user’s location continued to be snapped to a roadway even after the user’s course deviated significantly from that roadway, for example because the user was actually on a parallel road. ([#4012](https://github.com/mapbox/mapbox-navigation-ios/pull/4012)) +* Fixed an issue when `RouteController` didn't update `RouteProgress.distanceTraveled` property during simulation. ([#4043](https://github.com/mapbox/mapbox-navigation-ios/pull/4043)) + +### Other changes + +* Fixed the unmatched language issue of some localized strings in the feedback view. ([#4007](https://github.com/mapbox/mapbox-navigation-ios/pull/4007)) +* Added `NavigationSettings.utilizeSensorData` toggle to allow navigator to use additional device sensors data for better positioning. ([#3973](https://github.com/mapbox/mapbox-navigation-ios/pull/3973)) +* Fixed the issue of restricted layer over the whole route after the removal of continuous alternative route with a small portion of restricted road class at start. ([#4009](https://github.com/mapbox/mapbox-navigation-ios/pull/4009)) +* Added `ResumeButton.borderWidth`, `ResumeButton.cornerRadius` and `ResumeButton.borderColor` properties that allow `ResumeButton`'s style modification. ([#3996](https://github.com/mapbox/mapbox-navigation-ios/pull/3996)) +* Fixed a crash when dismissing `NavigationViewController`. ([#4029](https://github.com/mapbox/mapbox-navigation-ios/pull/4029)) +* Fixed an issue where `StyleManager` was not applying style on iPad. ([#4039](https://github.com/mapbox/mapbox-navigation-ios/pull/4039)) +* Added filling of `Incident` properties `countryCodeAlpha3`, `countryCode`, `roadIsClosed`, `longDescription`, `numberOfBlockedLanes`, `congestionLevel`, `affectedRoadNames` when receiving `RoadObject` via Electronic Horizon. ([#4045](https://github.com/mapbox/mapbox-navigation-ios/pull/4045)) +* Fixed an issue where simulation `inTunnels` or `onPoorGPS` could teleport user puck to the route origin. ([#4058](https://github.com/mapbox/mapbox-navigation-ios/pull/4058)) +* Fixed an issue where the user location indicator moves out of view when approaching complex intersections. ([#4070](https://github.com/mapbox/mapbox-navigation-ios/pull/4070)) + +## v2.6.2 + +### Packaging + +* This release of MapboxNavigation requires MapboxDirections v2.7._x_ to prevent an iOS 11 support removal issue. If you use Carthage, it requires MapboxDirections v2.7.1 exactly. ([#4273](https://github.com/mapbox/mapbox-navigation-ios/pull/4273)) + +## v2.6.1 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.7._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.7.0). ([#4125](https://github.com/mapbox/mapbox-navigation-ios/pull/4125)) + +### Location tracking + +* Fixed an issue where the user location couldn't be determined on iOS 13 and older versions. ([#4113](https://github.com/mapbox/mapbox-navigation-ios/issues/4113)) + +## v2.6.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.6._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.6.0). ([#3955](https://github.com/mapbox/mapbox-navigation-ios/pull/3955)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v106._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/106.0.0). ([#3955](https://github.com/mapbox/mapbox-navigation-ios/pull/3955)) +* MapboxCoreNavigation now requires [MapboxDirections v2.6._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.6.0). ([#3990](https://github.com/mapbox/mapbox-navigation-ios/pull/3990)) + +### Routing + +* Added `Router.finishRouting()` method to finish routing session without dismissing related UI and logic components. ([#3880](https://github.com/mapbox/mapbox-navigation-ios/pull/3880)) +* Added reporting `AlternativeRoute` during navigation sessions. Subscribe to `RouterDelegate.router(_:didUpdateAlternatives:removedAlternatives:)` or `Notification.Name.routeControllerDidUpdateAlternatives` notification to receive updates on actual alternative routes list. Switching to the alternative route could be monitored by observing `RouterDelegate.router(_:willTakeAlternativeRoute:at:)` and `RouterDelegate.router(_:didTakeAlternativeRouteAt:)` methods or `Notification.Name.routeControllerWillTakeAlternativeRoute` and `Notification.Name.routeControllerDidTakeAlternativeRoute` notifications. To configure alternative routes detection, setup `NavigationSettings.AlternativeRouteDetectionStrategy` before starting navigation. ([#3833](https://github.com/mapbox/mapbox-navigation-ios/pull/3833)) +* During turn-by-turn navigation, the map view displays any alternative routes that are currently available. Tapping an alternative route switches to it, just like in a standalone `NavigationMapView`. ([#3850](https://github.com/mapbox/mapbox-navigation-ios/pull/3850)) +* Implemented refreshing `RouteLeg.incidents` during a route refreshing. ([#3931](https://github.com/mapbox/mapbox-navigation-ios/pull/3931)) +* The `HistoryRecording.stopRecordingHistory(writingFileWith:)` method can be called safely from the main thread. ([#3913](https://github.com/mapbox/mapbox-navigation-ios/pull/3913)) +* Snapped locations are spaced more evenly when the application is connected to an external GPS or CarPlay device capable of high-frequency location updates and the user rounds a corner. ([#3913](https://github.com/mapbox/mapbox-navigation-ios/pull/3913)) +* Fixed an issue where the user’s location would be snapped to the nearest road while the user moved around in a parking garage where the [parking aisles](https://wiki.openstreetmap.org/wiki/Tag:service%3Dparking_aisle) have not been mapped in detail. ([#3913](https://github.com/mapbox/mapbox-navigation-ios/pull/3913)) +* Fixed an issue where `RouteController` sometimes took too long to detect that the user went off the route after making a turn or taking an off-ramp. ([#3913](https://github.com/mapbox/mapbox-navigation-ios/pull/3913)) +* When proactive reroute happens, new departure voice instruction will not be pronounced anymore. ([#3937](https://github.com/mapbox/mapbox-navigation-ios/pull/3937)) +* Fixed an issue where a departure instruction (e.g., “Head west”) was announced periodically in the middle of a trip due to proactive rerouting. ([#3937](https://github.com/mapbox/mapbox-navigation-ios/pull/3937)) + +### Camera + +* Fixed an issue where camera stops updating when `centerUpdatesAllowed`, `zoomUpdatesAllowed`, `bearingUpdatesAllowed`, `pitchUpdatesAllowed` or `paddingUpdatesAllowed` disabled in `OverviewCameraOptions` and `FollowingCameraOptions`. ([#3946](https://github.com/mapbox/mapbox-navigation-ios/pull/3946)) + +### Pricing + +* When calling `MapboxNavigationService.start()` and `MapboxNavigationService.stop()` billing session will be resumed and paused respectively. ([#3928](https://github.com/mapbox/mapbox-navigation-ios/pull/3928)) + +### Map + +* Added `NavigationMapView.tolerance` property to configure the tolerance of map sources for route line, maneuver arrow, and restricted areas. The property controls the level of simplification by specifying the maximum allowed distance between the original line point and the simplified point. A higher tolerance value results in higher simplification. ([#3891](https://github.com/mapbox/mapbox-navigation-ios/pull/3891)) +* Added the `layerPosition` parameter to the `NavigationMapView.show(_:layerPosition:legIndex:)` method for controlling the position of the main route layer while presenting routes. ([#3897](https://github.com/mapbox/mapbox-navigation-ios/pull/3897)) +* Fixed an issue where camera kept receiving updates even after stopping `MapboxNavigationService`. ([#3928](https://github.com/mapbox/mapbox-navigation-ios/pull/3928)) +* Added `NavigationViewController.showsContinuousAlternatives` and `CarPlayNavigationViewController.showsContinuousAlternatives` flags to toggle displaying alternative route's lines during navigation session. Use `NavigationMapView.show(continuousAlternatives:)` and `NavigationMapView.removeContinuousAlternativesRoutes()` methods for fine control over displayed routes. ([#3850](https://github.com/mapbox/mapbox-navigation-ios/pull/3850)) + +### CarPlay + +* Fixed an issue where route shields disappeared when the user enters a tunnel. ([#3882](https://github.com/mapbox/mapbox-navigation-ios/pull/3882)) +* The map automatically chooses the night style when "Always Show Dark Maps" is enabled in the Appearance section of Settings. ([#3882](https://github.com/mapbox/mapbox-navigation-ios/pull/3882)) +* Renamed the `VisualInstruction.carPlayManeuverLabelAttributedText(bounds:shieldHeight:window:)` to the `VisualInstruction.carPlayManeuverLabelAttributedText(bounds:shieldHeight:window:traitCollection:instructionLabelType:)` to have the ability to change color of the shield icons depending on provided trait collection. ([#3882](https://github.com/mapbox/mapbox-navigation-ios/pull/3882)) +* Fixed an issue where a `StyleManager` for CarPlay would update the appearance on both CarPlay and the iOS device simultaneously. ([#3914](https://github.com/mapbox/mapbox-navigation-ios/pull/3914)) +* Fixed an issue where an appearance change of CarPlay would cause an appearance change of iOS as well. Refer to `DayStyle` while implementing custom styles using `Style` class. ([#3922](https://github.com/mapbox/mapbox-navigation-ios/pull/3922)) +* Fixed an issue where maneuver arrow wasn't removed after passing visual instruction on CarPlay. ([#3987](https://github.com/mapbox/mapbox-navigation-ios/pull/3987)) +* Fixed an issue where `LaneView` uses incorrect styling on CarPlay. ([#3975](https://github.com/mapbox/mapbox-navigation-ios/pull/3975)) + +### Other changes + +* Reduced peak memory usage. +* Fixed an issue when alternative route lines overlapped the main route line during navigation. ([#3947](https://github.com/mapbox/mapbox-navigation-ios/pull/3947)) +* Fixed an issue when rerouting to the route which does not originate on current user location, route line and camera jumped to route origin. ([#3943](https://github.com/mapbox/mapbox-navigation-ios/pull/3943)) +* All logs that Navigation SDK produces are now sent to the `MapboxCommon` framework. You can intercept these logs in your own code using `LogConfiguration.registerLogWriterBackend(forLogWriter:)` method from `MapboxCommon` framework. ([#3944](https://github.com/mapbox/mapbox-navigation-ios/pull/3944)) +* Fixed an issue where popped window doesn't get updated in appearance when style changes on phone. ([#3954](https://github.com/mapbox/mapbox-navigation-ios/pull/3954)) +* Fixed an issue where detailed feedback items don't change color in different style. ([#3954](https://github.com/mapbox/mapbox-navigation-ios/pull/3954)) +* Update method deprecation for `HistoryRecording` protocol. Static methods are now preferred over instance ones. ([#3960](https://github.com/mapbox/mapbox-navigation-ios/pull/3960)) +* Fixed an issue where `UserPuckCourseView` is drawn in incorrect position if its location is outside of the bounds of `MapView`. ([#3988](https://github.com/mapbox/mapbox-navigation-ios/pull/3988)) + +## v2.5.4 + +### Packaging + +* This release of MapboxNavigation requires MapboxDirections v2.6._x_ to prevent an iOS 11 support removal issue. If you use Carthage, it requires MapboxDirections v2.6.1 exactly. ([#4274](https://github.com/mapbox/mapbox-navigation-ios/pull/4274)) + +## v2.5.3 + +### Packaging + +* Fixed an issue where dependencies couldn't be resolved when using Swift Package Manager and Xcode 13.2.1. ([#4054](https://github.com/mapbox/mapbox-navigation-ios/pull/4054)) +* MapboxNavigation now requires [MapboxMaps v10.5._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.5.1). ([#4054](https://github.com/mapbox/mapbox-navigation-ios/pull/4054)) +* MapboxCoreNavigation now requires [MapboxDirections v2.6._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.6.0). ([#4054](https://github.com/mapbox/mapbox-navigation-ios/pull/4054)) + +## v2.5.2 + +### Other changes + +* Fixed an issue when rerouting to the route which does not originate on current user location, route line and camera jumped to route origin. ([#3943](https://github.com/mapbox/mapbox-navigation-ios/pull/3943)) + +## v2.5.1 + +### Packaging + +* MapboxCoreNavigation now requires [MapboxNavigationNative v101.0.1](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/101.0.1). ([#3935](https://github.com/mapbox/mapbox-navigation-ios/pull/3935)) + +### Other changes + +* Fixed multiple switching between alternative routes on reroute. ([#3935](https://github.com/mapbox/mapbox-navigation-ios/pull/3935)) +* Fixed memory heap corruption crash. ([#3935](https://github.com/mapbox/mapbox-navigation-ios/pull/3935)) +* Fixed an issue where `SimulatedLocationManager` would jump back to the beginning of the simulated route whenever `RouteController` reroutes the user onto a different route. ([#3929](https://github.com/mapbox/mapbox-navigation-ios/pull/3929)) + +## v2.5.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.5._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.5.0). ([#3869](https://github.com/mapbox/mapbox-navigation-ios/pull/3869)) +* MapboxCoreNavigation now requires [MapboxDirections v2.5._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.5.0). ([#3920](https://github.com/mapbox/mapbox-navigation-ios/pull/3920)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v101._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/101.0.0). ([#3908](https://github.com/mapbox/mapbox-navigation-ios/pull/3908)) + +### User interface + +* Added the `CarPlayManagerDelegate.carPlayManager(_:shouldUpdateNotificationFor:with:in:)` and `CarPlayManagerDelegate.carPlayManager(_:shouldShowNotificationFor:in:)` methods for controlling the display of user notifications while the application is in the background in CarPlay. ([#3828](https://github.com/mapbox/mapbox-navigation-ios/pull/3828)) +* Fixed an issue where shields disappeared after the application returns to the foreground. ([#3840](https://github.com/mapbox/mapbox-navigation-ios/pull/3840)) +* The top banner now shows shields that are more consistent with the map and current road name label. ([#3864](https://github.com/mapbox/mapbox-navigation-ios/pull/3864)) +* Fixed an issue where exit views and generic shields in the top banner got outdated when the style changed during turn-by-turn navigation. ([#3864](https://github.com/mapbox/mapbox-navigation-ios/pull/3864)) +* Fixed an issue where the current road name label used a generic white circle instead of the correct shield to represent a state route in the United States. ([#3870](https://github.com/mapbox/mapbox-navigation-ios/pull/3870)) +* Lane guidance remains visible while the step table is visible. ([#3805](https://github.com/mapbox/mapbox-navigation-ios/pull/3805)) +* Removed a transparent gap that appeared between the top banner and step table if the user completed a maneuver while the step table was visible. ([#3805](https://github.com/mapbox/mapbox-navigation-ios/pull/3805)) +* Fixed an issue where a gray dashed line, which normally indicates a restricted-access road, appeared at the beginning of the route line even if there was no restriction. ([#3811](https://github.com/mapbox/mapbox-navigation-ios/pull/3811)) +* Lane guidance views will now be shown even when all lanes a valid for the current route. ([#3903](https://github.com/mapbox/mapbox-navigation-ios/pull/3903)) +* Fixed the crash of nonstop road shield updates when no valid road information contained in guidance instruction. ([#3911](https://github.com/mapbox/mapbox-navigation-ios/pull/3911)) + +### User feedback + +* Added the `NavigationViewControllerDelegate.navigationViewController(_:didSubmitArrivalFeedback:)` method, which is called when the user submits a rating or comment at the end of a trip. ([#3842](https://github.com/mapbox/mapbox-navigation-ios/pull/3842)) +* Fixed an issue where `EndOfRouteCommentView` is using dark style when only light style is allowed. ([#3845](https://github.com/mapbox/mapbox-navigation-ios/pull/3845)) + +### Location tracking + +* Added the `Router.initialManeuverAvoidanceRadius` property for adjusting the likelihood that the user will be rerouted onto a cross street very close to the current location. ([#3754](https://github.com/mapbox/mapbox-navigation-ios/pull/3754)) +* `UserPuckCourseView` no longer desaturates its color based on the age of the last location update. `RouteController` simulates location updates whenever Location Services is unable to receive real location updates. To ensure a steady stream of location updates outside of turn-by-turn navigation, install a `PassiveLocationManager`. ([#3836](https://github.com/mapbox/mapbox-navigation-ios/pull/3836)) +* Fixed an issue where `UserPuckCourseView`’s color desaturated during turn-by-turn navigation even as the location was being updated. ([#3836](https://github.com/mapbox/mapbox-navigation-ios/pull/3836)) +* Fixed an issue where the `PassiveLocationManager(directions:systemLocationManager:eventsManagerType:userInfo:datasetProfileIdentifier:)` initializer’s `datasetProfileIdentifier` argument was ignored. ([#3867](https://github.com/mapbox/mapbox-navigation-ios/pull/3867)) +* Fixed an issue where the user location was sometimes snapped to a parallel street just before it merges with the actual street. ([#3862](https://github.com/mapbox/mapbox-navigation-ios/pull/3862)) +* Fixed the possible crash after rerouting when `routeLineTracksTraversal` enabled. ([#3896](https://github.com/mapbox/mapbox-navigation-ios/pull/3896)) + +### Routing + +* Renamed `routingProvider` to `customRoutingProvider` within the `NavigationService` class and `Router` protocol. You can continue to implement a `RoutingProvider` to customize how the router calculates a new route when rerouting, but the default value is now `nil` when using the built-in rerouting behavior. ([#3754](https://github.com/mapbox/mapbox-navigation-ios/pull/3754)) + * Renamed the `NavigationService(routeResponse:routeIndex:routeOptions:routingProvider:credentials:locationSource:eventsManagerType:simulating:routerType:)` initializer to `NavigationService(routeResponse:routeIndex:routeOptions:customRoutingProvider:credentials:locationSource:eventsManagerType:simulating:routerType:)`. + * Renamed the `NavigationService(routeResponse:routeIndex:routeOptions:routingProvider:credentials:locationSource:eventsManagerType:simulating:routerType:)` initializer to `NavigationService(routeResponse:routeIndex:routeOptions:customRoutingProvider:credentials:locationSource:eventsManagerType:simulating:routerType:)`. + * Replaced the `NavigationService.routingProvider` property with `NavigationService.customRoutingProvider`. + * Renamed the `Router(alongRouteAtIndex:in:options:routingProvider:dataSource:)` initializer to `Router(alongRouteAtIndex:in:options:customRoutingProvider:dataSource:)` + * Replaced the `Router.routingProvider` property with `Router.customRoutingProvider`. +* Renamed the `NavigationSettings.initialize(directions:tileStoreConfiguration:)` method to `NavigationSettings.initialize(directions:tileStoreConfiguration:routingProviderSource:)`. This method allows you to control whether the rerouting uses the network or offline routing data. ([#3754](https://github.com/mapbox/mapbox-navigation-ios/pull/3754), [#3824](https://github.com/mapbox/mapbox-navigation-ios/pull/3824)) +* Fixed an issue where a failure to calculate a route offline could result in a successful result being passed to a `Directions.RouteCompletionHandler`. +* Added the public property of `NavigationMapView.routeLineTracksTraversal` when standalone `NavigationMapView` is used for active navigation. When it's set to `true`, call `NavigationMapView.updateRouteLine(routeProgress:coordinate:shouldRedraw:)` to update the route line, part of the route line disappears behind the user puck as the user travels along the main route. ([#3855](https://github.com/mapbox/mapbox-navigation-ios/pull/3855)) + +### CarPlay + +* Fixed an issue where an active navigation using CarPlay application with route that contains multiple legs would cause a memory leak. ([#3877](https://github.com/mapbox/mapbox-navigation-ios/pull/3877)) +* Added the `CarPlayManagerDelegate.carPlayManager(_:shouldUpdateNotificationFor:with:in:)` and `CarPlayManagerDelegate.carPlayManager(_:shouldShowNotificationFor:in:)` to provide the ability to control notifications presentation while CarPlay application is in the background. ([#3828](https://github.com/mapbox/mapbox-navigation-ios/pull/3828)) + +### Other changes + +* During turn-by-turn navigation, incidents along the route are now refreshed periodically along with traffic congestion. +* When the user passes a named toll collection point, the `TollCollection` object obtained through the `Notification.Name.electronicHorizonDidPassRoadObject` notification now has the `TollCollection.name` property set. + +## v2.4.3 + +### Packaging + +* Fixed an issue where dependencies couldn't be resolved when using Swift Package Manager. ([#4332](https://github.com/mapbox/mapbox-navigation-ios/pull/4332)) +* MapboxNavigation now requires [MapboxMaps v10.5.1](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.5.1). ([#4332](https://github.com/mapbox/mapbox-navigation-ios/pull/4332)) +* MapboxCoreNavigation now requires [MapboxDirections v2.6._x_ or v2.7._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.7.0). ([#4332](https://github.com/mapbox/mapbox-navigation-ios/pull/4332)) + +## v2.4.2 + +### Packaging + +* Fixed an issue where dependencies couldn't be resolved when using Swift Package Manager and Xcode 13.2.1. ([#4048](https://github.com/mapbox/mapbox-navigation-ios/pull/4048)) +* MapboxNavigation now requires [MapboxMaps v10.5._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.5.1). ([#4048](https://github.com/mapbox/mapbox-navigation-ios/pull/4048)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v94._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/94.0.5). ([#4048](https://github.com/mapbox/mapbox-navigation-ios/pull/4048)) +* MapboxCoreNavigation now requires [MapboxDirections v2.6._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.6.0). ([#4048](https://github.com/mapbox/mapbox-navigation-ios/pull/4048)) + +## v2.4.1 + +* Fixed an issue where the current road name, speed limit, and compass were missing from the map in CarPlay’s navigating activity. ([#3858](https://github.com/mapbox/mapbox-navigation-ios/pull/3858)) + +## v2.4.0 + +### Pricing + +* ❗ Starting with version 2.4.0, we are implementing a grace period of 30-seconds for all navigation sessions started by Nav SDK. A session will be counted only after this time period has surpassed. This allows you to reduce the cost of using the SDK during development and testing of your applications, as well as in production. Grace period is especially helpful to decrease the cost of short Free Drive session that are just a transition between Active Guidance sessions, or when a session is aborted right after it was started. + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.4.1](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.4.1). ([#3806](https://github.com/mapbox/mapbox-navigation-ios/pull/3806)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v94._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/94.0.0). ([#3806](https://github.com/mapbox/mapbox-navigation-ios/pull/3806)) +* MapboxCoreNavigation now requires [MapboxDirections v2.4.0-rc.2](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.4.0-rc.2). ([#3817](https://github.com/mapbox/mapbox-navigation-ios/pull/3817)) + +### User interface + +* `FeedbackViewController` now supports changing styles based on `StyleManager`. ([#3764](https://github.com/mapbox/mapbox-navigation-ios/pull/3764)) +* Deprecated the optional `StyleManagerDelegate.styleManager(_:viewForApplying:)` method. All views appearance will be refreshed based on `StyleManager`. ([#3764](https://github.com/mapbox/mapbox-navigation-ios/pull/3764)) +* Fixed an issue where the map’s floating buttons are misaligned with its attribution button and sometimes untappable after rotating the device during turn-by-turn navigation. ([#3776](https://github.com/mapbox/mapbox-navigation-ios/pull/3776)) +* Fixed an issue where the top instruction banner couldn't be swiped back to the current one. ([#3785](https://github.com/mapbox/mapbox-navigation-ios/pull/3785)) +* Fixed an issue where the road name label shows wrong shield image when applying custom style under poor network connection. ([#3792](https://github.com/mapbox/mapbox-navigation-ios/pull/3792)) +* Added the `SpeedLimitView.shouldShowUnknownSpeedLimit` property which defines the view behavior if the `SpeedLimitView.speedLimit` property is `nil`. Setting this property to `true` will cause the view to display `"--"` as a speed limit instead of the `SpeedLimitView` being invisible. ([#3798](https://github.com/mapbox/mapbox-navigation-ios/pull/3798)) + +### Location tracking + +* Added the `RoadObject.Kind.railroadCrossing` enumeration case to represent a railroad crossing along the route. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Throttled requests to the Mapbox Directions API while the user moves around in a parking lot that has not been mapped in detail. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* If the user backtracks from the beginning of one leg of the route to the end of the previous leg, the user is no longer considered to be off-route; instead, `RouteProgress.currentLegProgress` decrements and other properties follow suit. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Fixed a crash starting turn-by-turn navigation on some routes that included bridges and restricted-access roads. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Fixed an issue where the route line appeared to begin away from the user’s current location after the route was refreshed. ([#3781](https://github.com/mapbox/mapbox-navigation-ios/pull/3781)) +* Fixed a memory leak after ending a turn-by-turn navigation session. ([#3782](https://github.com/mapbox/mapbox-navigation-ios/pull/3782)) +* Fixed an issue where `RouteControllerWillReroute` notification was incorrectly sent when a reroute was already in progress. ([#3772](https://github.com/mapbox/mapbox-navigation-ios/pull/3772)) +* Fixed an issue when `SimulatedLocationManager` could freeze the main thread when working with long routes. The manager now calls delegate methods from a background thread. ([#3672](https://github.com/mapbox/mapbox-navigation-ios/pull/3672)) +* Fixed an issue where initial puck position can be incorrect when `NavigationViewController` is presented. ([#3773](https://github.com/mapbox/mapbox-navigation-ios/pull/3773)) +* Fixed an issue where `UserHaloCourseView` was not correctly shown while changing `CLLocationManager.accuracyAuthorization` and `CLLocationManager.authorizationStatus`. ([#3804](https://github.com/mapbox/mapbox-navigation-ios/pull/3804)) + +### Offline routing + +* In [bilingual and multilingual areas](https://wiki.openstreetmap.org/wiki/Multilingual_names), spoken and visual instructions include street names and destinations in the user’s preferred language when that language is signposted. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Fixed `Intersection.outletIndex` values that were off by one. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* High-occupancy vehicle roads in OpenStreetMap that lack a [`hov:minimum`](https://wiki.openstreetmap.org/wiki/Key:hov:minimum) tag are now assumed to be HOV 2+ roads, requiring one or more passengers. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Decreased memory usage when starting turn-by-turn navigation along a long-distance route. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Fixed an issue where street names in spoken instructions could be go unpronounced if tagged with a [pronunciation](https://wiki.openstreetmap.org/wiki/Key:name:pronunciation). ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* Added support for [the workaround](https://github.com/mapbox/mapbox-directions-swift/issues/662) for requesting a route that avoids an arbitrary set of coordinates. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) + +### CarPlay + +* Fixed an issue where CarPlay application was crashing during template dismissal on iOS 14 and higher. ([#3794](https://github.com/mapbox/mapbox-navigation-ios/pull/3794)) +* Added the ability to style each route line differently on CarPlay during route preview and active navigation using such delegate methods ([#3744](https://github.com/mapbox/mapbox-navigation-ios/pull/3744)): + * `CarPlayManagerDelegate.carPlayManager(_:routeLineLayerWithIdentifier:sourceIdentifier:for:)` to style the route. + * `CarPlayManagerDelegate.carPlayManager(_:routeCasingLineLayerWithIdentifier:sourceIdentifier:for:)` to style the casing of the route. +* Added `CarPlayManager.previewRoutes(for:)` to provide the ability to preview routes based on response from Mapbox Directions. ([#3807](https://github.com/mapbox/mapbox-navigation-ios/pull/3807)) + +### Other changes + +* Added the `MapboxSpeechSynthesizer(remoteSpeechSynthesizer:)` initializer for creating a `MapboxSpeechSynthesizer` object that uses a custom `SpeechSynthesizer` instance. ([#3747](https://github.com/mapbox/mapbox-navigation-ios/pull/3747)) +* MapboxNavigationNative now sends messages to the Unified Logging subsystem `com.mapbox` for easier filtering. ([#3765](https://github.com/mapbox/mapbox-navigation-ios/pull/3765)) +* `HistoryRecording` static methods are deprecated in favor of instance methods. Using these instance variants on `RouteController` or `PassiveLocationManager` ensures correct history events recording and storing. ([#3791](https://github.com/mapbox/mapbox-navigation-ios/pull/3791)) +* Fixed a bug which caused `RouteOptions.profileIdentifier` to be ignored in active navigation. This may have caused elevated network usage. ([#3796](https://github.com/mapbox/mapbox-navigation-ios/pull/3796)) + +## v2.3.0 + +The v2.2.0 release notes [clarified](https://github.com/mapbox/mapbox-navigation-ios/pull/3652) that is an error to have more than one instance of `NavigationViewController`, `NavigationService`, or `RouteController` running simultaneously. Now you will receive a log message at the fault level helping you to spot the issue. To pause the debugger when the SDK detect the problematic situation, enable the “All Runtime Issues” breakpoint in Xcode. Learn more about breakpoints in [Xcode documentation](https://developer.apple.com/documentation/xcode/setting-breakpoints-to-pause-your-running-app). ([#3740](https://github.com/mapbox/mapbox-navigation-ios/pull/3740)) + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.3._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.3.0). ([#3748](https://github.com/mapbox/mapbox-navigation-ios/pull/3748)) +* MapboxCoreNavigation now requires [MapboxDirections v2.3._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.3.0). ([#3723](https://github.com/mapbox/mapbox-navigation-ios/pull/3723)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v88._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/88.0.0). ([#3748](https://github.com/mapbox/mapbox-navigation-ios/pull/3748)) + +### Map + +* Renamed the `NavigationMapView.highlightBuildings(at:in3D:completion:)` method to `NavigationMapView.highlightBuildings(at:in3D:extrudeAll:completion:)` to provide the ability to extrude not only buildings at specific coordinates, but all other buildings as well. ([#3736](https://github.com/mapbox/mapbox-navigation-ios/pull/3736)) +* Added `MapView.showsTileSet(with:layerIdentifier:)` and `MapView.setShowsTileSet(_:with:layerIdentifier:)` to provide the ability to show and hide custom tile set identifiers on the map view. ([#3700](https://github.com/mapbox/mapbox-navigation-ios/pull/3700)) +* Added the `NavigationMapView.mapViewTapGestureRecognizer` property and the `NavigationMapView.legSeparatingWaypoints(on:closeTo:)` and `NavigationMapView.routes(closeTo:)` methods for configuring how the map view responds to tap gestures when previewing a route. ([#3746](https://github.com/mapbox/mapbox-navigation-ios/pull/3746)) +* Fixed an issue where the route line and 3D building highlights disappeared from a standalone `NavigationMapView` when the map style changed. ([#3734](https://github.com/mapbox/mapbox-navigation-ios/pull/3734), [#3736](https://github.com/mapbox/mapbox-navigation-ios/pull/3736)) +* Fixed an issue where the route line blinked when refreshing the route. ([#3647](https://github.com/mapbox/mapbox-navigation-ios/pull/3647)) + +### Visual instructions + +* Renamed the `NextBannerView.update(for:)`, `NextBannerView.show()` and `NextBannerView.hide()` methods to `NextBannerView.update(for:animated:duration:completion:)`, `NextBannerView.show(animated:duration:completion:)`, `NextBannerView.hide(animated:duration:completion:)`, respectively. ([#3704](https://github.com/mapbox/mapbox-navigation-ios/pull/3704)) +* Renamed the `LanesView.update(for:)`, `LanesView.show()` and `LanesView.hide()` methods to `LanesView.update(for:animated:duration:completion:)`, `LanesView.show(animated:duration:completion:)`, `LanesView.hide(animated:duration:completion:)`, respectively. ([#3704](https://github.com/mapbox/mapbox-navigation-ios/pull/3704)) +* Added the `InstructionsCardContainerView.separatorColor` and `InstructionsCardContainerView.highlightedSeparatorColor` to be able to change instruction card's separator colors. ([#3704](https://github.com/mapbox/mapbox-navigation-ios/pull/3704)) +* Added `routeShieldRepresentationKey` to the user info dictionary of `Notification.Name.passiveLocationManagerDidUpdate` posted by `PassiveLocationManager`, and the `Notification.Name.currentRoadNameDidChange` posted by `RouteController`. The corresponding value is a `MapboxDirections.VisualInstruction.Component.ImageRepresentation` object representing the road shield the user is currently traveling on. ([#3723](https://github.com/mapbox/mapbox-navigation-ios/pull/3723)) +* `InstructionsCardViewController` now has a flat appearance. ([#3704](https://github.com/mapbox/mapbox-navigation-ios/pull/3704)) +* Fixed a crash when approaching an intersection in which one of the lanes is a merge lane. ([#3699](https://github.com/mapbox/mapbox-navigation-ios/pull/3699)) +* Fixed an issue where the step list in `StepsViewController` is empty whle the user is on the final step of a route leg. ([#3729](https://github.com/mapbox/mapbox-navigation-ios/pull/3729)) +* Fixed the color of leg section headers in `StepsViewController` to switch between the day and night styles like the rest of the view controller. ([#3760](https://github.com/mapbox/mapbox-navigation-ios/pull/3760)) + +### Location tracking + +* Added an optional `datasetProfileIdentifier` argument to the `MapboxRoutingProvider(_:settings:datasetProfileIdentifier:)`, `PassiveLocationManager(directions:systemLocationManager:eventsManagerType:userInfo:datasetProfileIdentifier:),` `TilesetDescriptorFactory.getSpecificVersion(version:completionQueue:datasetProfileIdentifier:completion:)`, and `TilesetDescriptorFactory.getLatest(completionQueue:datasetProfileIdentifier:completion:)` methods for obtaining routing tiles optimized for a particular mode of transportation. Make sure to configure `MapboxRoutingProvider` and `TilesetDescriptorFactory` with the correct dataset profile if you customize `Directions.profileIdentifier`. ([#3717](https://github.com/mapbox/mapbox-navigation-ios/pull/3717)) +* Fixed a crash that sometimes occurred in Release configuration when initializing a `PassiveLocationManager` or `RouteController`. ([#3738](https://github.com/mapbox/mapbox-navigation-ios/pull/3738)) +* Fixed an issue where the user location indicator floated around when the user was stopped at an intersection in an urban canyon. ([#3705](https://github.com/mapbox/mapbox-navigation-ios/pull/3705)) +* Fixed poor location snapping while the user is inside a tunnel. ([#3705](https://github.com/mapbox/mapbox-navigation-ios/pull/3705)) +* Fixed a leak of location tracking and routing resources after stopping all instances `RouteController` and `PassiveLocationManager`. ([#3724](https://github.com/mapbox/mapbox-navigation-ios/pull/3724)) + +### Offline routing + +* If routing tiles in local storage are corrupted, the tiles are now redownloaded. ([#3705](https://github.com/mapbox/mapbox-navigation-ios/pull/3705)) +* Offline routes now respect the `RouteOptions.roadClassesToAllow` property. ([#3705](https://github.com/mapbox/mapbox-navigation-ios/pull/3705)) +* Fixed an issue where `Directions.calculateOffline(options:completionHandler:)` calculated the route by making a network request. ([#3702](https://github.com/mapbox/mapbox-navigation-ios/pull/3702)) +* Fixed an issue where offline directions contained instructions in English regardless of the `DirectionsOptions.locale` property. ([#3705](https://github.com/mapbox/mapbox-navigation-ios/pull/3705)) + +### Other changes + +* Added `CarPlayUserInfo` type alias for storing CarPlay-related user information. This type will be used by `CPRouteChoice` or `CPListItem` while presenting trip with multiple route choices or when selecting list item from search results, respectively. ([#3709](https://github.com/mapbox/mapbox-navigation-ios/pull/3709)) +* Added the `CarPlayManagerDelegate.carPlayManagerDidEndNavigation(_:byCanceling:)` method, which is similar to the existing `CarPlayManagerDelegate.carPlayManagerDidEndNavigation(_:)` method but indicates whether the user canceled the navigation session. ([#3731](https://github.com/mapbox/mapbox-navigation-ios/pull/3731)) +* Fixed an issue where changing `NavigationViewController.showsReportFeedback`, `NavigationViewController.showsSpeedLimits`, `NavigationViewController.detailedFeedbackEnabled`, `NavigationViewController.floatingButtonsPosition` and `NavigationViewController.floatingButtons` before presenting `NavigationViewController` had no effect. ([#3718](https://github.com/mapbox/mapbox-navigation-ios/pull/3718)) +* Fixed an issue where `SpeechSynthesizing.managesAudioSession` was ignored by `RouteVoiceController`. ([#3572](https://github.com/mapbox/mapbox-navigation-ios/pull/3572)) +* Fixed the gap between the end-of-route feedback panel and the bottom of the screen in landscape orientation. ([#3769](https://github.com/mapbox/mapbox-navigation-ios/pull/3769)) + +## v2.2.0 + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.2._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.2.0). ([#3665](https://github.com/mapbox/mapbox-navigation-ios/pull/3665)) +* MapboxCoreNavigation now requires [MapboxDirections v2.2._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.2.0). ([#3694](https://github.com/mapbox/mapbox-navigation-ios/pull/3694)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v83._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/83.0.0). ([#3683](https://github.com/mapbox/mapbox-navigation-ios/pull/3683)) + +### Map + +* Added `NavigationMapView.showsRestrictedAreasOnRoute` property which allows displaying on UI parts of a route which lie on restricted roads. This overlay is customisable through `NavigationMapView.routeRestrictedAreaColor`, `NavigationMapViewDelegate.navigationMapView(_:, restrictedAreasShapeFor:)` and `NavigationMapView.navigationMapView(_:, routeRestrictedAreasLineLayerWithIdentifier:, sourceIdentifier:)` methods. ([#3603](https://github.com/mapbox/mapbox-navigation-ios/pull/3603)) +* Fixed an issue where changing color of `NavigationMapView.maneuverArrowColor` and `NavigationMapView.maneuverArrowStrokeColor` did not work. ([#3633](https://github.com/mapbox/mapbox-navigation-ios/pull/3633)) +* Fixed an issue where the route line blinks when `NavigationMapView.showsRestrictedAreasOnRoute` is turned on during active navigation, and when `NavigationMapView.routeLineTracksTraversal` is set to `true`. ([#3654](https://github.com/mapbox/mapbox-navigation-ios/pull/3654)) +* Updated `RoutesPresentationStyle` to support the ability to present routes based on custom camera options. ([#3678](https://github.com/mapbox/mapbox-navigation-ios/pull/3678)) + +### Location tracking + +* Fixed an issue where customized `.puck2D` and `.puck3D` of `NavigationMapView.userLocationStyle` is not shown during simulated active navigation. ([#3674](https://github.com/mapbox/mapbox-navigation-ios/pull/3674)) +* Added the `NavigationLocationProvider.didUpdateLocations(locations:)` to send locations update to `MapView` and notify its `LocationConsumer`. ([#3674](https://github.com/mapbox/mapbox-navigation-ios/pull/3674)) +* When rerouting the user, if none of the new routes is very similar to the original route selection, the Router now follows the most optimal route, not a route that is only marginally similar. ([#3664](https://github.com/mapbox/mapbox-navigation-ios/pull/3664)) +* Exposed map matching status using new `MapMatchingResult` object which can be obtained through `RouteController.routeControllerProgressDidChange` and `PassiveLocationManager.passiveLocationManagerDidUpdate` notifications under `mapMatchingResultKey`. ([#3669](https://github.com/mapbox/mapbox-navigation-ios/pull/3669)) + +### Banners and guidance instructions + +* In landscape orientation, `NavigationViewController`’s top and bottom banners take up less space, leaving more room for the map. ([#3643](https://github.com/mapbox/mapbox-navigation-ios/pull/3643)) + +### CarPlay + +* Added the `CarPlayManagerDelegate.carPlayManagerWillEndNavigation(_:byCanceling:)` and `CarPlayNavigationViewControllerDelegate.carPlayNavigationViewControllerWillDismiss(_:byCanceling:)` methods for determining when `CarPlayNavigationViewController` is about to be dismissed. ([#3676](https://github.com/mapbox/mapbox-navigation-ios/pull/3676)) + +### Other Changes + +* Extracted `MapboxNavigationNative_Private` usage into a type alias to fix a compilation in Xcode 12.4. ([#3662](https://github.com/mapbox/mapbox-navigation-ios/pull/3662)) +* Fixed a bug where tapping `NavigationMapView` while it transitions the camera to or from `following/overview` states would leave it in `transitioning` state, and thus blocking switching to either mode. ([#3685](https://github.com/mapbox/mapbox-navigation-ios/pull/3685)) +* Fixed an issue where building extrusion highlighting was covering other items located on the map like POI and destination/arrival icons. ([#3692](https://github.com/mapbox/mapbox-navigation-ios/pull/3692)) + +### Location tracking + +* Fixed an issue where dismissing `NavigationViewController` could cause `RouteController` to crash or `PassiveLocationProvider` to behave like active turn-by-turn navigation. It is a programmer error to have more than one alive `NavigationViewController`, `NavigationService` or `RouteController` simultaneously. ([#3652](https://github.com/mapbox/mapbox-navigation-ios/pull/3652)) + +## v2.1.0 + +### Pricing + +* Fixed billing issues that might affect upgrading from v1._x_ to v2._x_. This update is strongly recommended. ([#3626](https://github.com/mapbox/mapbox-navigation-ios/pull/3626)) +* Fixed an issue where paused billing trip sessions might result in requests made inside MapboxNavigationNative to be billed per request. ([#3348](https://github.com/mapbox/mapbox-navigation-ios/pull/3558)) + +### Packaging + +* MapboxNavigation now requires [MapboxMaps v10.1.0](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.1.0) or above. ([#3590](https://github.com/mapbox/mapbox-navigation-ios/pull/3590)) +* MapboxCoreNavigation now requires [MapboxDirections v2.1.0](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.1.0) or above. ([#3590](https://github.com/mapbox/mapbox-navigation-ios/pull/3590)) +* MapboxCoreNavigation now requires [MapboxNavigationNative v80._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/80.0.0). ([#3590](https://github.com/mapbox/mapbox-navigation-ios/pull/3590)) + +### Location tracking + +* Added `RoutingProvider` to parameterize routing fetching and refreshing during active guidance sessions. `Directions.calculateWithCache(options:completionHandler:)` and `Directions.calculateOffline(options:completionHandler)` functionality is deprecated by `MapboxRoutingProvider`. It is now recommended to use `MapboxRoutingProvider` to request or refresh routes instead of `Directions` object but you may also provide your own `RoutingProvider` implementation to `NavigationService`, `RouteController` or `LegacyRouteController`. Using `directions` property of listed above entities is discouraged, you should use corresponding `routingProvider` instead, albeit `Directions` also implements the protocol. ([#3261](https://github.com/mapbox/mapbox-navigation-ios/pull/3261)) +* Added the `PassiveLocationManager.rawLocation` and `PassiveLocationManager.location` properties to get the latest raw and idealized locations, respectively. ([#3474](https://github.com/mapbox/mapbox-navigation-ios/pull/3474)) +* Fixed an issue where `ReplayLocationManager` would crash if initialized with just one location. ([#3528](https://github.com/mapbox/mapbox-navigation-ios/pull/3528)) +* Added the `ReplayLocationManager.replayCompletionHandler` property that allows you to loop location. ([#3528](https://github.com/mapbox/mapbox-navigation-ios/pull/3528), [3550](https://github.com/mapbox/mapbox-navigation-ios/pull/3550)) +* Added `RouteControllerNotificationUserInfoKey.headingKey` to the user info dictionary of `Notification.Name.routeControllerWillReroute`, `Notification.Name.routeControllerDidReroute`, and `Notification.Name.routeControllerProgressDidChange` notifications. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620)) +* Added a `Router.heading` property that may contain a heading from the location manager. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620)) +* Changed the behavior of `ReplayLocationManager` so that it doesn't loop locations by default. ([#3550](https://github.com/mapbox/mapbox-navigation-ios/pull/3550)) +* If the user walks away from the route, they may be rerouted onto a route that initially travels in the opposite direction. This is only the case along steps that require walking on foot. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620)) +* Fixed an issue where `ReplayLocationManager` didn't update location timestamps when a new loop started. ([#3550](https://github.com/mapbox/mapbox-navigation-ios/pull/3550)) +* Fixed the background location update issue during active navigation when using default `.courseView` for `NavigationMapView.userLocationStyle`. ([#3533](https://github.com/mapbox/mapbox-navigation-ios/pull/3533)) +* Fixed an issue where `UserPuckCourseView` is trimmed when using custom frame for `UserLocationStyle.courseView(_:)`. ([#3601](https://github.com/mapbox/mapbox-navigation-ios/pull/3601)) +* Fixed an issue where route line blinks when style is changed during active navigation. ([#3613](https://github.com/mapbox/mapbox-navigation-ios/pull/3613)) +* Fixed an issue where route line missing traffic colors after refresh or rerouting. ([#3622](https://github.com/mapbox/mapbox-navigation-ios/pull/3622)) +* Fixed an issue when user goes offline and the route line grows back when `NavigationViewController.routeLineTracksTraversal` enabled. When the distance of user location to the route is larger than certain distance threshold, the vanishing effect of route line would stop until the new route line gets generated. ([#3385](https://github.com/mapbox/mapbox-navigation-ios/pull/3385)) +* Fixed an issue where `RouteStepProgress.currentIntersection` was always returning invalid value, which in turn caused inability to correctly detect whether specific location along the route is in tunnel, or not. ([#3559](https://github.com/mapbox/mapbox-navigation-ios/pull/3559)) + +### Banners and guidance instructions + +* Added the `TopBannerViewController.lanesView`, `TopBannerViewController.nextBannerView`, `TopBannerViewController.statusView` and `TopBannerViewController.junctionView` properties. ([#3575](https://github.com/mapbox/mapbox-navigation-ios/pull/3575)) +* Added the `WayNameView.backgroundColor` and `WayNameView.borderWidth` properties for customizing how the current road name is labeled. ([#3534](https://github.com/mapbox/mapbox-navigation-ios/pull/3534)) +* The `InstructionsBannerViewDelegate` and `TopBannerViewControllerDelegate` protocols now conform to the `VisualInstructionDelegate` protocol. ([#3575](https://github.com/mapbox/mapbox-navigation-ios/pull/3575)) +* Fixed a crash when scrolling the guidance cards while the orientation changes. ([#3544](https://github.com/mapbox/mapbox-navigation-ios/pull/3544)) +* Fixed an issue where `VisualInstructionDelegate.label(_:willPresent:as:)` was never called. Your `NavigationViewControllerDelegate` class can now implement this method to customize the contents of a visual instruction during turn-by-turn navigation. ([#3575](https://github.com/mapbox/mapbox-navigation-ios/pull/3575)) +* Fixed an issue where certain dual- or triple-use lanes were blank in the tertiary instruction banner. ([#3569](https://github.com/mapbox/mapbox-navigation-ios/pull/3569), [mapbox/navigation-ui-resources#26](https://github.com/mapbox/navigation-ui-resources/pull/26)) +* Fixed an issue where dual-use slight turn lanes were sometimes depicted as normal turn lanes in the tertiary instruction banner. ([#3569](https://github.com/mapbox/mapbox-navigation-ios/pull/3569), [mapbox/navigation-ui-resources#26](https://github.com/mapbox/navigation-ui-resources/pull/26)) +* Setting the `WayNameView.isHidden` property to `true` now keeps the view hidden even after the user goes onto a named road. ([#3534](https://github.com/mapbox/mapbox-navigation-ios/pull/3534)) +* Fixed an issue where the user interface did not necessarily display distances in the same units as the route by default. `NavigationRouteOptions` and `NavigationMatchOptions` now set `DirectionsOptions.distanceMeasurementSystem` to a default value matching the `NavigationSettings.distanceUnit` property. ([#3541](https://github.com/mapbox/mapbox-navigation-ios/pull/3541)) + +### Map + +* Added the `NavigationViewController.usesNightStyleWhileInTunnel` and `CarPlayNavigationViewController.usesNightStyleWhileInTunnel` properties, which allow to disable dark style usage, while traversing the tunnels. ([#3559](https://github.com/mapbox/mapbox-navigation-ios/pull/3559)) +* Added the ability to change congestion color transition sharply or softly when `NavigationMapView.crossfadesCongestionSegments` changed during active navigation. ([#3466](https://github.com/mapbox/mapbox-navigation-ios/pull/3466)) +* While the user is walking, the map rotates according to the user’s heading instead of their course. ([#3620](https://github.com/mapbox/mapbox-navigation-ios/pull/3620)) +* Fixed an issue where the entire route line was colored as `NavigationMapView.routeCasingColor` instead of `NavigationMapView.trafficUnknownColor` when traffic congestion data was missing. ([#3577](https://github.com/mapbox/mapbox-navigation-ios/pull/3577)) +* Fixed an issue where `NavigationMapView.showcase(_:animated:)` was clipping unselected routes by renaming it to the `NavigationMapView.showcase(_:routesPresentationStyle:animated:)`, with an optional parameter to control whether the camera fits to unselected routes in addition to the selected route. ([#3556](https://github.com/mapbox/mapbox-navigation-ios/pull/3556)) +* Fixed an issue where on routes with large distances between current location and next manuever camera zoom level was too low. To control navigation camera zoom level use `IntersectionDensity.averageDistanceMultiplier` coefficient. ([#3616](https://github.com/mapbox/mapbox-navigation-ios/pull/3616)) + +### CarPlay + +* Added the `CarPlayActivity.panningInNavigationMode` case, which allows to track a state when user is panning a map view while actively navigating. ([#3545](https://github.com/mapbox/mapbox-navigation-ios/pull/3545)) +* Fixed an issue that caused the panning dismissal button to stop working on CarPlay. ([#3543](https://github.com/mapbox/mapbox-navigation-ios/pull/3543)) +* Fixed an issue which caused the inability to see `SpeedLimitView` and `CarPlayCompassView` when left-hand traffic mode is used on CarPlay. ([#3583](https://github.com/mapbox/mapbox-navigation-ios/pull/3583)) +* Added the `CarPlayMapViewController.wayNameView` and `CarPlayNavigationViewController.wayNameView` properties to show the current road name on CarPlay. `CarPlayNavigationViewController.compassView`, `CarPlayNavigationViewController.speedLimitView` and `CarPlayMapViewController.speedLimitView` are kept as strong references, thus available throughout the lifetime of a parent object. ([#3534](https://github.com/mapbox/mapbox-navigation-ios/pull/3534)) +* Fixed an issue when `NavigationMapView.crossfadesCongestionSegments` enabled but congestion color transition is still sharp in CarPlay. ([#3466](https://github.com/mapbox/mapbox-navigation-ios/pull/3466)) +* Fixed an issue when incorrect padding was used for `SpeedLimitView` and `CarPlayCompassView` for right-hand traffic mode on CarPlay. ([#3605](https://github.com/mapbox/mapbox-navigation-ios/pull/3605)) +* Added the ability to extrude or highlight building on CarPlay by setting the `CarPlayNavigationViewController.waypointStyle` property. ([#3564](https://github.com/mapbox/mapbox-navigation-ios/pull/3564)) +* Fixed a retain cycle in CarPlay implementation of a navigation map view that prevented `NavigationMapView` instances from being deallocated after CarPlay is stopped. ([#3552](https://github.com/mapbox/mapbox-navigation-ios/pull/3552)) + +### Other changes + +* Added the `SpeechSynthesizing.managesAudioSession` property to control if the speech synthesizer is allowed to manage the shared `AVAudioSession`. Set this value to false if you want to enable and disable the `AVAudioSession` yourself, for example, if your app plays background music. ([#3572](https://github.com/mapbox/mapbox-navigation-ios/pull/3572)) +* Fixed an issue when `SpeechSynthesizingDelegate.speechSynthesizer(_:willSpeak:)` callback was called at the wrong moment. ([#3572](https://github.com/mapbox/mapbox-navigation-ios/pull/3572)) +* Renamed the `Locale.usesMetric` property to `Locale.measuresDistancesInMetricUnits`. `Locale.usesMetric` is still available but deprecated. ([#3547](https://github.com/mapbox/mapbox-navigation-ios/pull/3547)) + +## v2.0.1 + +* Added the `Notification.Name.didArriveAtWaypoint` constant for notifications posted when the user arrives at a waypoint. ([#3514](https://github.com/mapbox/mapbox-navigation-ios/pull/3514)) +* Added the `CarPlayManager.currentActivity` property to determine how a `CPTemplate` is being used. ([#3521](https://github.com/mapbox/mapbox-navigation-ios/pull/3521)) +* Fixed an issue where setting `StyleManager.styles` to an array of only one style did not immediately apply the style. ([#3508](https://github.com/mapbox/mapbox-navigation-ios/pull/3508)) +* Fixed an issue in CarPlay’s previewing activity where only the selected route was visible on the map, while other alternative routes were hidden. Now all the routes are visible simultaneously. ([#3511](https://github.com/mapbox/mapbox-navigation-ios/pull/3511)) +* Fixed an issue where the route line flashed when the user arrived at the destination if `NavigationViewController.routeLineTracksTraversal` was enabled. ([#3516](https://github.com/mapbox/mapbox-navigation-ios/pull/3516)) + +### Banners and guidance instructions + +* `InstructionsCardViewController` now adapts to `NightStyle`. ([#3503](https://github.com/mapbox/mapbox-navigation-ios/pull/3503)) +* Fixed an issue where `InstructionsCardViewController` installed duplicate Auto Layout constraints on each location update. ([#3503](https://github.com/mapbox/mapbox-navigation-ios/pull/3503)) + +## v2.0.0 + +### Packaging + +* Choose from [two new pricing options](https://docs.mapbox.com/ios/beta/navigation/guides/pricing/) depending on your use case: per-trip or unlimited trips. ([#3147](https://github.com/mapbox/mapbox-navigation-ios/pull/3147), [#3338](https://github.com/mapbox/mapbox-navigation-ios/pull/3338)) +* The Mapbox Navigation SDK for iOS license has changed from the ISC License to the Mapbox Terms of Service. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* To gain access to Mapbox server APIs, set `MBXAccessToken` in your Info.plist. `MGLMapboxAccessToken` is deprecated and no longer supported by `NavigationMapView`. ([#2837](https://github.com/mapbox/mapbox-navigation-ios/pull/2837)) +* The `MBXNavigationBillingMethod` Info.plist key is no longer supported. ([#3147](https://github.com/mapbox/mapbox-navigation-ios/pull/3147)) + +#### System requirements + +* MapboxNavigation and MapboxCoreNavigation require iOS 11.0 or above to run. iOS 10._x_ is no longer supported. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Xcode 12.4 or above is now required for building this SDK from source. +* You can build MapboxNavigation for an iOS simulator on an Apple Silicon–powered Mac. ([#3031](https://github.com/mapbox/mapbox-navigation-ios/pull/3031)) +* You can now install MapboxNavigation using Swift Package Manager, but you can no longer install it using Carthage. If you previously installed MapboxNavigation using Carthage, use Swift Package Manager instead. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Carthage v0.38 or above is now required for installing this SDK if you use Carthage. ([#3031](https://github.com/mapbox/mapbox-navigation-ios/pull/3031)) +* Added a Castilian Spanish localization. ([#3186](https://github.com/mapbox/mapbox-navigation-ios/pull/3186)) + +#### Dependencies + +* MapboxNavigation now depends on [MapboxMaps v10._x_](https://github.com/mapbox/mapbox-maps-ios/releases/tag/v10.0.0) instead of [Mapbox Maps SDK for iOS v6._x_](https://github.com/mapbox/mapbox-gl-native-ios/). Consult the “[Migrate to v10](https://docs.mapbox.com/ios/beta/maps/guides/migrate-to-v10/)” guide for tips on upgrading your runtime styling and other map-related code. ([#3413](https://github.com/mapbox/mapbox-navigation-ios/pull/3413)) +* MapboxNavigation now depends on [MapboxSpeech v2._x_](https://github.com/mapbox/mapbox-speech-swift/releases/tag/v2.0.0). ([#3500](https://github.com/mapbox/mapbox-navigation-ios/pull/3500)) +* MapboxCoreNavigation no longer depends on [MapboxAccounts](https://github.com/mapbox/mapbox-accounts-ios/). If you previously installed MapboxCoreNavigation using Carthage, remove MapboxAccounts.framework from your application’s Link Binary With Libraries build phase. ([#2829](https://github.com/mapbox/mapbox-navigation-ios/pull/2829)) +* MapboxCoreNavigation now depends on [MapboxMobileEvents v1._x_](https://github.com/mapbox/mapbox-events-ios/releases/tag/v1.0.0). The dependency on MapboxMobileEvents is subject to change or removal in a future minor release of MapboxCoreNavigation, so your Podfile, Cartfile, or Package.swift should not explicitly depend on MapboxMobileEvents. ([#3320](https://github.com/mapbox/mapbox-navigation-ios/pull/3320)) +* MapboxCoreNavigation now depends on [MapboxDirections v2._x_](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v2.0.0). ([#3500](https://github.com/mapbox/mapbox-navigation-ios/pull/3500)) +* MapboxCoreNavigation now depends on [Turf v2._x_](https://github.com/mapbox/turf-swift/releases/tag/v2.0.0). ([#3413](https://github.com/mapbox/mapbox-navigation-ios/pull/3413)) +* MapboxCoreNavigation now depends on [MapboxNavigationNative v69._x_](https://github.com/mapbox/mapbox-navigation-native-ios/releases/tag/69.0.0). ([#3413](https://github.com/mapbox/mapbox-navigation-ios/pull/3413)) +* MapboxCoreNavigation now depends on [MapboxCommon v20._x_](https://github.com/mapbox/mapbox-common-ios/releases/tag/v20.0.0). ([#3413](https://github.com/mapbox/mapbox-navigation-ios/pull/3413)) +* Removed the optional dependency on [MapboxGeocoder.swift](https://github.com/mapbox/MapboxGeocoder.swift/). ([#2999](https://github.com/mapbox/mapbox-navigation-ios/pull/2999), [#3183](https://github.com/mapbox/mapbox-navigation-ios/issues/3183)) + +### Map + +* `NavigationMapView` is no longer a subclass of `MGLMapView`. To access `MGLMapView` properties and methods, use the `NavigationMapView.mapView` property. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Added the `NavigationOptions.navigationMapView` property for reusing a custom map view within `NavigationViewController`. ([#3186](https://github.com/mapbox/mapbox-navigation-ios/pull/3186)). +* Added the `NavigationMapView(frame:navigationCameraType:tileStoreLocation:)` initializer. ([#2826](https://github.com/mapbox/mapbox-navigation-ios/pull/2826)) +* Replaced the `NavigationMapView.navigationMapDelegate` and `NavigationMapView.navigationMapViewDelegate` properties with a single `NavigationMapView.delegate` property. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed the `NavigationViewController.mapView` property to `NavigationViewController.navigationMapView`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed the `MGLStyle.navigationDayStyleURL` and `MGLStyle.navigationNightStyleURL` properties to `StyleURI.navigationDay` and `StyleURI.navigationNight`, respectively. Removed the `MGLStyle.navigationDayStyleURL(version:)` and `MGLStyle.navigationNightStyleURL(version:)` methods in favor of these renamed properties. ([#3332](https://github.com/mapbox/mapbox-navigation-ios/pull/3332)) +* Renamed the `NavigationMapView.highlightBuildings(at:in3D:)` method to `NavigationMapView.highlightBuildings(at:in3D:completion:)`. ([#2827](https://github.com/mapbox/mapbox-navigation-ios/pull/2827)) + +#### Camera + +* Added the `NavigationMapView.navigationCamera` and `NavigationCamera.cameraStateTransition` properties for controlling the camera’s motion and the `NavigationViewportDataSource` class for configuring the viewport behavior based on the current location and nearby portions of the route line. Added the `ViewportDataSource` and `CameraStateTransition` protocols and the `NavigationViewportDataSourceOptions` struct for more granular customization. ([#2826](https://github.com/mapbox/mapbox-navigation-ios/pull/2826), [#2944](https://github.com/mapbox/mapbox-navigation-ios/pull/2944)) +* Removed the `CarPlayNavigationViewController.tracksUserCourse` property and the `NavigationMapView.enableFrameByFrameCourseViewTracking(for:)`, `NavigationMapView.updateCourseTracking(location:camera:animated:)`, `NavigationMapView.setOverheadCameraView(from:along:for:)`, and `NavigationMapView.recenterMap()` methods in favor of the `NavigationMapView.navigationCamera` property. ([#2826](https://github.com/mapbox/mapbox-navigation-ios/pull/2826)) +* Removed the `NavigationMapView.defaultAltitude`, `NavigationMapView.zoomedOutMotorwayAltitude`, `NavigationMapView.longManeuverDistance`, `NavigationMapView.defaultPadding`, `NavigationMapView.courseTrackingDelegate`, and `NavigationViewController.pendingCamera` properties and the `NavigationMapViewDelegate.navigationMapViewUserAnchorPoint(_:)` method in favor of the `NavigationCamera.cameraStateTransition` property. ([#2826](https://github.com/mapbox/mapbox-navigation-ios/pull/2826)) +* `NavigationMapView.updateCourseTracking(location:camera:animated:)` accepts a `CameraOptions` instance instead of an `MGLMapCamera` object. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Changed the `NavigationViewController.pendingCamera` property’s type from `MGLMapCamera` to `CameraOptions`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed the `CourseUpdatable.update(location:pitch:direction:animated:tracksUserCourse:)` method to `CourseUpdatable.update(location:pitch:direction:animated:navigationCameraState:)`. ([#2826](https://github.com/mapbox/mapbox-navigation-ios/pull/2826)) +* Eliminated redundant camera animations to conserve power. ([#3155](https://github.com/mapbox/mapbox-navigation-ios/pull/3155), [#3172](https://github.com/mapbox/mapbox-navigation-ios/pull/3172)) +* Fixed the camera shaking in mobile and CarPlay during active navigation in simulation mode. ([#3393](https://github.com/mapbox/mapbox-navigation-ios/pull/3393)) + +#### User location indicator + +* Removed the `NavigationMapView.showsUserLocation` and `NavigationMapView.tracksUserCourse` properties in favor of `NavigationMapView.userLocationStyle`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Added the `NavigationMapView.userLocationStyle` property to customize how the user’s current location is displayed on the map. Set this property to `UserLocationStyle.puck2D(configuration:)` or `UserLocationStyle.puck3D(configuration:)` to use a location indicator layer (`LayerType.locationIndicator`) powered by the Mapbox Maps SDK instead of the default view-backed implementation. ([#2968](https://github.com/mapbox/mapbox-navigation-ios/pull/2968)) +* Removed the `NavigationMapView.userCourseView` property in favor of the associated value when `NavigationMapView.userLocationStyle` is set to `UserLocationStyle.courseView(_:)`. Added `NavigationMapView.reducedAccuracyActivatedMode` property, which allows to control current location styling based on accuracy authorization permission on iOS 14 and above. ([#2968](https://github.com/mapbox/mapbox-navigation-ios/pull/2968), [#3384](https://github.com/mapbox/mapbox-navigation-ios/pull/3384)) +* If you need to customize the appearance of the user location indicator, you can subclass `UserPuckCourseView` and `UserHaloCourseView` as a starting point. ([#2968](https://github.com/mapbox/mapbox-navigation-ios/pull/2968)) +* Added the `UserHaloCourseView.haloBorderWidth` property for changing the width of the ring around the halo view. ([#3309](https://github.com/mapbox/mapbox-navigation-ios/pull/3309)) +* Fixed an issue where setting `UserPuckCourseView.puckColor` in a `Style` subclass had no effect. ([#3306](https://github.com/mapbox/mapbox-navigation-ios/pull/3306)) +* Fixed a memory leak in `UserCourseView`. ([#3120](https://github.com/mapbox/mapbox-navigation-ios/issues/3120)) +* Fixed the pitch issue of `UserHaloCourseView` when map tilted during active guidance navigation. ([#3407](https://github.com/mapbox/mapbox-navigation-ios/issues/3407)) +* Added the `UserPuckCourseView.minimizesInOverview` property, which allows to disable `UserPuckCourseView` minimization in case when navigation camera state is `NavigationCameraState.overview`. ([#3460](https://github.com/mapbox/mapbox-navigation-ios/issues/3460)) + +#### Route overlay + +* Removed the `NavigationAnnotation` class. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed the `MBRouteLineWidthByZoomLevel` property to `Constants.RouteLineWidthByZoomLevel` and changed its type to `Double` for keys and values. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed the `MBCurrentLegAttribute` and `MBCongestionAttribute` constants to `Constants.CurrentLegAttribute` and `Constants.CongestionAttribute`, respectively. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Added the `NavigationMapView.navigationMapView(_:didAdd:pointAnnotationManager:)` and `NavigationViewController.navigationViewController(_:didAdd:pointAnnotationManager:)` delegate methods, which are called whenever a `PointAnnotation` is added to a `NavigationMapView` or `NavigationViewController`, respectively, to represent the final destination. Added the `NavigationMapView.pointAnnotationManager` property for managing point annotations. ([#2961](https://github.com/mapbox/mapbox-navigation-ios/pull/2961), [#3109](https://github.com/mapbox/mapbox-navigation-ios/pull/3109)) +* When specifying the `legIndex` in `NavigationMapView.show(_:legIndex:)`, the route line for the specific route leg shows color-coded congestion segments, while other route legs are stroked with `NavigationMapView.routeCasingColor` by default. If the leg index is unspecified, all the route legs show color-coded congestion. During turn-by-turn navigation, the default specified route leg is the current route leg. You can override the route leg colors using properties such as `NavigationMapView.routeCasingColor` and `NavigationMapView.trafficHeavyColor`. Added the `NavigationMapView.showsCongestionForAlternativeRoutes` property to show congestion levels with different colors on alternative route lines. ([#2833](https://github.com/mapbox/mapbox-navigation-ios/pull/2833), [#2887](https://github.com/mapbox/mapbox-navigation-ios/pull/2887)) +* Fixed an issue where the route line disappears when changing a `NavigationMapView`’s style. ([#3136](https://github.com/mapbox/mapbox-navigation-ios/pull/3136)) +* Renamed the `NavigationMapView.updateRoute(_:)` method to `NavigationMapView.travelAlongRouteLine(to:)`. Improved the performance of updating the route line to change color at the user’s location as they progress along the route. ([#3201](https://github.com/mapbox/mapbox-navigation-ios/pull/3201)). +* Fixed an issue where the route line grows backwards when the `NavigationViewController.routeLineTracksTraversal` property is set to `true` and the user passes the destination. ([#3255](https://github.com/mapbox/mapbox-navigation-ios/pull/3255)) +* Fixed incorrect color-coded traffic congestion along the route line and incorrect speeds in the speed limit view after some time had elapsed after rerouting. ([#3344](https://github.com/mapbox/mapbox-navigation-ios/pull/3344])) +* By default, there is no longer a subtle crossfade between traffic congestion segments along a route line. To reenable this crossfade, set the `NavigationMapView.crossfadesCongestionSegments` property to `true`. You can also adjust the length of this crossfade using the global variable `GradientCongestionFadingDistance`. ([#3153](https://github.com/mapbox/mapbox-navigation-ios/pull/3153), [#3307](https://github.com/mapbox/mapbox-navigation-ios/pull/3307)) +* The duration annotations added by the `NavigationMapView.showRouteDurations(along:)` method are now set in the fonts you specify using the `NavigationMapView.routeDurationAnnotationFontNames` property. Use this property to specify a list of fallback fonts for better language support. ([#2873](https://github.com/mapbox/mapbox-navigation-ios/pull/2873)) +* Fixed an issue when route line was sometimes invisible after starting turn-by-turn navigation. ([#3205](https://github.com/mapbox/mapbox-navigation-ios/pull/3205)) + +### Banners and guidance instructions + +* Removed the `InstructionsBannerViewDelegate.didDragInstructionsBanner(_:)` method. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Removed the `StatusView.delegate` and `StatusView.canChangeValue` properties and the `StatusViewDelegate` and `DeprecatedStatusViewDelegate` protocols. ([#2993](https://github.com/mapbox/mapbox-navigation-ios/pull/2993)) +* Removed the `BottomBannerViewController(delegate:)` initializer. ([#2993](https://github.com/mapbox/mapbox-navigation-ios/pull/2993)) +* The top banner can now show a wider variety of turn lane configurations, such as combination U-turn/left turn lanes and combination through/slight right turn lanes. ([#2882](https://github.com/mapbox/mapbox-navigation-ios/pull/2882)) +* Fixed an issue where the current road name label flashed when the camera state changed or the user traveled onto an unnamed road. ([#2958](https://github.com/mapbox/mapbox-navigation-ios/pull/2958)) +* Fixed an issue where the current road name label sometimes displayed the name of an intersecting road instead of the current road or blinked in and out. ([#3257](https://github.com/mapbox/mapbox-navigation-ios/pull/3257)) +* Fixed an issue where lane guidance icons would sometimes highlight the wrong arrow. ([#2942](https://github.com/mapbox/mapbox-navigation-ios/pull/2942)) +* Fixed an issue where instruction banners could appear in the wrong color after switching between `Style`s. ([#2977](https://github.com/mapbox/mapbox-navigation-ios/pull/2977)) +* Fixed an issue where `GenericRouteShield` images would ignore changing its foreground color in favor of a cached image. ([#3217](https://github.com/mapbox/mapbox-navigation-ios/pull/3217)) +* Fixed an issue where some banner instructions were occasionally skipped. ([#3265](https://github.com/mapbox/mapbox-navigation-ios/pull/3265)) +* Improved the current road name label’s performance and fixed a potential crash when updating it. ([#3340](https://github.com/mapbox/mapbox-navigation-ios/pull/3340)) +* Fixed an issue where arrival guidance card appears too early. ([#3383](https://github.com/mapbox/mapbox-navigation-ios/pull/3383)) +* Fixed an issue where the noncurrent guidance cards were highlighted. ([#3442](https://github.com/mapbox/mapbox-navigation-ios/pull/3442)) +* Fixed an issue where guidance cards for multi-leg routes could temporarily show fewer cards than available. ([#3451](https://github.com/mapbox/mapbox-navigation-ios/pull/3451)) + +### Location tracking + +* Added the `NavigationLocationProvider` class to conform to `LocationProvider` protocol, which depends on `NavigationLocationManager` to detect the user’s location as it changes during turn-by-turn navigation. `SimulatedLocationManager` and `ReplayLocationManager` can now be used with a standalone `NavigationMapView` through `NavigationMapView.mapView.location.overrideLocationProvider(with:)`. ([#3091](https://github.com/mapbox/mapbox-navigation-ios/pull/3091)) +* Added the `Notification.Name.currentRoadNameDidChange` to detect the road name posted by `RouteController`. ([#3266](https://github.com/mapbox/mapbox-navigation-ios/pull/3266)) +* `RouteController` and `PassiveLocationManager` now conform to the `NavigationHistoryRecording` protocol, which has methods for recording details about a trip for debugging purposes. ([#3157](https://github.com/mapbox/mapbox-navigation-ios/pull/3157), [#3448](https://github.com/mapbox/mapbox-navigation-ios/pull/3448)) +* Renamed the `RouterDataSource.locationProvider` and `EventsManagerDataSource.locationProvider` properties to `RouterDataSource.locationManagerType` and `ActiveNavigationEventsManagerDataSource.locationManagerType`, respectively. ([#3199](https://github.com/mapbox/mapbox-navigation-ios/pull/3199)) +* Renamed the `Router.advanceLegIndex()` method to `Router.advanceLegIndex(completionHandler:)` and the `PassiveLocationDataSource.updateLocation(_:)` method to `PassiveLocationManager.updateLocation(_:completionHandler:)`. These methods are now asynchronous, and their completion handlers indicate whether the operation succeeded. ([#3342](https://github.com/mapbox/mapbox-navigation-ios/pull/3342)) +* Removed the `RouteLegProgress.upComingStep` property. ([#2993](https://github.com/mapbox/mapbox-navigation-ios/pull/2993)) +* Removed the `NavigationViewController.indexedRoute`, `NavigationService.indexedRoute`, and `Router.indexedRoute` properties in favor of `NavigationViewController.indexedRouteResponse`, `NavigationService.indexedRouteResponse`, and `Router.indexedRouteResponse`, respectively. Removed the `RouteProgress.indexedRoute` property. ([#3182](https://github.com/mapbox/mapbox-navigation-ios/pull/3182)) +* The `NavigationViewController.indexedRoute`, `NavigationService.indexedRoute`, `Router.indexedRoute`, and `RouteController.routeProgress` properties are no longer writable. Use the `Router.updateRoute(with:routeOptions:completion:)` method to manually reroute the user. ([#3159](https://github.com/mapbox/mapbox-navigation-ios/pull/#3159), [#3345](https://github.com/mapbox/mapbox-navigation-ios/pull/3345]), [#3432](https://github.com/mapbox/mapbox-navigation-ios/pull/3432)) +* The `NavigationService.router` and `MapboxNavigationService.router` properties are no longer unsafe-unowned. ([#3055](https://github.com/mapbox/mapbox-navigation-ios/pull/3055)) +* Fixed unnecessary rerouting when calling the `NavigationService.start()` method. ([#3239](https://github.com/mapbox/mapbox-navigation-ios/pull/3239)) +* Fixed an issue where `RouteController` or `PassiveLocationManager` sometimes snapped the user’s location assuming a path that violated a turn restriction. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Added `SimulationMode.inTunnels` to enable simulating user location when loosing GPS signal while traversing tunnels. Simulation mode for default navigation service now can be configured using `NavigationOptons.simulationMode`. ([#3314](https://github.com/mapbox/mapbox-navigation-ios/pull/3314)) +* Improved performance and decreased memory usage when downloading routing tiles. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Fixed a crash when navigating along a route 0 meters long (for example, because two waypoints snap to the same location). ([#3387](https://github.com/mapbox/mapbox-navigation-ios/pull/3387)) +* Renamed the `Router.updateRoute(with:routeOptions:)` method to `Router.updateRoute(with:routeOptions:completion:)`. The method is now asynchronous, with a new completion handler that is called when the update has completed. ([#3432](https://github.com/mapbox/mapbox-navigation-ios/pull/3432)) +* Fixed an issue where `RouteController` sometimes incorrectly reported the user’s location as being off-route. ([#3432](https://github.com/mapbox/mapbox-navigation-ios/pull/3432)) +* Fixed a crash due to an invalid `RouteProgress` object. ([#3432](https://github.com/mapbox/mapbox-navigation-ios/pull/3432)) + +#### Passive navigation + +* Renamed `PassiveLocationManager` to `PassiveLocationProvider` and `PassiveLocationDataSource` to `PassiveLocationManager` for consistency with `NavigationLocationProvider` and `NavigationLocationManager`. ([#3091](https://github.com/mapbox/mapbox-navigation-ios/pull/3091)) +* `PassiveLocationProvider` now conforms to the `LocationProvider` protocol instead of `MGLLocationManager`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* The `PassiveLocationProvider.delegate` property is now of type `LocationProviderDelegate` instead of `MGLLocationManagerDelegate`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Replaced `PassiveLocationManager.accuracyAuthorization()` was replaced with the `PassiveLocationProvider.accuracyAuthorization` property, which now returns `CLAccuracyAuthorization` instead of `MBNavigationAccuracyAuthorization`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Fixed a potential hang when `PassiveLocationManager` fails to download routing tiles. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed `PassiveLocationManager.startUpdatingLocation(completionHandler:)` to `PassiveLocationProvider.startUpdatingLocation()`. This method now runs synchronously like `CLLocationManager.startUpdatingLocation()`. ([#2823](https://github.com/mapbox/mapbox-navigation-ios/pull/2823)) + +#### Rerouting + +* `RouteOptions` no longer conforms to `NSCopying`. Use `JSONEncoder` and `JSONDecoder` to get a copy of the `RouteOptions` object round-tripped through JSON. ([#3484](https://github.com/mapbox/mapbox-navigation-ios/pull/3484)) +* Added the `NavigationViewControllerDelegate.navigationViewController(_:shouldPreventReroutesWhenArrivingAt:)` method, which is called each time the user arrives at a waypoint. By default, this method returns true and prevents rerouting upon arriving. ([#3195](https://github.com/mapbox/mapbox-navigation-ios/pull/3195)) +* Renamed `RouteOptions.without(waypoint:)` to `RouteOptions.without(_:)`. ([#3192](https://github.com/mapbox/mapbox-navigation-ios/pull/3192)) +* Rerouting now uses a snapped location instead of a raw location from Core Location. ([#3361](https://github.com/mapbox/mapbox-navigation-ios/pull/3361), [#3644](https://github.com/mapbox/mapbox-navigation-ios/pull/3644)) +* Fixed an issue where a subclass of `NavigationRouteOptions` would turn into an ordinary `RouteOptions` when rerouting the user. ([#3192](https://github.com/mapbox/mapbox-navigation-ios/pull/3192), [#3484](https://github.com/mapbox/mapbox-navigation-ios/pull/3484)) +* Fixed an issue where the `RouteController.indexedRouteResponse` property would remain unchanged after the user is rerouted. ([#3344](https://github.com/mapbox/mapbox-navigation-ios/pull/3344])) +* Fixed an issue where the `IndexedRouteResponse.routeIndex` of the `NavigationService.indexedRouteResponse` property would reset to zero after the user is rerouted. ([#3345](https://github.com/mapbox/mapbox-navigation-ios/pull/3345])) +* Fixed an issue where the user would be rerouted even if `NavigationViewControllerDelegate.navigationViewController(_:shouldRerouteFrom:)` returned `false`. To implement reroute after arrival behavior, return `true` from this method and `false` from `NavigationViewControllerDelegate.navigationViewController(_:shouldPreventReroutesWhenArrivingAt:)`, then set `NavigationViewController.showsEndOfRouteFeedback` to `false`. ([#3195](https://github.com/mapbox/mapbox-navigation-ios/pull/3195)) + +#### Predictive caching and offline navigation + +* A new predictive cache proactively fetches tiles which may become necessary if the device loses its Internet connection at some point during passive or active turn-by-turn navigation. Pass a `PredictiveCacheOptions` instance into the `NavigationOptions(styles:navigationService:voiceController:topBanner:bottomBanner:predictiveCacheOptions:)` initializer as you configure a `NavigationViewController`, or manually call `NavigationMapView.enablePredictiveCaching(options:)`. ([#2830](https://github.com/mapbox/mapbox-navigation-ios/pull/2830)) +* Added the `Directions.calculateOffline(options:completionHandler:)` and `Directions.calculateWithCache(options:completionHandler:)` methods, which incorporate routing tiles from the predictive cache when possible to avoid relying on a network connection to calculate the route. `RouteController` now also uses the predictive cache when rerouting. ([#2848](https://github.com/mapbox/mapbox-navigation-ios/pull/2848)) +* Fixed an issue where `PassiveLocationManager` and `RouteController` did not use the access token and host specified by `PassiveLocationDataSource.directions` and `RouteController.directions`, respectively. Added the `PredictiveCacheOptions.credentials` property for specifying the access token and host used for prefetching resources. ([#2876](https://github.com/mapbox/mapbox-navigation-ios/pull/2876)) +* Added the `NavigationMapView.mapTileStore`, `PassiveLocationManager.navigatorTileStore` and `RouteController.navigatorTileStore` properties for accessing `TileStore` objects that are responsible for downloading map and routing tiles. ([#2955](https://github.com/mapbox/mapbox-navigation-ios/pull/2955)) +* Added the `TilesetDescriptorFactory` class for checking routing tiles in a `TileStore`. The tile storage location is determined by the `NavigationSettings.tileStoreConfiguration` property. ([#3015](https://github.com/mapbox/mapbox-navigation-ios/pull/3015), [#3164](https://github.com/mapbox/mapbox-navigation-ios/pull/3164), [#3215](https://github.com/mapbox/mapbox-navigation-ios/pull/3215)) +* Added the `Notification.Name.navigationDidSwitchToFallbackVersion` and `Notification.Name.navigationDidSwitchToTargetVersion` notifications, which are posted when `PassiveLocationManager` and `RouteController` fall back to an older set of navigation tiles present in the current tile storage. ([#3014](https://github.com/mapbox/mapbox-navigation-ios/pull/3014)) +* Added the `NavigationSettings.directions` and `NavigationSettings.tileStoreConfiguration` properties for ensuring consistent caching between instances of `PassiveLocationManager` and `RouteController`. The `directions` argument of `PassiveLocationManager(directions:systemLocationManager:)`, `RouteController(alongRouteAtIndex:in:options:directions:dataSource:)`, and `MapboxNavigationService(routeResponse:routeIndex:routeOptions:directions:locationSource:eventsManagerType:simulating:routerType:)` now defaults to `NavigationSettings.directions`. ([#3215](https://github.com/mapbox/mapbox-navigation-ios/pull/3215)) +* Removed `Bundle.ensureSuggestedTileURLExists()`, `Bundle.suggestedTileURL` and `Bundle.suggestedTileURL(version:)`. ([#3425](https://github.com/mapbox/mapbox-navigation-ios/pull/3425)) + +### Electronic horizon and route alerts + +* While a `RouteController`, `PassiveLocationProvider`, or `PassiveLocationManager` is tracking the user’s location, you can get notifications about location changes that indicate relevant details in the _electronic horizon_ – the upcoming portion of the routing graph – such as the names of cross streets and upcoming speed limit changes. To receive this information call `RouteController.startUpdatingElectronicHorizon(with:)` or `PassiveLocationManager.startUpdatingElectronicHorizon(with:)` methods and observe the `Notification.Name.electronicHorizonDidUpdatePosition`, `Notification.Name.electronicHorizonDidEnterRoadObject`, `Notification.Name.electronicHorizonDidExitRoadObject`, and `Notification.Name.electronicHorizonDidPassRoadObject` notifications. Use the `RouteController.roadGraph` or `PassiveLocationManager.roadGraph` property to get more information about the edges contained in these notifications. ([#2834](https://github.com/mapbox/mapbox-navigation-ios/pull/2834)) +* **Note:** The Mapbox Electronic Horizon feature of the Mapbox Navigation SDK is in public beta and is subject to changes, including its pricing. Use of the feature is subject to the beta product restrictions in the Mapbox Terms of Service. Mapbox reserves the right to eliminate any free tier or free evaluation offers at any time and require customers to place an order to purchase the Mapbox Electronic Horizon feature, regardless of the level of use of the feature. +* Added the `RouteController.roadObjectMatcher` and `PassiveLocationManager.roadObjectMatcher` properties for creating user-defined road objects by matching location primitives to the road graph. ([#3004](https://github.com/mapbox/mapbox-navigation-ios/pull/3004)) +* Removed the `Alert` enumeration and the `RouteAlert.alert`, `RouteAlert.distance`, `RouteAlert.length`, `RouteAlert.beginCoordinate`, `RouteAlert.endCoordinate`, `RouteAlert.beginSegmentIndex`, and `RouteAlert.endSegmentIndex` properties in favor of a consolidated `RouteAlerts.roadObject` property. ([#2991](https://github.com/mapbox/mapbox-navigation-ios/pull/2991)) +* Added the `RouteController.startUpdatingElectronicHorizon(with:)`, `RouteController.stopUpdatingElectronicHorizon()`, `PassiveLocationManager.startUpdatingElectronicHorizon(with:)` and `PassiveLocationManager.stopUpdatingElectronicHorizon()` methods for managing electronic horizon updates. By default electronic horizon updates are disabled. ([#3475](https://github.com/mapbox/mapbox-navigation-ios/pull/3475)) + +### CarPlay + +* Removed the `CarPlayNavigationDelegate.carPlayNavigationViewControllerDidArrive(_:)` method. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Renamed the `CarPlayManager.mapView` property to `CarPlayManager.navigationMapView`. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Removed the `CarPlayManager.overviewButton` property. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Removed the `CarPlayNavigationViewController.drivingSide` property. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Added the `CarPlayManagerDelegate.carPlayManager(_:shouldPresentArrivalUIFor:)` and `CarPlayNavigationViewController.navigationService(_:didArriveAt:)` methods for determining when to present an arrival user interface. ([#3016](https://github.com/mapbox/mapbox-navigation-ios/pull/3016)) +* Renamed the `CarPlayNavigationDelegate` protocol to `CarPlayNavigationViewControllerDelegate` and the `CarPlayNavigationViewController.carPlayNavigationDelegate` property to `CarPlayNavigationViewController.delegate`. ([#3036](https://github.com/mapbox/mapbox-navigation-ios/pull/3036)) +* The `CarPlayNavigationViewController.styleManager` and `CarPlayMapViewController.styleManager` properties are now read-only. ([#3137](https://github.com/mapbox/mapbox-navigation-ios/pull/3137)) +* Moved the `CarPlaySearchController.searchTemplate(_:updatedSearchText:completionHandler:)`, `CarPlaySearchController.searchTemplate(_:searchTemplate:selectedResult:completionHandler:)` methods to the `CarPlaySearchControllerDelegate` protocol. Renamed the `CarPlaySearchControllerDelegate.resultsOrNoResults(_:limit:)` method to `CarPlaySearchControllerDelegate.searchResults(with:limit:)`. ([#2999](https://github.com/mapbox/mapbox-navigation-ios/pull/2999)) +* `CarPlaySearchControllerDelegate` now conforms to the `CPSearchTemplateDelegate` protocol. ([#2999](https://github.com/mapbox/mapbox-navigation-ios/pull/2999)) +* Added the `NavigationGeocodedPlacemark` struct, which is similar to MapboxGeocoder.swift’s `GeocodedPlacemark` struct but with the addition of the `NavigationGeocodedPlacemark.listItem()` method. Added the `RecentItem` struct to represent a recently selected search result. ([#2999](https://github.com/mapbox/mapbox-navigation-ios/pull/2999)) +* Added the `CarPlayMapViewControllerDelegate` protocol, which provides methods for reacting to events during the browsing and previewing activities. ([#3190](https://github.com/mapbox/mapbox-navigation-ios/pull/3190)) +* Added the `CarPlayMapViewControllerDelegate.carPlayMapViewController(_:didAdd:pointAnnotationManager:)`, `CarPlayNavigationViewControllerDelegate.carPlayNavigationViewController(_:didAdd:pointAnnotationManager:)` and `CarPlayManager.carPlayManager(_:didAdd:to:pointAnnotationManager:)` delegate methods, which will be called whenever the `PointAnnotation` representing the final destination is added to `CarPlayMapViewController`, `CarPlayNavigationViewController` and `CarPlayManager`, respectively. ([#3190](https://github.com/mapbox/mapbox-navigation-ios/pull/3190)) +* A speed limit indicator now appears on the map during the browsing activity. ([#3197](https://github.com/mapbox/mapbox-navigation-ios/pull/3197)) +* A speed limit indicator now can be fully hidden by using `SpeedLimitView.isAlwaysHidden` property. ([#3429](https://github.com/mapbox/mapbox-navigation-ios/pull/3429)) +* Renamed the `CarPlayManagerDelegate.carPlayManager(_:navigationServiceAlong:routeIndex:routeOptions:desiredSimulationMode:)` method to `CarPlayManagerDelegate.carPlayManager(_:navigationServiceFor:routeIndex:routeOptions:desiredSimulationMode:)`. It now returns an optional `NavigationService`; if it is `nil`, a `MapboxNavigationService` will be used by default. ([#3208](https://github.com/mapbox/mapbox-navigation-ios/pull/3208)) +* Renamed the `CarPlayManagerDelegate.carplayManagerShouldDisableIdleTimer(_:)` method to `CarPlayManagerDelegate.carPlayManagerShouldDisableIdleTimer(_:)`. ([#3208](https://github.com/mapbox/mapbox-navigation-ios/pull/3208)) +* Added the `CarPlayManagerDelegate.carPlayManager(_:templateWillAppear:animated:)`, `CarPlayManagerDelegate.carPlayManager(_:templateDidAppear:animated:)`, `CarPlayManagerDelegate.carPlayManager(_:templateWillDisappear:animated:)`, and `CarPlayManagerDelegate.carPlayManager(_:templateDidDisappear:animated:)` methods to pass through the corresponding methods from `CPInterfaceControllerDelegate`. ([#3219](https://github.com/mapbox/mapbox-navigation-ios/pull/3219)) +* Fixed an issue where `CPMapTemplate.tripEstimateStyle` uses dark appearance even if light appearance is selected. ([#3397](https://github.com/mapbox/mapbox-navigation-ios/pull/3397)) +* `CarPlayMapViewController` and `CarPlayNavigationViewController` are now subclassable. ([#3424](https://github.com/mapbox/mapbox-navigation-ios/pull/3424)) +* Added `CPInterfaceController.safePopTemplate(animated:)`, which allows to safely pop back a `CPTemplate` by a single level in the template navigation hierarchy. ([#3426](https://github.com/mapbox/mapbox-navigation-ios/pull/3426)) + +### User feedback + +* You can now solicit user feedback about `PassiveLocationManager` and `NavigationMapView` outside of active turn-by-turn navigation. Use `PassiveLocationManager.eventsManager` property of `NavigationEventsManager` type to create and send user feedback. You can use a `FeedbackViewController` to present the user with the same options as during turn-by-turn navigation. Alternatively, if you present a custom feedback UI, call the `NavigationEventsManager.createFeedback()` method and configure the resulting `FeedbackEvent` with any additional context. ([#3122](https://github.com/mapbox/mapbox-navigation-ios/pull/3122), [#3322](https://github.com/mapbox/mapbox-navigation-ios/pull/3322)) +* The `ActiveNavigationEventsManagerDataSource.router`, `NavigationService.eventsManager`, and `MapboxNavigationService.eventsManager` properties are no longer unsafe-unowned. ([#3055](https://github.com/mapbox/mapbox-navigation-ios/pull/3055)) +* Removed the `EventsManager` type alias. ([#2993](https://github.com/mapbox/mapbox-navigation-ios/pull/2993)) +* Feedback events now include a snapshot of `NavigationViewController` that is taken sooner, when the problem is more likely to be apparent. ([#3049](https://github.com/mapbox/mapbox-navigation-ios/pull/3049)) +* You can now manage the feedback event lifecycle, allowing the user to submit additional details later. Use `NavigationEventsManager.createFeedback()` to create a `FeedbackEvent` and `NavigationEventsManager.sendActiveNavigationFeedback(_:type:description:)` to send it to Mapbox. `FeedbackEvent` conforms to the `Codable` protocol, so your application can store incomplete feedback across sessions if necessary. ([#3154](https://github.com/mapbox/mapbox-navigation-ios/pull/3154), [#3318](https://github.com/mapbox/mapbox-navigation-ios/pull/3318)) +* To submit feedback during passive navigation, use `NavigationEventsManager.createFeedback()` to create a `FeedbackEvent` and `NavigationEventsManager.sendPassiveNavigationFeedback(_:type:description:)` to send it to Mapbox. This method accepts `PassiveNavigationFeedbackType` with feedback types specific to the passive navigation. ([#3154](https://github.com/mapbox/mapbox-navigation-ios/pull/3154), [#3318](https://github.com/mapbox/mapbox-navigation-ios/pull/3318)) +* Added an optional `NavigationEventsManager.userInfo` property that can be sent with all navigation events. The new property can contain application metadata, such as the application name and version, that is included in each event to help Mapbox triage and diagnose unexpected behavior. ([#3007](https://github.com/mapbox/mapbox-navigation-ios/pull/3007)). +* Fixed a missing feedback subtype description for `LooksIncorrectSubtype.incorrectSpeedLimit` and all “other” subtypes. ([#3238](https://github.com/mapbox/mapbox-navigation-ios/pull/3238)) +* Renamed the `FeedbackViewController(eventsManager:)` initializer to `FeedbackViewController(eventsManager:type:)`. You can now customize the view controller to show only the feedback types specific to passive navigation. ([#3323](https://github.com/mapbox/mapbox-navigation-ios/pull/3323)) +* Renamed the `FeedbackType` enumeration to `ActiveNavigationFeedbackType` and the `EventsManagerDataSource` protocol to `ActiveNavigationEventsManagerDataSource`. ([#3327](https://github.com/mapbox/mapbox-navigation-ios/pull/3327)) +* Renamed the user-facing feedback categories and subcategories for active turn-by-turn navigation that are represented at runtime by the `ActiveNavigationFeedbackType` enumeration. ([#3339]((https://github.com/mapbox/mapbox-navigation-ios/pull/3339)) +* Added the ability to pass your own screenshot to the `NavigationEventsManager.createFeedback()` when a user submits a feedback. Screenshots help Mapbox to determine where issues exist for review and correction. ([#3380]((https://github.com/mapbox/mapbox-navigation-ios/pull/3380)) +* Added `NavigationEventsManager.sessionId`, which allows getting session identifier used in feedback and other events. ([#3449](https://github.com/mapbox/mapbox-navigation-ios/pull/3449)) + +### Other changes + +* If your storyboard has a segue to `NavigationViewController` in Navigation.storyboard, you have to call the `NavigationViewController.prepareViewLoading(routeResponse:routeIndex:routeOptions:navigationOptions:)` method in your implementation of the `UIViewController.prepare(for:sender:)` method. ([#2974](https://github.com/mapbox/mapbox-navigation-ios/pull/2974), [#3182](https://github.com/mapbox/mapbox-navigation-ios/pull/3182)) +* Removed the `NavigationViewController.origin` property. ([#2808](https://github.com/mapbox/mapbox-navigation-ios/pull/2808)) +* Fixed a potential memory leak when using `MultiplexedSpeechSynthesizer`. ([#3005](https://github.com/mapbox/mapbox-navigation-ios/pull/3005)) +* Fixed a thread-safety issue in `UnimplementedLogging` protocol implementation. ([#3024](https://github.com/mapbox/mapbox-navigation-ios/pull/3024)) +* Fixed an issue where `UIApplication.shared.isIdleTimerDisabled` was not properly set in some cases. ([#3245](https://github.com/mapbox/mapbox-navigation-ios/pull/3245)) +* Fixed an issue where `LegacyRouteController` could not correctly handle arrival to the intermediate waypoint of a multi leg route. ([#3483](https://github.com/mapbox/mapbox-navigation-ios/pull/3483)) +* Added the `Notification.Name.navigationServiceSimulationDidChange` to detect when the navigation service changes the simulating status, including `MapboxNavigationService.NotificationUserInfoKey.simulationStateKey` and `MapboxNavigationService.NotificationUserInfoKey.simulatedSpeedMultiplierKey`. ([#3393](https://github.com/mapbox/mapbox-navigation-ios/pull/3393)). +* By default, `NavigationRouteOptions` requests `AttributeOptions.maximumSpeedLimit` attributes along the route with the `DirectionsProfileIdentifier.walking` profile as with other profiles. ([#3496](https://github.com/mapbox/mapbox-navigation-ios/pull/3496)) + +## v1.4.1 + +* Fixed the moment of custom feedback event creation. ([#2495](https://github.com/mapbox/mapbox-navigation-ios/pull/2495)) +* Fixed a bug in `RouterDelegate.router(_:shouldDiscard:)` handling. If you implemented this method, you will need to reverse the value you return. Previously, if you returned `true`, the `Router` wouldn't discard the location. ([#3058](https://github.com/mapbox/mapbox-navigation-ios/pull/3058)) + +## v1.4.0 + +* Increased the minimum version of `MapboxNavigationNative` to v32.0.0. ([#2910](https://github.com/mapbox/mapbox-navigation-ios/pull/2910)) +* Fixed an issue when feedback UI was always appearing for short routes. ([#2871](https://github.com/mapbox/mapbox-navigation-ios/pull/2871)) +* Fixed automatic day/night switching. ([#2881](https://github.com/mapbox/mapbox-navigation-ios/pull/2881)) +* Fixed an issue where presenting `NavigationViewController` could sometimes interfere with view presentation in other windows. ([#2897](https://github.com/mapbox/mapbox-navigation-ios/pull/2897)) +* Added an optional `StyleManagerDelegate.styleManager(_:viewForApplying:)` method to determine which part of the view hierarchy is affected by a change to a different `Style`. ([#2897](https://github.com/mapbox/mapbox-navigation-ios/pull/2897)) +* Added the `NavigationViewController.styleManager`, `StyleManager.currentStyleType`, and `StyleManager.currentStyle` properties and the `StyleManager.applyStyle(type:)` method to manually change the UI style at any time. ([#2888](https://github.com/mapbox/mapbox-navigation-ios/pull/2888)) +* Fixed crash when switching between day / night modes. ([#2896](https://github.com/mapbox/mapbox-navigation-ios/pull/2896)) +* Added support for iOS 13's UIScene based CarPlay API. ([#2832](https://github.com/mapbox/mapbox-navigation-ios/pull/2832)) +* Added an optional `CarPlayManagerDelegate.carPlayManager(_:didPresent:)` method that is called when `CarPlayManager` presents a new navigation session. ([#2832](https://github.com/mapbox/mapbox-navigation-ios/pull/2832)) + +## v1.3.0 + +* MapboxCoreNavigation can now be installed using Swift Package Manager. ([#2771](https://github.com/mapbox/mapbox-navigation-ios/pull/2771)) +* The CarPlay guidance panel now shows lane guidance. ([#1885](https://github.com/mapbox/mapbox-navigation-ios/pull/1885)) +* Old versions of routing tiles are automatically deleted from the cache to save storage space. ([#2807](https://github.com/mapbox/mapbox-navigation-ios/pull/2807)) +* Fixed an issue where lane guidance icons would indicate the wrong arrow for certain maneuvers. ([#2796](https://github.com/mapbox/mapbox-navigation-ios/pull/2796), [#2809](https://github.com/mapbox/mapbox-navigation-ios/pull/2809)) +* Fixed a crash showing a junction view. ([#2805](https://github.com/mapbox/mapbox-navigation-ios/pull/2805)) +* Fixed an issue with CarPlay visual instructions where U-Turn maneuver icons were not being flipped properly based on regional driving side ([#2803](https://github.com/mapbox/mapbox-navigation-ios/pull/2803)) +* Fixed swiping for right-to-left languages for the Guidance Card UI to be more intuitive. ([#2724](https://github.com/mapbox/mapbox-navigation-ios/pull/2724)) +* `NavigationViewController` can now manage multiple status banners one after another. Renamed the `NavigationViewController.showStatus(title:spinner:duration:animated:interactive:)` method to `NavigationViewController.show(_:)` and added a corresponding `NavigationViewController.hide(_:)` method. Renamed the `NavigationStatusPresenter.showStatus(title:spinner:duration:animated:interactive:)` method to `NavigationStatusPresenter.show(_:)` and added a `NavigationStatusPresenter.hide(_:)` method. ([#2747](https://github.com/mapbox/mapbox-navigation-ios/pull/2747)) + +## v1.2.1 + +* Increased the minimum versions of `MapboxNavigationNative` to v30.0 and `MapboxCommon` to v9.2.0. ([#2793](https://github.com/mapbox/mapbox-navigation-ios/pull/2793)) +* Fixed an issue that caused the App Store to reject some application submissions with error ITMS-90338. ([#2793](https://github.com/mapbox/mapbox-navigation-ios/pull/2793)) + +## v1.2.0 + +### Packaging + +* Increased the minimum versions of `MapboxNavigationNative` to v29.0, `MapboxCommon` to v9.1.0 and `MapboxDirections` to v1.2. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694), [#2770](https://github.com/mapbox/mapbox-navigation-ios/pull/2770), [#2781](https://github.com/mapbox/mapbox-navigation-ios/pull/2781)) +* Installing MapboxCoreNavigation using CocoaPods no longer overrides the `EXCLUDED_ARCHS` build setting of your application’s target. Installing MapboxNavigation still overrides this setting. ([#2770](https://github.com/mapbox/mapbox-navigation-ios/pull/2770)) +* Added a Ukrainian localization. ([#2735](https://github.com/mapbox/mapbox-navigation-ios/pull/2735)) + +### Map + +* Added the ability to customize the floating buttons in navigation view. The floating buttons could be edited with `NavigationViewController.floatingButtons`, the position of the floating buttons could be edited with `NavigationViewController.floatingButtonsPosition`. ([#2763](https://github.com/mapbox/mapbox-navigation-ios/pull/2763)) +* Fixed an issue which was causing clear map button disappearance in the example app when selecting the route. ([#2718](https://github.com/mapbox/mapbox-navigation-ios/pull/2718)) +* Fixed an issue where maneuver icon was not shown after selecting specific step. ([#2728](https://github.com/mapbox/mapbox-navigation-ios/pull/2728)) +* Added the ability to style each route line differently using such delegate methods ([#2719](https://github.com/mapbox/mapbox-navigation-ios/pull/2719)): + * `NavigationMapViewDelegate.navigationMapView(_:mainRouteStyleLayerWithIdentifier:source:)` to style the main route. + * `NavigationMapViewDelegate.navigationMapView(_:mainRouteCasingStyleLayerWithIdentifier:source:)` to style the casing of the main route. + * `NavigationMapViewDelegate.navigationMapView(_:alternativeRouteStyleLayerWithIdentifier:source:)` to style alternative route. + * `NavigationMapViewDelegate.navigationMapView(_:alternativeRouteCasingStyleLayerWithIdentifier:source:)` to style the casing of alternative route. +* Fixed an issue where the route line periodically peeked out from behind the user puck even though `NavigationViewController.routeLineTracksTraversal` was enabled. ([#2737](https://github.com/mapbox/mapbox-navigation-ios/pull/2737)) +* Created the `UserHaloCourseView` similar to `UserCourseView` for approximate location on iOS 14 during the navigation to represent user location. Allow the switch between `UserHaloCourseView` and `UserCourseView` when precise mode is changed. ([#2664](https://github.com/mapbox/mapbox-navigation-ios/pull/2664)) +* Added option to show route duration callouts when previewing route alternatives ([#2734](https://github.com/mapbox/mapbox-navigation-ios/pull/2734)): + * `NavigationMapView.showRouteDurations(along:)` to show duration annotation callouts on the map for the provided routes. + * `NavigationMapView.removeRouteDurations()` to remove any route duration annotations currently displayed on the map. + +### Instruction banners + +* Fixed an issue which was preventing the ability to customize the bottom banner height. ([#2705](https://github.com/mapbox/mapbox-navigation-ios/pull/2705)) +* Fixed an issue which was preventing the ability to scroll between instructions cards on iOS 14 using workaround. ([#2755](https://github.com/mapbox/mapbox-navigation-ios/pull/2755)) +* Fixed an instructions cards layout issue that arose when changing orientation (portrait to landscape). ([#2755](https://github.com/mapbox/mapbox-navigation-ios/pull/2755)) +* Fixed swiping for right-to-left languages for the traditional top banner to be more intuitive. ([#2755](https://github.com/mapbox/mapbox-navigation-ios/pull/2755)) +* Fixed an issue which was returning incorrect card width after multiple rotations on iPads by adding `InstructionsCardViewController.viewWillTransition(to:with:)`. ([#2724](https://github.com/mapbox/mapbox-navigation-ios/pull/2724)) + +### Location tracking + +* Fixed potential crashes when using `PassiveLocationManager` or `PassiveLocationDataSource`. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694)) +* Fixed repeated rerouting when traveling alongside a freeway off-ramp. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694)) +* Fixed repeated rerouting when starting a new leg while the user is too far from the new leg’s origin. ([#2781](https://github.com/mapbox/mapbox-navigation-ios/pull/2781)) +* `RouteController` more reliably detects when the user has gone off-route. ([#2781](https://github.com/mapbox/mapbox-navigation-ios/pull/2781)) +* Fixed an issue where `RouteController` snapped the user’s location to the opposite side of a divided highway. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694)) +* Fixed an issue where `RouteController` got stuck after making a U-turn. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694)) + +### Other changes + +* The user can now report feedback about an incorrect speed limit in the speed limit view. ([#2725](https://github.com/mapbox/mapbox-navigation-ios/pull/2725)) +* Added the `RouteProgress.upcomingRouteAlerts` property to track upcoming points along the route experiencing conditions that may require the user’s attention. The `UpcomingRouteAlertInfo.alert` property contains one of the following types with more details about the alert: `Incident`, `TunnelInfo`, `BorderCrossingInfo`, `TollCollection`, and `RestStop`. ([#2694](https://github.com/mapbox/mapbox-navigation-ios/pull/2694)) +* Added a new `NavigationMapView.roadClassesWithOverriddenCongestionLevels` property. For any road class in it all route segments with an `CongestionLevel.unknown` traffic congestion level and a matching `Intersection.outletMapboxStreetsRoadClass` will be replaced with the `CongestionLevel.low` congestion level. ([#2741](https://github.com/mapbox/mapbox-navigation-ios/pull/2741)) +* Added a new `RouteLeg.streetsRoadClasses` property, which allows to get a collection of `MapboxStreetsRoadClass` objects for specific `RouteLeg`. ([#2741](https://github.com/mapbox/mapbox-navigation-ios/pull/2741)) +* `NavigationAnnotation` was made public to provide a way to detect annotations created by `NavigationMapView`. ([#2769](https://github.com/mapbox/mapbox-navigation-ios/pull/2769)) + +## v1.1.0 + +### Packaging + +* MapboxNavigationNative dependency was updated to v22.0.5 and MapboxCommon to v7.1.2. ([#2648](https://github.com/mapbox/mapbox-navigation-ios/pull/2648)) + +### User location + +* Fixed issues which was causing unsmooth user puck updates on iOS and inability to zoom-in to current location at the start of navigation on CarPlay by updating to Mapbox Maps SDK for iOS v6.2.2. ([#2699](https://github.com/mapbox/mapbox-navigation-ios/pull/2699)) +* Added the `NavigationServiceDelegate.navigationService(_:didChangeAuthorizationFor:)` method and `Notification.Name.locationAuthorizationDidChange` to detect when the user changes the Location Services permissions for the current application, including for approximate location on iOS 14. ([#2693](https://github.com/mapbox/mapbox-navigation-ios/pull/2693)) +* When approximate location is enabled on iOS 14, a banner appears reminding the user to disable approximate location to continue navigating. ([#2693](https://github.com/mapbox/mapbox-navigation-ios/pull/2693)) + +### Other changes + +* `RouteProgress`, `RouteLegProgress`, and `RouteStepProgress` now conform to the `Codable` protocol. ([#2615](https://github.com/mapbox/mapbox-navigation-ios/pull/2615)) +* Fixed an issue where `NavigationMapView` redrew at a low frame rate even when the device was plugged in. ([#2643](https://github.com/mapbox/mapbox-navigation-ios/pull/2643)) +* Fixed an issue where the route line flickered when refreshing. ([#2642](https://github.com/mapbox/mapbox-navigation-ios/pull/2642)) +* Fixed an issue where the End of route view UI is broken prior to iOS 11. ([#2690](https://github.com/mapbox/mapbox-navigation-ios/pull/2690)) +* Fixed an issue where completed waypoints remained on map after rerouting. ([#2378](https://github.com/mapbox/mapbox-navigation-ios/pull/2378)) +* Fixed an issue where positioning icon was not highlighted on CarPlay when using iOS 14.0. ([#2697](https://github.com/mapbox/mapbox-navigation-ios/pull/2697)) +* Fixed an issue where ETA label font was too small during turn-by-turn navigation. ([#2679](https://github.com/mapbox/mapbox-navigation-ios/pull/2679)) +* Fixed an issue with `NavigationMapViewDelegate.navigationMapView(_:shapeFor:)` and `NavigationMapViewDelegate.navigationMapView(_:simplifiedShapeFor:)` methods were not correctly called for route shape customization ([#2623](https://github.com/mapbox/mapbox-navigation-ios/pull/2623)) +* Fixed an issue where the banner indicating simulation mode displayed a very large speed factor in the Hebrew location. ([#2714](https://github.com/mapbox/mapbox-navigation-ios/pull/2714)) +* Fixed an issue where incorrect speed multiplier value was shown after arriving to the intermediate waypoint. ([#2710](https://github.com/mapbox/mapbox-navigation-ios/pull/2710)) + + +## v1.0.0 + +### Packaging + +* By default, usage of Mapbox APIs is now [billed](https://www.mapbox.com/pricing/#navmaus) together based on [monthly active users](https://docs.mapbox.com/help/glossary/monthly-active-users/) rather than individually by HTTP request. Learn more in the [pricing guide](https://docs.mapbox.com/ios/navigation/guides/pricing/). ([#2405](https://github.com/mapbox/mapbox-navigation-ios/pull/2405)) +* Carthage v0.35 or above is now required for installing this SDK if you use Carthage. ([`81a36d0`](https://github.com/mapbox/mapbox-navigation-ios/commit/81a36d090e8a0602b7144ee7697b7857675b496f)) +* MapboxNavigation depends on Mapbox Maps SDK for iOS v6.0.0, and MapboxCoreNavigation depends on builds of MapboxNavigationNative and MapboxCommon that require authentication. Before CocoaPods or Carthage can download Mapbox.framework, MapboxNavigationNative.framework, and MapboxCommon.framework, you need to create a special-purpose access token. See [the updated installation instructions in the readme](./README.md#installing-the-latest-prerelease) for more details. ([#2437](https://github.com/mapbox/mapbox-navigation-ios/pull/2437), [#2477](https://github.com/mapbox/mapbox-navigation-ios/pull/2477)) +* If you install this SDK using Carthage, you need to also add MapboxCommon.framework to your application target’s Embed Frameworks build phase. ([#2477](https://github.com/mapbox/mapbox-navigation-ios/pull/2477)) +* Xcode 11.4.1 or above is now required for building this SDK from source. ([#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* Added Greek and Turkish localizations. ([#2385](https://github.com/mapbox/mapbox-navigation-ios/pull/2385), [#2475](https://github.com/mapbox/mapbox-navigation-ios/pull/2475)) +* Upgraded to [MapboxDirections v1.0.0](https://github.com/mapbox/mapbox-directions-swift/releases/tag/v1.0.0), [MapboxSpeech v1.0.0](https://github.com/mapbox/mapbox-speech-swift/releases/tag/v1.0.0), and [Turf v1.0.0](https://github.com/mapbox/turf-swift/releases/tag/v1.0.0). ([#2646](https://github.com/mapbox/mapbox-navigation-ios/pull/2646)) + +### Map + +* The `MGLStyle.navigationDayStyleURL` and `MGLStyle.navigationNightStyleURL` properties contain URLs to the Mapbox Navigation Day and Night v5 styles, both of which show traffic congestion lines on all roads by default. The traffic congestion layer is appropriate for a preview map; to tailor the style to turn-by-turn navigation, set `MGLMapView.showsTraffic` to `false`. ([#2523](https://github.com/mapbox/mapbox-navigation-ios/pull/2523)) +* A portion of the route line now disappears behind the user puck as the user travels along the route during turn-by-turn navigation if `NavigationViewController.routeLineTracksTraversal` is set to `true`. ([#2377](https://github.com/mapbox/mapbox-navigation-ios/pull/2377)) +* Ability to hide the route line behind the user puck on CarPlay can be enabled by setting `CarPlayNavigationViewController.routeLineTracksTraversal` to `true`. ([#2601](https://github.com/mapbox/mapbox-navigation-ios/pull/2601)) +* Traffic congestion segments along the route line and the estimated arrival time periodically update to reflect current conditions when using the `DirectionsProfileIdentifier.automobileAvoidingTraffic` profile. These updates correspond to the new `Notification.Name.routeControllerDidRefreshRoute` notification, `NavigationServiceDelegate.navigationService(_:didRefresh:)` method, and `NavigationViewControllerDelegate.navigationViewController(_:didRefresh:)` method. To disable these updates, set `RouteOptions.refreshingEnabled` to `false`. ([#2366](https://github.com/mapbox/mapbox-navigation-ios/pull/2366)) +* A building at the destination waypoint can be extruded in 3D and highlighted for emphasis and recognizability. To enable building extrusion or highlighting, set the `NavigationViewController.waypointStyle` property. For a standalone map view that is not part of `NavigationViewController`, call the `NavigationMapView.highlightBuildings(at:in3D:)` method to highlight the destination building at a specific coordinate and `NavigationMapView.unhighlightBuildings()` to reverse this effect. ([#2535](https://github.com/mapbox/mapbox-navigation-ios/pull/2535)) +* Replaced the `MGLStyle.navigationPreviewDayStyleURL` and `MGLStyle.navigationGuidanceDayStyleURL` properties with `MGLStyle.navigationDayStyleURL`, and replaced `MGLStyle.navigationPreviewNightStyleURL` and `MGLStyle.navigationGuidanceNightStyleURL` with `MGLStyle.navigationNightStyleURL`. ([#2523](https://github.com/mapbox/mapbox-navigation-ios/pull/2523)) +* Replaced the `MGLStyle.navigationGuidanceDayStyleURL(version:)` and `MGLStyle.navigationGuidanceNightStyleURL(version:)` methods with `MGLStyle.navigationDayStyleURL(version:)` and `MGLStyle.navigationNightStyleURL(version:)` respectively, removed the `MGLStyle.navigationPreviewDayStyleURL(version:)` and `MGLStyle.navigationPreviewNightStyleURL(version:)` methods. ([#2567](https://github.com/mapbox/mapbox-navigation-ios/pull/2567)) +* Removed the `NavigationViewControllerDelegate.navigationViewController(_:imageFor:)` and `NavigationViewControllerDelegate.navigationViewController(_:viewFor:)` methods in favor of `MGLMapViewDelegate.mapView(_:imageFor:)` and `MGLMapViewDelegate.mapView(_:viewFor:)`, respectively. ([#2396](https://github.com/mapbox/mapbox-navigation-ios/pull/2396)) +* Removed `NavigationMapViewDelegate.navigationMapView(_:routeStyleLayerWithIdentifier:source:)`, `NavigationMapViewDelegate.navigationMapView(_:routeCasingStyleLayerWithIdentifier:source:)` in favor of four new delegate methods to customize the route styling ([#2377](https://github.com/mapbox/mapbox-navigation-ios/pull/2377)): + * `NavigationMapViewDelegate.navigationMapView(_:mainRouteStyleLayerWithIdentifier:source:)` to style the main route. + * `NavigationMapViewDelegate.navigationMapView(_:mainRouteCasingStyleLayerWithIdentifier:source:)` to style the casing of the main route. + * `NavigationMapViewDelegate.navigationMapView(_:alternativeRouteStyleLayerWithIdentifier:source:)` to style alternative routes. + * `NavigationMapViewDelegate.navigationMapView(_:alternativeRouteCasingStyleLayerWithIdentifier:source:)` to style the casing of alternative routes. +* Removed the deprecated `NavigationMapView.showRoutes(_:legIndex:)` method in favor of `NavigationMapView.show(_:legIndex:)` and `NavigationMapView.showWaypoints(_:legIndex:)` in favor of `NavigationMapView.showWaypoints(on:legIndex:)`. ([#2539](https://github.com/mapbox/mapbox-navigation-ios/pull/2539)) +* Fixed an issue where the casing for the main route would not overlap alternative routes. ([#2377](https://github.com/mapbox/mapbox-navigation-ios/pull/2377)) +* Fixed memory leaks after disconnecting the application from CarPlay. ([#2470](https://github.com/mapbox/mapbox-navigation-ios/pull/2470)) +* Fixed issue which was causing incorrect alignment of `MGLMapView.attributionButton` and `MGLMapView.logoView`. ([#2613](https://github.com/mapbox/mapbox-navigation-ios/pull/2613)) + +### Visual and spoken instructions + +* As the user approaches certain junctions, an enlarged illustration of the junction appears below the top banner to help the user understand a complex maneuver. These junction views only appear when the relevant data is available. Contact your Mapbox sales representative or [support team](https://support.mapbox.com/) for access to the junction views feature. ([#2408](https://github.com/mapbox/mapbox-navigation-ios/pull/2408)) +* Replaced `RouteVoiceController` and `MapboxVoiceController` with `MultiplexedSpeechSynthesizer`. `MultiplexedSpeechSynthesizer` coordinates multiple cascading speech synthesizers. By default, the controller still tries to speak instructions via the Mapbox Voice API (`MapboxSpeechSynthesizer`) before falling back to VoiceOver (`SystemSpeechSynthesizer`), but you can also provide your own speech synthesizer that conforms to the `SpeechSynthesizing` protocol. ([#2348](https://github.com/mapbox/mapbox-navigation-ios/pull/2348)) +* Added an alternative presentation for maneuver instructions that resembles swipeable user notification cards. To replace the conventional `TopBannerViewController` presentation with the cardlike presentation, create an instance of `InstructionsCardViewController` and pass it into the `NavigationOptions(styles:navigationService:voiceController:topBanner:bottomBanner:)` method. ([#2149](https://github.com/mapbox/mapbox-navigation-ios/pull/2149), [#2296](https://github.com/mapbox/mapbox-navigation-ios/pull/2296), [#2627](https://github.com/mapbox/mapbox-navigation-ios/pull/2627)) + +### Feedback + +* The user can optionally provide more detailed feedback during turn-by-turn navigation. After tapping the feedback button and selecting a feedback type, the user is taken to a second screen for selecting from among multiple subtypes. Set the `FeedbackViewController.detailedFeedbackEnabled` property to `true` to enable two-step feedback. ([#2544](https://github.com/mapbox/mapbox-navigation-ios/pull/2544)) +* Reorganized `FeedbackType` cases ([#2419](https://github.com/mapbox/mapbox-navigation-ios/pull/2419)): + * Removed `FeedbackType.accident`, `FeedbackType.hazard`, `FeedbackType.reportTraffic`, and `FeedbackType.mapIssue`. + * Renamed `FeedbackType.roadClosed` and `FeedbackType.notAllowed` to `FeedbackType.roadClosure(subtype:)` and `FeedbackType.illegalRoute(subtype:)`, respectively. + * Renamed `FeedbackType.routingError` to `FeedbackType.routeQuality(subtype:)`. + * Renamed `FeedbackType.confusingInstruction` to `FeedbackType.confusingAudio(subtype:)`. + * Added `FeedbackType.incorrectVisual(subtype:)`, `FeedbackType.routeQuality(subtype:)`, and `FeedbackType.positioning(subtype:)`. + * `FeedbackType.missingRoad` is now represented as `FeedbackType.routeQuality(subtype:)` with a subtype of `RouteQualitySubtype.routeIncludedMissingRoads`. + * `FeedbackType.missingExit` is now represented as `FeedbackType.incorrectVisual(subtype:)` with a subtype of `IncorrectVisualSubtype.exitInfoIncorrect`. +* `FeedbackViewController` no longer dismisses automatically after 10 seconds. ([#2420](https://github.com/mapbox/mapbox-navigation-ios/pull/2420)) +* Refreshed the feedback type icons. ([#2419](https://github.com/mapbox/mapbox-navigation-ios/pull/2419), [#2421](https://github.com/mapbox/mapbox-navigation-ios/pull/2421)) +* Fixed warnings in Interface Builder that prevented styling of UI components in `EndOfRouteViewController`. ([#2518](https://github.com/mapbox/mapbox-navigation-ios/pull/2518)) + +### User location + +* Improved the accuracy of location tracking and off-route detection. ([#2319](https://github.com/mapbox/mapbox-navigation-ios/pull/2319)) +* Added the `PassiveLocationManager` class for use with the `MGLMapView.locationManager` property. Unlike `CLLocationManager`, this class causes the map view to display user locations snapped to the road network, just like during turn-by-turn navigation. To receive these locations without an `MGLMapView`, use the `PassiveLocationDataSource` class and implement the `PassiveLocationDataSourceDelegate.passiveLocationDataSource(_:didUpdateLocation:rawLocation:)` method or observe `Notification.Name.passiveLocationDataSourceDidUpdate` notifications. ([#2410](https://github.com/mapbox/mapbox-navigation-ios/pull/2410)) +* The `NavigationViewController.route` and `NavigationService.route` properties are now read-only. To change the route that the user is traveling along, set the `NavigationViewController.indexedRoute` or `NavigationService.indexedRoute` property instead, pairing the route with the index of the route in the original `RouteResponse` object. ([#2366](https://github.com/mapbox/mapbox-navigation-ios/pull/2366)) +* The following methods now require a route index to be passed in as an argument ([#2366](https://github.com/mapbox/mapbox-navigation-ios/pull/2366)): + * `NavigationViewController(for:routeIndex:routeOptions:navigationOptions:)` + * `NavigationViewController(route:routeIndex:routeOptions:navigationService:)` + * `CarPlayManagerDelegate.carPlayManager(_:navigationServiceAlong:routeIndex:routeOptions:desiredSimulationMode:)` + * `MapboxNavigationService(route:routeIndex:routeOptions:)` + * `MapboxNavigationService(route:routeIndex:routeOptions:directions:locationSource:eventsManagerType:simulating:routerType:)` + * `RouteProgress(route:routeIndex:options:legIndex:spokenInstructionIndex:)` + * `RouteProgress(route:routeIndex:options:legIndex:spokenInstructionIndex:)` + * `Router(along:routeIndex:options:directions:dataSource:)` + * `RouteController(along:routeIndex:options:directions:dataSource:)` +* Fixed an issue where location tracking would pause at the beginning of a route after setting `RouteOptions.shapeFormat` to `RouteShapeFormat.polyline` or `RouteShapeFormat.geoJSON`. Note that you most likely do not need to override the default value of `RouteShapeFormat.polyline6`: this is the least bandwidth-intensive format, and `Route.shape` and `RouteStep.shape` are set to `LineString`s regardless. ([#2319](https://github.com/mapbox/mapbox-navigation-ios/pull/2319)) +* Fixed an issue where various delegate methods omitted `CLLocation.courseAccuracy` and `CLLocation.speedAccuracy` properties from passed-in `CLLocation` objects when using `RouteController`, even when these properties are provided by Core Location on iOS 13.4 and above. ([#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* Fixed issues where the user puck would sometimes drift away from the route line even though the user was following the route. ([#2412](https://github.com/mapbox/mapbox-navigation-ios/pull/2412), [#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* Fixed an issue where `RouteController` took longer than usual to detect that the user had gone off-route. ([#2412](https://github.com/mapbox/mapbox-navigation-ios/pull/2412)) +* Fixed an issue where `RouteController` would detect that the user had gone off-route due to a single errant location update. ([#2412](https://github.com/mapbox/mapbox-navigation-ios/pull/2412), [#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* Fixed an issue where the camera and user puck would cut a corner when making a turn at speed. ([#2412](https://github.com/mapbox/mapbox-navigation-ios/pull/2412)) +* Fixed an issue where `RouteController` became too sensitive to the user going off-route near “intersections” that the Mapbox Directions API synthesizes at road classification changes, such as at either end of a tunnel. ([#2412](https://github.com/mapbox/mapbox-navigation-ios/pull/2412)) +* If the user’s raw course as reported by Core Location differs significantly from the direction of the road ahead, the camera and user puck are oriented according to the raw course. ([#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* `RouteController` now tracks the user’s location more accurately within roundabouts. ([#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* Fixed an issue where departure instructions were briefly missing when beginning turn-by-turn navigation. ([#2417](https://github.com/mapbox/mapbox-navigation-ios/pull/2417)) +* Removed the `RouteController.projectedLocation(for:)` method in favor of `RouteController.location`. It is no longer possible to predict the user’s location at an arbitrary time. ([#2610](https://github.com/mapbox/mapbox-navigation-ios/pull/2610)) +* Renamed the `Router.advanceLegIndex(location:)` method to `Router.advanceLegIndex()`. It is no longer possible to advance to an arbitrary leg using this method. ([#2610](https://github.com/mapbox/mapbox-navigation-ios/pull/2610)) + +### Other changes + +* The `RouteProgress.congestionTravelTimesSegmentsByStep` and `RouteProgress.congestionTimesPerStep` properties are now read-only. ([#2624](https://github.com/mapbox/mapbox-navigation-ios/pull/2624)) +* Deprecated `NavigationDirectionsCompletionHandler`, `OfflineRoutingError`, `UnpackProgressHandler`, `UnpackCompletionHandler`, `OfflineRouteCompletionHandler`, and `NavigationDirections`. Use `Directions` instead of `NavigationDirections` to calculate a route. ([#2509](https://github.com/mapbox/mapbox-navigation-ios/pull/2509)) + +## v0.40.0 + +### Packaging +* This SDK can no longer be used in applications written in pure Objective-C. If you need to use this SDK’s public API from Objective-C code, you will need to implement a wrapper in Swift that bridges the subset of the API you need from Swift to Objective-C. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) +* Added a new dependency on MapboxAccounts to prepare for upcoming improvements to how Mapbox [bills](https://www.mapbox.com/pricing/) this SDK’s usage of Mapbox APIs. If you use Carthage to install this SDK, remember to add MapboxAccounts.framework to the “Frameworks, Libraries, and Embedded Content” section and the input and output file lists of Carthage’s Run Script build phase. ([#2151](https://github.com/mapbox/mapbox-navigation-ios/pull/2151)) +* Upgraded to [Mapbox Maps SDK for iOS v5.6._x_](https://github.com/mapbox/mapbox-gl-native-ios/releases/tag/ios-v5.6.0). ([#2302](https://github.com/mapbox/mapbox-navigation-ios/pull/2302)) +* Fixed sporadic build failures after installing this SDK using CocoaPods. ([#2368](https://github.com/mapbox/mapbox-navigation-ios/pull/2368)) + +### Top and bottom banners +* Removed `BottomBannerViewController(delegate:)` in favor of `BottomBannerViewController()` and the `BottomBannerViewController.delegate` property’s setter. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed the `StatusView.canChangeValue` property in favor of `StatusView.isEnabled`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) + +### Map +* `UserCourseView` is now a type alias of the `UIView` class and the `CourseUpdatable` protocol rather than a protocol in its own right. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) +* Renamed `NavigationMapView.showRoutes(_:legIndex:)` to `NavigationMapView.show(_:legIndex:)`. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) +* Renamed `NavigationMapView.showWaypoints(_:legIndex:)` to `NavigationMapView.showWaypoints(on:legIndex:)`. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) +* Removed the `NavigationMapView.navigationMapDelegate` property in favor of `NavigationMapView.navigationMapViewDelegate`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Added a speed limit indicator to the upper-left corner of the map view during turn-by-turn navigation (upper-right corner in CarPlay). To hide the speed limit indicator, set the `NavigationViewController.showsSpeedLimits` property to `false`. To customize the indicator’s colors, configure `SpeedLimitView`’s appearance proxy inside a `Style` subclass. ([#2291](https://github.com/mapbox/mapbox-navigation-ios/pull/2291)) +* Fixed an issue where the current road name label contained an oversized route shield when the current map style was a custom style created in Mapbox Studio. ([#2357](https://github.com/mapbox/mapbox-navigation-ios/pull/2357)) + +### Spoken instructions +* Removed `MapboxVoiceController.play(_:)` in favor of `MapboxVoiceController.play(instruction:data:)`. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230), [#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* The `MapboxVoiceController.speakWithDefaultSpeechSynthesizer(_:error:)` and `VoiceControllerDelegate.voiceController(_:spokenInstructionsDidFailWith:)` methods now accept a `SpeechError` instance instead of an `NSError` object. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) +* Added the `VoiceControllerDelegate.voiceController(_:didFallBackTo:becauseOf:)` method for detecting when the voice controller falls back to `AVSpeechSynthesizer`. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) + +### User location +* Removed the `NavigationViewController.routeController` property and `LegacyRouteController(along:directions:dataSource:eventsManager:)`. To use `LegacyRouteController` instead of the default `RouteController` class, pass that type into `MapboxNavigationService(route:directions:locationSource:eventsManagerType:simulating:routerType:)`, pass the `MapboxNavigationService` object into `NavigationOptions(styles:navigationService:voiceController:topBanner:bottomBanner:)`, and pass the `NavigationOptions` object into `NavigationViewController(route:navigationService:)`. To access `LegacyRouteController`, use the `NavigationViewController.navigationService` and `NavigationService.router` properties and cast the value of `NavigationService.router` to a `LegacyRouteController`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed the `NavigationViewController.locationManager` and `LegacyRouteController.locationManager` properties in favor of `NavigationService.locationManager`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed `RouteLegProgress.upComingStep` in favor of `RouteLegProgress.upcomingStep`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed the `RouteProgress.nearbyCoordinates` property in favor of `RouteProgress.nearbyShape`. ([#2275](https://github.com/mapbox/mapbox-navigation-ios/pull/2275), [#2275](https://github.com/mapbox/mapbox-navigation-ios/pull/2275)) +* Removed the `LegacyRouteController.tunnelIntersectionManager` property. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) + +### Other changes +* Various delegate protocols now provide default no-op implementations for all their methods and conform to the `UnimplementedLogging` protocol, which can inform you at runtime when a delegate method is called but has not been implemented. This replaces the use of optional methods, which are disallowed in pure Swift protocols. Messages are sent through Apple Unified Logging and can be disabled globally through [Unifed Logging](https://developer.apple.com/documentation/os/logging#2878594), or by overriding the delegate function with a no-op implementation. ([#2230](https://github.com/mapbox/mapbox-navigation-ios/pull/2230)) +* Removed `NavigationViewController(for:styles:navigationService:voiceController:)` and `NavigationViewController(for:directions:styles:routeController:locationManager:voiceController:eventsManager:)` in favor of `NavigationViewController(route:options:)`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed the `EventsManager` type alias in favor of the `NavigationEventsManager` class. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed the `NavigationViewController.eventsManager` and `LegacyRouteController.eventsManager` properties in favor of `NavigationService.eventsManager`. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* Removed the `NavigationViewController.carPlayManager(_:didBeginNavigationWith:window:delegate:)` and `NavigationViewController.carPlayManagerDidEndNavigation(_:window:)` methods. To mirror CarPlay navigation on the main device, present and dismiss a `NavigationViewController` in the `CarPlayManagerDelegate.carPlayManager(_:didBeginNavigationWith:)` and `CarPlayManagerDelegate.carPlayManagerDidEndNavigation(_:)` methods, respectively. ([#2297](https://github.com/mapbox/mapbox-navigation-ios/pull/2297)) +* When Dark Mode is enabled, user notifications now draw maneuver icons in white instead of black for better contrast. ([#2283](https://github.com/mapbox/mapbox-navigation-ios/pull/2283)) +* Added the `RouteLegProgress.currentSpeedLimit` property. ([#2114](https://github.com/mapbox/mapbox-navigation-ios/pull/2114)) +* Added convenience initializers for converting Turf geometry structures into `MGLShape` and `MGLFeature` objects such as `MGLPolyline` and `MGLPolygonFeature`. ([#2308](https://github.com/mapbox/mapbox-navigation-ios/pull/2308)) +* Fixed an issue where the “End Navigation” button in the end-of-route feedback panel appeared in English regardless of the current localization. ([#2315](https://github.com/mapbox/mapbox-navigation-ios/pull/2315)) + +## v0.39.0 + +* Upgraded to [Mapbox Maps SDK for iOS v5.5.1](https://github.com/mapbox/mapbox-gl-native-ios/releases/tag/ios-v5.5.1). (#2341) +* Fixed an issue where the spoken instructions always fell back to VoiceOver when the `MGLMapboxAPIBaseURL` key was set in the Info.plist file. ([#2329](https://github.com/mapbox/mapbox-navigation-ios/pull/2329)) +* Fixed a crash when setting certain properties of a `Style` subclass to a dynamic color. ([#2338](https://github.com/mapbox/mapbox-navigation-ios/pull/2338)) + +## v0.38.3 + +* Fixed a crash on launch if this SDK is installed using Carthage. ([#2317](https://github.com/mapbox/mapbox-navigation-ios/pull/2317)) +* Fixed a crash when the first visual instruction contained a route shield or exit number and the application’s user interface was written in SwiftUI. ([#2323](https://github.com/mapbox/mapbox-navigation-ios/pull/2323)) +* Fixed an issue where a black background could appear under the arrow in a `ManeuverView` regardless of the view’s `backgroundColor` property. ([#2279](https://github.com/mapbox/mapbox-navigation-ios/pull/2279)) +* Fixed an issue where the wrong style was applied to exit numbers in the top banner and for subsequent maneuver banners in CarPlay, resulting in poor contrast. ([#2280](https://github.com/mapbox/mapbox-navigation-ios/pull/2280)) + +## v0.38.2 + +* Fixed a crash on launch if this SDK is installed using Carthage. ([#2301](https://github.com/mapbox/mapbox-navigation-ios/pull/2301)) + +## v0.38.1 + +* Fixed an issue where user notifications displayed right turn arrows for left turn maneuvers. ([#2270](https://github.com/mapbox/mapbox-navigation-ios/pull/2270)) + +## v0.38.0 + +* This library now requires a minimum deployment target of iOS 10.0 or above. iOS 9._x_ is no longer supported. ([#2206](https://github.com/mapbox/mapbox-navigation-ios/pull/2206)) +* Fixed an issue where the user puck appeared farther up the screen than the actual user location even while the camera pivoted around the user location at turns. ([#2211](https://github.com/mapbox/mapbox-navigation-ios/pull/2211)) +* Lock screen notifications are presented more reliably and more closely resemble instruction banners. ([#2206](https://github.com/mapbox/mapbox-navigation-ios/pull/2206)) +* Fixed an issue where manually incrementing `RouteProgress.legIndex` could lead to undefined behavior. ([#2229](https://github.com/mapbox/mapbox-navigation-ios/pull/2229)) +* `DistanceFormatter` now inherits directly from `Formatter` rather than `LengthFormatter`. ([#2206](https://github.com/mapbox/mapbox-navigation-ios/pull/2206)) +* Fixed an issue where `DistanceFormatter.attributedString(for:withDefaultAttributes:)` set `NSAttributedString.Key.quantity` to the original distance value rather than the potentially rounded value represented by the attributed string. ([#2206](https://github.com/mapbox/mapbox-navigation-ios/pull/2206)) + +## v0.37.1 + +* Fixed a crash on launch if this SDK is installed using Carthage. ([#2301](https://github.com/mapbox/mapbox-navigation-ios/pull/2301)) + +## v0.37.0 + +* Fixed an issue where a second swipe down on the top banner causes an open `StepsTableViewController` to animate incorrectly. ([#2197](https://github.com/mapbox/mapbox-navigation-ios/pull/2197)) +* Added the `NavigationViewControllerDelegate.navigationViewController(_:didUpdate:location:rawLocation:)` method for capturing progress updates without having to inject a class between the `NavigationViewController` and the `NavigationService`. ([#2224](https://github.com/mapbox/mapbox-navigation-ios/pull/2224)) +* Fixed an issue where the bottom banner can disappear when presenting in `UIModalPresentationStyle.fullScreen` in iOS 13. ([#2182](https://github.com/mapbox/mapbox-navigation-ios/pull/2182)) + +## v0.36.0 + +* Fixed an issue where InstructionsBannerView remained the same color after switching to a day or night style. ([#2178](https://github.com/mapbox/mapbox-navigation-ios/pull/2178)) +* Fixed an issue where `NavigationMapView` showed routes without congestion attributes, such as `MBDirectionsProfileIdentifier.walking` routes, as translucent lines, even if the route had only one leg. ([#2193](https://github.com/mapbox/mapbox-navigation-ios/pull/2193)) +* Fixed an issue where the “iPhone Volume Low” banner would persist until replaced by another banner about simulation or rerouting. ([#2183](https://github.com/mapbox/mapbox-navigation-ios/pull/2183)) +* Designables no longer crash and fail to render in Interface Builder when the application target links to this SDK via CocoaPods. ([#2179](https://github.com/mapbox/mapbox-navigation-ios/pull/2179)) +* Fixed a crash that could occur when statically initializing a `Style` if the SDK was installed using CocoaPods. ([#2179](https://github.com/mapbox/mapbox-navigation-ios/pull/2179)) +* Fixed incorrect animation of instruction labels when presenting the step list. ([#2185](https://github.com/mapbox/mapbox-navigation-ios/pull/2185)) + +## v0.35.0 + +* Upgraded to [Mapbox Maps SDK for iOS v5.1.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/ios-v5.1.0). ([#2134](https://github.com/mapbox/mapbox-navigation-ios/pull/2134)) +* Added the ability to define a custom view controller for the top banner via `NavigationOptions.topBanner`. ([#2121](https://github.com/mapbox/mapbox-navigation-ios/pull/2121)) +* StyleManager now posts a `StyleManagerDidApplyStyleNotification` when a style gets applied due to a change of day of time, or when entering or exiting a tunnel. ([#2148](https://github.com/mapbox/mapbox-navigation-ios/pull/2148)) +* Fixed a crash when presenting `NavigationViewController` on iOS 13.0. ([#2156](https://github.com/mapbox/mapbox-navigation-ios/pull/2156)) +* Added a setter to the `Router.reroutesProactively` property. ([#2157](https://github.com/mapbox/mapbox-navigation-ios/pull/2157)) +* Added a Yoruba localization. ([#2159](https://github.com/mapbox/mapbox-navigation-ios/pull/2159)) + +## v0.34.0 + +* Upgraded to [Mapbox Maps SDK for iOS v5.0.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/ios-v5.0.0), which changes [how monthly active users are counted](https://www.mapbox.com/52219). ([#2133](https://github.com/mapbox/mapbox-navigation-ios/pull/2133)) +* Deprecated `StatusViewDelegate` in favor of calling the `UIControl.addTarget(_:action:for:)` method on `StatusView` for `UIControl.Event.valueChanged`. ([#2136](https://github.com/mapbox/mapbox-navigation-ios/pull/2136)) +* Fixed an issue where the status view showed a simulated speed factor as an unformatted number. ([#2136](https://github.com/mapbox/mapbox-navigation-ios/pull/2136)) +* Fixed an issue preventing the status view from appearing while rerouting. ([#2137](https://github.com/mapbox/mapbox-navigation-ios/pull/2137)) +* The `RouteOptions.alleyPriority`, `RouteOptions.walkwayPriority`, and `RouteOptions.speed` properties now work when calculating walking routes offline. ([#2142](https://github.com/mapbox/mapbox-navigation-ios/pull/2142)) + +## v0.33.0 + +* Restored the compass to `CarPlayNavigationViewController`, now displaying a digital readout of the direction of travel, represented by the `CarPlayCompassView` class. ([#2077](https://github.com/mapbox/mapbox-navigation-ios/pull/2077)) + +## v0.32.0 + +### Core Navigation + +* Fixed an issue where `RouteControllerNotificationUserInfoKey.isProactiveKey` was not set to `true` in `Notification.Name.routeControllerDidReroute` notifications after proactively rerouting the user. ([#2086](https://github.com/mapbox/mapbox-navigation-ios/pull/2086)) +* Fixed an issue where `LegacyRouteController` failed to call `NavigationServiceDelegate.navigationService(_:didPassSpokenInstructionPoint:routeProgress:)` and omitted `RouteControllerNotificationUserInfoKey.spokenInstructionKey` from `Notification.Name.routeControllerDidPassSpokenInstructionPoint` notifications. ([#2089](https://github.com/mapbox/mapbox-navigation-ios/pull/2089)) +* Fixed an issue where `SimulatedLocationManager`’s distance did not update in response to updating the `Router`’s route, causing the user puck to be snapped to an invalid location on the new route. ([#2096](https://github.com/mapbox/mapbox-navigation-ios/pull/2096)) +* `NavigationMatchOptions.shapeFormat` now defaults to `RouteShapeFormat.polyline6` for consistency with `NavigationRouteOptions` and compatibility with the `RouteController`. ([#2084](https://github.com/mapbox/mapbox-navigation-ios/pull/2084)) +* Fixed an issue where the user location was unsnapped when the user’s course was unavailable. ([#2092](https://github.com/mapbox/mapbox-navigation-ios/pull/2092)) +* Fixed an issue where a failed rerouting request prevented `LegacyRouteController` from ever rerouting the user again. ([#2093](https://github.com/mapbox/mapbox-navigation-ios/pull/2093)) + +### CarPlay + +* Fixed an issue where the remaining distance and travel time displayed during turn-by-turn navigation were calculated relative to the upcoming waypoint instead of the final destination. ([#2119](https://github.com/mapbox/mapbox-navigation-ios/pull/2119)) +* Deprecated `CarPlayManager.overviewButton` in favor of `CarPlayManager.userTrackingButton`, which updates the icon correctly when panning out of tracking state. ([#2100](https://github.com/mapbox/mapbox-navigation-ios/pull/2100)) +* When previewing a route, the distance and estimated travel time are displayed at the bottom of the window. ([#2120](https://github.com/mapbox/mapbox-navigation-ios/pull/2120)) +* By default, the destination waypoint name is no longer displayed a second time when previewing a route. To add a subtitle to the preview, implement the `CarPlayManagerDelegate.carPlayManager(_:willPreview:)` method; create an `MKMapItem` whose `MKPlacemark` has the `Street` key in its address dictionary. ([#2120](https://github.com/mapbox/mapbox-navigation-ios/pull/2119)) + +### Other changes + +* Fixed compiler warnings in Xcode 10.2 when installing the SDK using CocoaPods. ([#2087](https://github.com/mapbox/mapbox-navigation-ios/pull/2087)) +* Fixed an issue where the user puck could float around while the user is at rest or moving in reverse. ([#2109](https://github.com/mapbox/mapbox-navigation-ios/pull/2109)) + +## v0.31.0 + +* Fixed a number of warnings and errors when building the SDK from source using CocoaPods in Swift 4.2. ([#2058](https://github.com/mapbox/mapbox-navigation-ios/pull/2058)) +* Restored “Declaration” and “Parameters” sections throughout the API reference. ([#2076](https://github.com/mapbox/mapbox-navigation-ios/pull/2076)) +* Deprecated `NavigationMapView.navigationMapDelegate` in favor of `NavigationMapView.navigationMapViewDelegate`. ([#2061](https://github.com/mapbox/mapbox-navigation-ios/pull/2061)) +* The `NavigationMapView.navigationMapViewDelegate` and `RouteVoiceController.voiceControllerDelegate` properties are now accessible in Objective-C. ([#2061](https://github.com/mapbox/mapbox-navigation-ios/pull/2061)) +* The sources added to the style by `NavigationMapView.showRoutes(_:legIndex:)` once again enables `MGLShapeSourceOptions.lineDistanceMetrics`. ([#2071](https://github.com/mapbox/mapbox-navigation-ios/pull/2071)) +* Deprecated `NavigationDirections.configureRouter(tilesURL:translationsURL:completionHandler:)` in favor of `NavigationDirections.configureRouter(tilesURL:completionHandler:)`. ([#2079](https://github.com/mapbox/mapbox-navigation-ios/pull/2079)) +* Fixed a crash that occurred if the `Route` lacked `SpokenInstruction` data, such as if the request was made using `RouteOptions` instead of `NavigationRouteOptions` or if the route was generated by a non-Mapbox API. ([#2079](https://github.com/mapbox/mapbox-navigation-ios/pull/2079)) + +## v0.30.0 + +### Core Navigation + +* Fixed an issue where the wrong instruction could be announced or a crash could occur near maneuvers when using a `RouteController`. ([#2004](https://github.com/mapbox/mapbox-navigation-ios/pull/2004), [#2029](https://github.com/mapbox/mapbox-navigation-ios/pull/2029)) +* Restored the `RouteController.reroutesProactively` property. By default, `RouteController` and `LegacyRouteController` proactively check for a faster route on an interval defined by `RouteControllerProactiveReroutingInterval`. ([#1986](https://github.com/mapbox/mapbox-navigation-ios/pull/1986)) +* Added a `RouteControllerMinimumDurationRemainingForProactiveRerouting` global variable to customize when `RouteController` stops looking for more optimal routes as the user nears the destination. ([#1986](https://github.com/mapbox/mapbox-navigation-ios/pull/1986)) +* Fixed a bug which would cancel an ongoing reroute request when the request takes longer than one second to complete. ([#1986](https://github.com/mapbox/mapbox-navigation-ios/pull/1986)) +* Fixed an issue where rerouting would ignore any waypoints from the original route options where the `Waypoint.separatesLegs` property was set to `false`. ([#2014](https://github.com/mapbox/mapbox-navigation-ios/pull/2014)) + +### CarPlay + +* Removed `NavigationViewController.carPlayManager(_:didBeginNavigationWith:window:)` that created and presented a `NavigationViewController`. Have your `NavigationViewControllerDelegate` (such as a `UIViewController` subclass, or a discrete delegate) create and present a `NavigationViewController`. ([#2045](https://github.com/mapbox/mapbox-navigation-ios/pull/2045)) +* Removed `NavigationViewController.carPlayManagerDidEndNaviation(_:window:)`. Have your `NavigationViewControllerDelegate` (such as a `UIViewController` subclass, or a discrete delegate) dismiss the active `NavigationViewController`. ([#2045](https://github.com/mapbox/mapbox-navigation-ios/pull/2045)) +* Fixed an issue where `CarPlayManager` sometimes created a redundant `NavigationService` object, resulting in unexpected behavior. ([#2041](https://github.com/mapbox/mapbox-navigation-ios/pull/2041)) +* Fixed an issue where `CarPlayManager` sometimes created and presented a redundant `NavigationViewController`. ([#2041](https://github.com/mapbox/mapbox-navigation-ios/pull/2041)) +* Added the `CarPlayManager.beginNavigationWithCarPlay(_:navigationService:)` method. Use this method to programmatically start navigation in CarPlay if CarPlay is being connected while turn-by-turn navigation is already underway on the iOS device. ([#2021](https://github.com/mapbox/mapbox-navigation-ios/pull/2021)) +* Renamed the `CarPlayManagerDelegate.carPlayManager(_:navigationServiceAlong:)` method to `CarPlayManagerDelegate.carPlayManager(_:navigationServiceAlong:desiredSimulationMode:)`. `CarPlayManagerDelegate` implementations are now required to implement this method. ([#2018](https://github.com/mapbox/mapbox-navigation-ios/pull/2018), [#2021](https://github.com/mapbox/mapbox-navigation-ios/pull/2021)) +* Renamed the `MapboxVoiceController(speechClient:dataCache:audioPlayerType:)` initializer to `MapboxVoiceController(navigationService:speechClient:dataCache:audioPlayerType:)` and the `RouteVoiceController()` initializer to `RouteVoiceController(navigationService:)`. ([#2018](https://github.com/mapbox/mapbox-navigation-ios/pull/2018)) +* Added the `CarPlayManagerDelegate.carPlayManager(_:didFailToFetchRouteBetween:options:error:)` method, which allows you to present an alert on the map template when a route request fails. ([#1981](https://github.com/mapbox/mapbox-navigation-ios/pull/1981)) +* A modal alert is no longer displayed when the user arrives at an intermediate waypoint. This fixes a crash that occurred when the user tapped the Continue button. ([#2005](https://github.com/mapbox/mapbox-navigation-ios/pull/2005)) +* Added the `CarPlayNavigationViewController.navigationService` property. ([#2005](https://github.com/mapbox/mapbox-navigation-ios/pull/2005)) +* `CarPlayNavigationDelegate.carPlayNavigationViewControllerDidDismiss(_:byCanceling:)` is now optional. ([#2005](https://github.com/mapbox/mapbox-navigation-ios/pull/2005)) +* Removed the `CarPlayNavigationDelegate.carPlayNavigationViewControllerDidArrive(_:)` method in favor of `NavigationServiceDelegate.navigationService(_:didArriveAt:)`. ([#2005](https://github.com/mapbox/mapbox-navigation-ios/pull/2005), [#2025](https://github.com/mapbox/mapbox-navigation-ios/pull/2025)) +* Fixed an issue where the camera would sometimes fail to animate properly when returning to the browsing activity. [#2022](https://github.com/mapbox/mapbox-navigation-ios/pull/2022)) +* Removed the compass from `CarPlayNavigationViewController`. ([#2051](https://github.com/mapbox/mapbox-navigation-ios/pull/2051)) + +### Other changes + +* Fixed an issue where the turn banner stayed blank when using a `RouteController`. ([#1996](https://github.com/mapbox/mapbox-navigation-ios/pull/1996)) +* The `BottomBannerViewController` now accounts for the safe area inset if present. ([#1982](https://github.com/mapbox/mapbox-navigation-ios/pull/1982)) +* Deprecated `BottomBannerViewController(delegate:)`. Set the `BottomBannerViewController.delegate` property separately after initializing a `BottomBannerViewController`. ([#2027](https://github.com/mapbox/mapbox-navigation-ios/pull/2027)) +* The map now pans when the user drags a `UserCourseView`. ([#2012](https://github.com/mapbox/mapbox-navigation-ios/pull/2012)) +* Added a Japanese localization. ([#2032](https://github.com/mapbox/mapbox-navigation-ios/pull/2032)) +* Fixed a compiler error when rendering a `NavigationViewController` designable inside an Interface Builder storyboard. ([#2039](https://github.com/mapbox/mapbox-navigation-ios/pull/2039)) +* Fixed an issue where the user puck moved around onscreen while tracking the user’s location. ([#2047](https://github.com/mapbox/mapbox-navigation-ios/pull/2047)) +* Fixed an issue where the user puck briefly moved away from the route line as the user completed a turn. ([#2047](https://github.com/mapbox/mapbox-navigation-ios/pull/2047)) + +## v0.29.1 + +### Core Navigation + +* Fixed an issue where `RouteController` could not advance to a subsequent leg along the route. ([#1979](https://github.com/mapbox/mapbox-navigation-ios/pull/1979)) +* Fixed an issue where the turn banner remained blank and `RouterDelegate.router(_:didPassVisualInstructionPoint:routeProgress:)` was never called if `MapboxNavigationService` was created with a `LegacyRouteController` router. ([#1983](https://github.com/mapbox/mapbox-navigation-ios/pull/1983)) +* Fixed an issue causing `LegacyRouteController` to prematurely advance to the next step when receiving an unreliable course from Core Location. ([#1989](https://github.com/mapbox/mapbox-navigation-ios/pull/1989)) + +### Other changes + +* Fixed an issue preventing `CarPlayMapViewController` and `CarPlayNavigationViewController` from applying custom map styles. ([#1985](https://github.com/mapbox/mapbox-navigation-ios/pull/1985)) +* Renamed `-[MBStyleManagerDelegate styleManager:didApply:]` to `-[MBStyleManagerDelegate styleManager:didApplyStyle:]` in Objective-C. If your `StyleManagerDelegate`-conforming class is written in Swift, make sure its methods match `StyleManagerDelegate`’s method signatures, including `@objc` annotations. ([#1985](https://github.com/mapbox/mapbox-navigation-ios/pull/1985)) + +## v0.29.0 + +### Core Navigation + +* `PortableRouteController` has been renamed to `RouteController`. The previous `RouteController` has been renamed to `LegacyRouteController` and will be removed in a future release. ([#1904](https://github.com/mapbox/mapbox-navigation-ios/pull/1904)) +* Added the `MapboxNavigationService.router(_:didPassVisualInstructionPoint:routeProgress:)` and `MapboxNavigationService.router(_:didPassSpokenInstructionPoint:routeProgress:)` methods, which correspond to `Notification.Name.routeControllerDidPassVisualInstructionPoint` and `Notification.Name.routeControllerDidPassSpokenInstructionPoint`, respectively. ([#1912](https://github.com/mapbox/mapbox-navigation-ios/pull/1912)) +* Added an initializer to `DispatchTimer`, along with methods for arming and disarming the timer. ([#1912](https://github.com/mapbox/mapbox-navigation-ios/pull/1912)) + +### CarPlay + +* You can now customize the control layer of the map template comprising of the navigation bar's leading and trailing buttons and the map buttons. ([#1962](https://github.com/mapbox/mapbox-navigation-ios/pull/1962)) +* Added new map buttons in the `CarPlayManager` and the `CarPlayMapViewController`. You can now access map buttons that perform built-in actions on the map by accessing read-only properties such as: `CarPlayManager.exitButton`, `CarPlayManager.muteButton`, `CarPlayManager.showFeedbackButton`, `CarPlayManager.overviewButton`, `CarPlayMapViewController.recenterButton`, `CarPlayMapViewController.zoomInButton`, `CarPlayMapViewController.zoomOutButton`, `CarPlayMapViewController.panningInterfaceDisplayButton(for:)`, `CarPlayMapViewController.panningInterfaceDismissalButton(for:)`. ([#1962](https://github.com/mapbox/mapbox-navigation-ios/pull/1962)) + +### Other changes + +* Replaced `NavigationViewController(for:styles:navigationService:viewController:)` with `NavigationViewController(for:options:)`, which accepts a `NavigationOptions` object (not to be confused with `NavigationRouteOptions`). `NavigationOptions` contains various options for customizing the user experience of a turn-by-turn navigation session, including replacing the bottom banner with a custom view controller. ([#1951](https://github.com/mapbox/mapbox-navigation-ios/pull/1951)) +* Restored “Declaration” and “Parameters” sections throughout the API reference. ([#1952](https://github.com/mapbox/mapbox-navigation-ios/pull/1952)) +* Removed the deprecated `NavigationViewController.routeController`, `NavigationViewController.eventsManager`, and `NavigationViewController.locationManager` properties. ([#1904](https://github.com/mapbox/mapbox-navigation-ios/pull/1904)) +* Fixed audio ducking issues. ([#1915](https://github.com/mapbox/mapbox-navigation-ios/pull/1915)) +* Removed the `NavigationViewControllerDelegate.navigationViewController(_:imageFor:)` and `NavigationViewControllerDelegate.navigationViewController(_:viewFor:)` methods in favor of `NavigationMapViewDelegate.navigationMapView(_:imageFor:)` and `NavigationMapViewDelegate.navigationMapView(_:viewFor:)`, respectively. ([#1964](https://github.com/mapbox/mapbox-navigation-ios/pull/1964)) +* The `NavigationViewController.navigationService` property is now read-only. ([#1965](https://github.com/mapbox/mapbox-navigation-ios/pull/1965])) +* CarPlayManager now offers its delegate the opportunity to customize a trip and its related preview text configuration before displaying it for preview ([#1955](https://github.com/mapbox/mapbox-navigation-ios/pull/1955)) + +## v0.28.0 (January 23, 2018) + +* Xcode 10 or above is now required for building this SDK. ([#1936](https://github.com/mapbox/mapbox-navigation-ios/pull/1936)) +* Search functionality on CarPlay is now managed by `CarPlaySearchController`. Added the `CarPlayManagerDelegate.carPlayManager(_:selectedPreviewFor:using:)` method for any additional customization after a trip is selected on CarPlay. ([#1846](https://github.com/mapbox/mapbox-navigation-ios/pull/1846)) +* Added the `NavigationViewController.showEndOfRouteFeedback(duration:completionHandler:)` method for showing the end-of-route feedback UI after manually ending a navigation session. ([#1932](https://github.com/mapbox/mapbox-navigation-ios/pull/1932)) +* Fixed inaudible spoken instructions while other audio is playing. ([#1933](https://github.com/mapbox/mapbox-navigation-ios/pull/1933)) +* Fixed an issue where setting `Router.route` did not update `SimulatedLocationManager.route`. ([#1928](https://github.com/mapbox/mapbox-navigation-ios/pull/1928)) +* Fixed an issue where U-turn lane was displayed as a U-turn to the right even in regions that drive on the right. ([#1910](https://github.com/mapbox/mapbox-navigation-ios/pull/1910)) +* Fixed an issue where a left-or-through lane was displayed as a right turn lane. ([#1910](https://github.com/mapbox/mapbox-navigation-ios/pull/1910)) +* Programmatically setting `Router.route` no longer causes `NavigationViewControllerDelegate.navigationViewController(_:shouldRerouteFrom:)` or `RouterDelegate.router(_:shouldRerouteFrom:)` to be called. ([#1931](https://github.com/mapbox/mapbox-navigation-ios/pull/1931)) +* Fixed redundant calls to `NavigationViewControllerDelegate.navigationViewController(_:shouldRerouteFrom:)` and `RouterDelegate.router(_:shouldRerouteFrom:)` when rerouting repeatedly. ([#1930](https://github.com/mapbox/mapbox-navigation-ios/pull/1930)) + +## v0.27.0 (December 20, 2018) + +* The `NavigationDirections.unpackTilePack(at:outputDirectoryURL:progressHandler:completionHandler:)` method is now available to Objective-C code as `-[MBNavigationDirections unpackTilePackAtURL:outputDirectoryURL:progressHandler:completionHandler:]`. ([#1891](https://github.com/mapbox/mapbox-navigation-ios/pull/1891)) +* Added support for styles powered by [version 8 of the Mapbox Streets source](https://docs.mapbox.com/vector-tiles/mapbox-streets-v8/). ([#1909](https://github.com/mapbox/mapbox-navigation-ios/pull/1909)) +* Fixed potential inaccuracies in location snapping, off-route detection, and the current road name label. ([mapbox/turf-swift#74](https://github.com/mapbox/turf-swift/pull/74)) + +## v0.26.0 (December 6, 2018) + +### Client-side routing + +* Added a `NavigationDirections` class that manages offline tile packs and client-side route calculation. ([#1808](https://github.com/mapbox/mapbox-navigation-ios/pull/1808)) +* Extended `Bundle` with `Bundle.suggestedTileURL` and other properties to facilitate offline downloads. ([#1808](https://github.com/mapbox/mapbox-navigation-ios/pull/1808)) + +### CarPlay + +* When selecting a search result in CarPlay, the resulting routes lead to the search result’s routable location when available. Routes to a routable location are more likely to be passable. ([#1859](https://github.com/mapbox/mapbox-navigation-ios/pull/1859)) +* Fixed an issue where the CarPlay navigation map’s vanishing point and user puck initially remained centered on screen, instead of accounting for the maneuver panel, until the navigation bar was shown. ([#1856](https://github.com/mapbox/mapbox-navigation-ios/pull/1856)) +* Fixed an issue where route shields and exit numbers appeared blurry in the maneuver panel on CarPlay devices and failed to appear in the CarPlay simulator. ([#1868](https://github.com/mapbox/mapbox-navigation-ios/pull/1868)) +* Added `VisualInstruction.containsLaneIndications`, `VisualInstruction.maneuverImageSet(side:)`, `VisualInstruction.shouldFlipImage(side:)`, and `VisualInstruction.carPlayManeuverLabelAttributedText(bounds:shieldHeight:window:)`. ([#1860](https://github.com/mapbox/mapbox-navigation-ios/pull/1860)) +* `RouteLegProgress.upComingStep` has been renamed to `upcomingStep`. ([#1860](https://github.com/mapbox/mapbox-navigation-ios/pull/1860)) + +### Other changes + +* The `NavigationSettings.shared` property is now accessible in Objective-C code as `MBNavigationSettings.sharedSettings`. ([#1882](https://github.com/mapbox/mapbox-navigation-ios/pull/1882)) +* Fixed spurious rerouting on multi-leg routes. ([#1884](https://github.com/mapbox/mapbox-navigation-ios/pull/1884)) +* Fixed a hang that occurred when failing to fetch a route shield image for display in a visual instruction banner. ([#1888](https://github.com/mapbox/mapbox-navigation-ios/pull/1888)) +* Adding property `RouteController.nearbyCoordinates`, which offers similar behavior to `RouteLegProgress.nearbyCoordinates`, which the addition of step lookahead/lookbehind in multi-leg routes. ([#1883](https://github.com/mapbox/mapbox-navigation-ios/pull/1883)) +* The `MGLShapeSourceOptions.lineDistanceMetrics` property has been temporarily disabled from the route line shape source due to a crash. This means it isn’t possible to set the `MGLLineStyleLayer.lineGradient` property on the route line style layers. ([#1886](https://github.com/mapbox/mapbox-navigation-ios/pull/1886)) + +## v0.25.0 (November 22, 2018) + +### CarPlay + +* Renamed `CarPlayManager.calculateRouteAndStart(from:to:completionHandler:)` to `CarPlayManager.previewRoutes(between:completionHandler:)` and added a `CarplayManager.previewRoutes(to:completionHandler)`, as well as a `CarPlayManager.previewRoutes(for:completionHandler:)` method that accepts an arbitrary `NavigationRouteOptions` object. ([#1841](https://github.com/mapbox/mapbox-navigation-ios/pull/1841)) +* Fixed an issue causing `UserCourseView` to lag behind `NavigationMapView` whenever the map’s camera or content insets change significantly or when the map rotates. ([#1838](https://github.com/mapbox/mapbox-navigation-ios/pull/1838)) +* Renamed `CarPlayManager(_:)` to `CarPlayManager(styles:directions:eventsManager:)` and `CarPlayNavigationViewController(with:mapTemplate:interfaceController:manager:styles:)` to `CarPlayNavigationViewController(navigationService:mapTemplate:interfaceController:manager:styles:)`. These initializers now accept an array of `Style` objects to apply throughout the CarPlay interface, similar to `NavigationViewController`. You can also change the styles at any time by setting the `CarPlayManager.styles` property. ([#1836](https://github.com/mapbox/mapbox-navigation-ios/pull/1836)) +* `CarPlayManager(styles:directions:eventsManager:)` also allows you to pass in a custom `Directions` object to use when calculating routes. ([#1834](https://github.com/mapbox/mapbox-navigation-ios/pull/1834/)) +* Removed the `StyleManager(_:)` initializer. After initializing a `StyleManager` object, set the `StyleManager.delegate` property to ensure that the style manager’s settings take effect. ([#1836](https://github.com/mapbox/mapbox-navigation-ios/pull/1836)) +* Added `CarPlayManager.mapView` and `CarPlayNavigationViewController.mapView` properties. ([#1852](https://github.com/mapbox/mapbox-navigation-ios/pull/1852)) +* Some additional members of `CarPlayManager` are now accessible in Objective-C code. ([#1836](https://github.com/mapbox/mapbox-navigation-ios/pull/1836)) +* Fixed an issue where distances are incorrectly displayed as “0 m” in regions that use the metric system. ([#1854](https://github.com/mapbox/mapbox-navigation-ios/pull/1854)) +* Fixed an issue where the user puck pointed away from the route line during turn-by-turn navigation in CarPlay. The map’s vanishing point now accounts for safe area insets, including the side maneuver view. ([#1845](https://github.com/mapbox/mapbox-navigation-ios/pull/1845)) +* Fixed an issue where the map view used for browsing and previewing failed to call `MGLMapViewDelegate.mapView(_:viewFor:)` and `MGLMapViewDelegate.mapViewWillStartLocatingUser(_:)`. ([#1852](https://github.com/mapbox/mapbox-navigation-ios/pull/1852)) +* You can now create a `UserPuckCourseView` using the `UserPuckCourseView(frame:)` initializer. ([#1852](https://github.com/mapbox/mapbox-navigation-ios/pull/1852)) + +### Other changes + +* Fixed a crash during turn-by-turn navigation. ([#1820](https://github.com/mapbox/mapbox-navigation-ios/pull/1820)) +* Fixed a crash that could happen while simulating a route. ([#1820](https://github.com/mapbox/mapbox-navigation-ios/pull/1820)) +* Fixed an issue causing MapboxVoiceController to speak instructions using VoiceOver instead of the Mapbox Voice API. ([#1830](https://github.com/mapbox/mapbox-navigation-ios/issues/1830)) +* Added `NavigationViewController.navigationService(_:willArriveAt:after:distance:)` to assist with preparations for arrival. ([#1847](https://github.com/mapbox/mapbox-navigation-ios/pull/1847)) + +## v0.24.0 (November 7, 2018) + +* It is now safe to set the `NavigationMapView.delegate` property of the `NavigationMapView` in `NavigationViewController.mapView`. Implement `MGLMapViewDelegate` in your own class to customize annotations and other details. ([#1601](https://github.com/mapbox/mapbox-navigation-ios/pull/1601)) +* Fixed an issue where the map view while navigating in CarPlay showed labels in the style’s original language instead of the local language. ([#1601](https://github.com/mapbox/mapbox-navigation-ios/pull/1601)) +* Fixed an issue where rerouting could still occur after arrival, even though `NavigationServiceDelegate.navigationService(_:shouldPreventReroutesWhenArrivingAt:)` returned `true`. ([#1833](https://github.com/mapbox/mapbox-navigation-ios/pull/1833)) +* `NavigationMapViewDelegate.navigationMapView(_:routeStyleLayerWithIdentifier:source:)`, `NavigationMapViewDelegate.navigationMapView(_:routeCasingStyleLayerWithIdentifier:source:)`, `NavigationViewControllerDelegate.navigationViewController(_:routeStyleLayerWithIdentifier:source:)`, and `NavigationViewControllerDelegate.navigationViewController(_:routeCasingStyleLayerWithIdentifier:source:)` can now set the `MGLLineStyleLayer.lineGradient` property. ([#1799](https://github.com/mapbox/mapbox-navigation-ios/pull/1799)) +* Reduced the `NavigationMapView.minimumFramesPerSecond` property’s default value from 30 frames per second to 20 frames per second for improved performance on battery power. ([#1819](https://github.com/mapbox/mapbox-navigation-ios/pull/1819)) + +## v0.23.0 (October 24, 2018) +* `CarPlayManager` is no longer a singleton; your application delegate is responsible for creating and owning an instance of this class. This fixes a crash in applications that specify the access token programmatically instead of in the Info.plist file. ([#1792](https://github.com/mapbox/mapbox-navigation-ios/pull/1792)) +* `NavigationService.start()` now sets the first coordinate on a route, if a fixed location isn't available the first few seconds of a navigation session. ([#1790](https://github.com/mapbox/mapbox-navigation-ios/pull/1790)) + +## v0.22.3 (October 17, 2018) + +* Fixed over-retain issue that resulted in the `MapboxNavigationService` persisting beyond its expected lifecycle. This could cause unexpected behavior with components that observe progress noitifications. +* Fixed warnings caused by internal usage of deprecated types. + +## v0.22.2 (October 15, 2018) + +* Fixed an issue where the U-turn icon in the turn banner pointed in the wrong direction. ([#1647](https://github.com/mapbox/mapbox-navigation-ios/pull/1647)) +* Fixed an issue where the user puck was positioned too close to the bottom of the map view, underlapping the current road name label. ([#1766](https://github.com/mapbox/mapbox-navigation-ios/pull/1766)) +* Added `InstructionsBannerView.showStepIndicator` to enable showing/hiding the drag indicator ([#1772](https://github.com/mapbox/mapbox-navigation-ios/pull/1772)) +* Renamed `EventsManager` to `NavigationEventsManager`. ([#1767](https://github.com/mapbox/mapbox-navigation-ios/pull/1767)) +* Added support in `NavigationEventsManager` that allows for routeless events. ([#1767](https://github.com/mapbox/mapbox-navigation-ios/pull/1767)) + +## v0.22.1 (October 2, 2018) + +### User Location + +* Added ability to adjust `poorGPSPatience` of a `NavigationService`. [#1763](https://github.com/mapbox/mapbox-navigation-ios/pull/1763) +* Increased default Poor-GPS patience of `MapboxNavigationService` to 2.5 seconds. [#1763](https://github.com/mapbox/mapbox-navigation-ios/pull/1763) +* Fixed an issue where the map view while navigating in CarPlay displayed the day style even at night. ([#1762](https://github.com/mapbox/mapbox-navigation-ios/pull/1762)) + +## v0.22.0 (October 1, 2018) + +### Packaging + +* Added a dependency on the Mapbox Navigation Native framework. If you use Carthage to install this framework, your target should also link against `MapboxNavigationNative.framework`. ([#1618](https://github.com/mapbox/mapbox-navigation-ios/pull/1618)) + +### User location + +* Added a `NavigationService` protocol implemented by classes that provide location awareness functionality. Our default implementation, `MapboxNavigationService` conforms to this protocol. ([#1602](https://github.com/mapbox/mapbox-navigation-ios/pull/1602)) + * Added a new `Router` protocol, which allows for custom route-following logic. Our default implementation, `RouteController`, conforms to this protocol. + * `NavigationViewController.init(for:styles:directions:styles:routeController:locationManager:voiceController:eventsManager)` has been renamed `NavigationViewController.init(for:styles:navigationService:voiceController:)`. + * `NavigationViewController.routeController` has been replaced by `NavigationViewController.navigationService`. + * If you currently use `RouteController` directly, you should migrate to `MapboxNavigationService`. + * If you currently use `SimulatedLocationManager` directly, you should instead pass `SimulationOption.always` into `MapboxNavigationService(route:directions:locationSource:eventsManagerType:simulating:)`. + * Note: the `MapboxNavigationService`, by default, will start simulating progress if more than 1.5 seconds elapses without any update from the GPS. This can happen when simulating locations in Xcode, or selecting the "Custom Location" simulation option in the iOS Simulator. This is normal behavior. +* Improved the reliability of off-route detection. ([#1618](https://github.com/mapbox/mapbox-navigation-ios/pull/1618)) + +### User interface + +* `StyleManagerDelegate.locationFor(styleManager:)` has been renamed to `StyleManagerDelegate.location(for:)` ([#1724](https://github.com/mapbox/mapbox-navigation-ios/pull/1724)) +* Fixed inaccurate maneuver arrows along the route line when the route doubles back on itself. ([#1735](https://github.com/mapbox/mapbox-navigation-ios/pull/1735)) +* Added an `InstructionsBannerView.swipeable` property that allows the user to swipe the banner to the side to preview future steps. The `InstructionsBannerViewDelegate.didDragInstructionsBanner(_:)` method has been deprecated in favor of `InstructionsBannerViewDelegate.didSwipeInstructionsBanner(_:swipeDirection:)`. ([#1750](https://github.com/mapbox/mapbox-navigation-ios/pull/1750)) +* `NavigationMapView` no longer mutates its own frame rate implicitly. A new `NavigationMapView.updatePreferredFrameRate(for:)` method allows you to update the frame rate in response to route progress change notifications. The `NavigationMapView.minimumFramesPerSecond` property determines the frame rate while the application runs on battery power. By default, the map views in `NavigationViewController` and CarPlay’s navigation activity animate at a higher frame rate on battery power than before. ([#1749](https://github.com/mapbox/mapbox-navigation-ios/pull/1749)) +* Fixed a crash that occurred when the end of route view controller appears, showing the keyboard. ([#1754](https://github.com/mapbox/mapbox-navigation-ios/pull/1754)) + +## v0.21.0 (September 17, 2018) + +### User interface + +* In CarPlay-enabled applications on iOS 12, this SDK now displays a map, search interface, and turn-by-turn navigation experience on the connected CarPlay device. The CarPlay screen is managed by the shared `CarPlayManager` object, which you can configure by implementing the `CarPlayManagerDelegate` protocol. ([#1714](https://github.com/mapbox/mapbox-navigation-ios/pull/1714)) +* Added the `Style.previewMapStyleURL` property for customizing the style displayed by a preview map. ([#1695](https://github.com/mapbox/mapbox-navigation-ios/pull/1695)) + +### User location + +* Breaking change: The `eventsManager` argument of `RouteController(along:directions:locationManager:eventsManager:)` is now required. `NavigationViewController(for:directions:styles:locationManager:voiceController:eventsManager:)` now has an optional `eventsManager` argument, which is passed to any instance of `RouteController` created as a result of rerouting. ([#1671](https://github.com/mapbox/mapbox-navigation-ios/pull/1671)) +* Fixed issues where the user puck would overshoot a turn or drift away from a curved road. ([#1710](https://github.com/mapbox/mapbox-navigation-ios/pull/1710)) +* Fixed incorrect conversions to inches in `DistanceFormatter`. ([#1699](https://github.com/mapbox/mapbox-navigation-ios/pull/1699)) +* Fixed several crashes related to telemetry collection. ([#1668](https://github.com/mapbox/mapbox-navigation-ios/pull/1668)) + +## v0.20.1 (September 10, 2018) + +* Upgraded mapbox-events-ios to v0.5.0 to avoid a potential incompatibility when using Carthage to install the SDK. +* Fixed a bug which prevented automatic day and night style switching. ([#1629](https://github.com/mapbox/mapbox-navigation-ios/pull/1629)) + +## v0.20.0 (September 6, 2018) + +### User interface + +* While traveling on a numbered road, the route number is displayed in a shield beside the current road name at the bottom of the map. ([#1576](https://github.com/mapbox/mapbox-navigation-ios/pull/1576)) +* Added the `shouldManageApplicationIdleTimer` flag to `NavigationViewController` to allow applications to opt out of automatic `UIApplication.isIdleTimerDisabled` management. ([#1591](https://github.com/mapbox/mapbox-navigation-ios/pull/1591)) +* Added various methods, properties, and initializers to `StatusView`, allowing you to use it in a custom user interface. ([#1612](https://github.com/mapbox/mapbox-navigation-ios/pull/1612)) +* Added `StyleManager.automaticallyAdjustsStyleForTimeOfDay`, `StyleManager.delegate`, and `StyleManager.styles` properties so that you can control same time-based style switching just as `NavigationViewController` does. [#1617](https://github.com/mapbox/mapbox-navigation-ios/pull/1617) +* Fixed an issue where the banner was stuck on rerouting past the reroute threshold when simulating navigation. ([#1583](https://github.com/mapbox/mapbox-navigation-ios/pull/1583)) +* Fixed an issue where the banner appears in the wrong colors after you tap the Resume button. ([#1588](https://github.com/mapbox/mapbox-navigation-ios/pull/1588), [#1589](https://github.com/mapbox/mapbox-navigation-ios/pull/1589)) +* `NavigationMapView`’s user puck now responds to changes to the safe area insets while tracking the user’s location, matching the behavior of the map camera. ([#1653](https://github.com/mapbox/mapbox-navigation-ios/pull/1653)) +* Added `StepsViewControllerDelegate` and `InstructionsBannerViewDelegate` which makes it possible to listen in on tap events that occur in `StepsViewController` and `InstructionsBannerView`. [#1633](https://github.com/mapbox/mapbox-navigation-ios/pull/1633) + +### Feedback + +* Added a `FeedbackViewController` class for soliciting feedback from the user in a custom user interface. ([#1605](https://github.com/mapbox/mapbox-navigation-ios/pull/1605)) +* Replaced `NavigationViewControllerDelegate.navigationViewControllerDidOpenFeedback(_:)` with `FeedbackViewControllerDelegate.feedbackViewControllerDidOpen(_:)`, `NavigationViewControllerDelegate.navigationViewControllerDidCancelFeedback(_:)` with `FeedbackViewControllerDelegate.feedbackViewController(_:didSend:uuid:)`, and `NavigationViewControllerDelegate.navigationViewController(_:didSendFeedbackAssigned:feedbackType)` with `FeedbackViewControllerDelegate.feedbackViewControllerDidCancel(_:)`. ([#1605](https://github.com/mapbox/mapbox-navigation-ios/pull/1605)) +* Fixed a crash that occurred when the end of route view controller appears, showing the keyboard. ([#1599](https://github.com/mapbox/mapbox-navigation-ios/pull/1599/)) + +### Other changes + +* Added a `MapboxVoiceController.audioPlayer` property. You can use this property to interrupt a spoken instruction or adjust the volume. ([#1596](https://github.com/mapbox/mapbox-navigation-ios/pull/1596)) +* Fixed a memory leak when `RouteController.isDeadReckoningEnabled` is enabled. ([#1624](https://github.com/mapbox/mapbox-navigation-ios/pull/1624)) + +## v0.19.2 (August 23, 2018) + +* The `MGLStyle.navigationGuidanceDayStyleURL` and `MGLStyle.navigationGuidanceNightStyleURL` properties now return [version 4 of the Mapbox Navigation Guidance Day and Night styles](https://blog.mapbox.com/incidents-are-live-on-the-map-beeff6b84bf9), respectively. These styles indicate incidents such as road closures and detours. ([#1619](https://github.com/mapbox/mapbox-navigation-ios/pull/1619)) +* Added an `MGLMapView.showsIncidents` property to toggle the visibility of any Mapbox Incidents data on a map view. ([#1613](https://github.com/mapbox/mapbox-navigation-ios/pull/1613)) + +## v0.19.1 (August 15, 2018) + +* Fixed build errors when installing this SDK with Mapbox Maps SDK for iOS v4.3.0 or above. ([#1608](https://github.com/mapbox/mapbox-navigation-ios/pull/1608), [#1609](https://github.com/mapbox/mapbox-navigation-ios/pull/1609)) + +## v0.19.0 (July 24, 2018) + +### Packaging + +* Moved guides and examples to [a new Mapbox Navigation SDK for iOS website](https://docs.mapbox.com/ios/navigation/). ([#1552](https://github.com/mapbox/mapbox-navigation-ios/pull/1552)) +* Applications intended for use in mainland China can set the `MGLMapboxAPIBaseURL` key in Info.plist to `https://api.mapbox.cn/` to use China-optimized APIs. This setting causes `NavigationMapView` to default to China-optimized day and night styles with places and roads labeled in Simplified Chinese. ([#1558](https://github.com/mapbox/mapbox-navigation-ios/pull/1558)) + +### User interface + +* Fixed an issue where selecting a step from the steps list would take the user to the wrong step. ([#1524](https://github.com/mapbox/mapbox-navigation-ios/pull/1524/)) +* The `StyleManagerDelegate.locationFor(styleManager:)` method’s return value is now optional. ([#1523](https://github.com/mapbox/mapbox-navigation-ios/pull/1523)) +* `NavigationViewController` smoothly fades between light and dark status bars. ([#1535](https://github.com/mapbox/mapbox-navigation-ios/pull/1535)) +* Renamed the `InstructionsBannerView.updateInstruction(_:)` method to `InstructionsBannerView.update(for:)`. Added the `NextBannerView.update(for:)` and `LanesView.update(for:)` methods. These methods are intended to be called in response to `Notification.Name.routeControllerDidPassVisualInstructionPoint` if the views are used outside a `NavigationViewController`. By contrast, `InstructionsBannerView.updateDistance(for:)` should be called on every location update. ([#1514](https://github.com/mapbox/mapbox-navigation-ios/pull/1514)) +* Added the `ManeuverView.visualInstruction` and `ManeuverView.drivingSide` properties. ([#1514](https://github.com/mapbox/mapbox-navigation-ios/pull/1514)) + +## v0.18.1 (June 19, 2018) + +### Packaging + +* Increased the minimum deployment target of Core Navigation to iOS 9. ([#1494](https://github.com/mapbox/mapbox-navigation-ios/pull/1494)) + +### User interface + +* Added `NavigationMapView.recenterMap()` for recentering the map if a user gesture causes it to stop following the user. ([#1471](https://github.com/mapbox/mapbox-navigation-ios/pull/1471)) +* Deprecated `NavigationViewController.usesNightStyleInsideTunnels`. Style switching is enabled as a side effect of `TunnelIntersectionManager.tunnelSimulationEnabled`, which is set to `true` by default. ([#1489] +* Fixed an issue where the user location view slid around after the user pressed the Overview button. [#1506](https://github.com/mapbox/mapbox-navigation-ios/pull/1506) + +### Core Navigation + +* Moved `RouteController.tunnelSimulationEnabled` to `TunnelIntersectionManager.tunnelSimulationEnabled`. ([#1489](https://github.com/mapbox/mapbox-navigation-ios/pull/1489)) +(https://github.com/mapbox/mapbox-navigation-ios/pull/1489)) +* Added `RouteControllerDelegate.routeControllerWillDisableBatteryMonitoring(_:)` which allows developers control whether battery monitoring is disabled when `RouteController.deinit()` is called. [#1476](https://github.com/mapbox/mapbox-navigation-ios/pull/1476) +* Fixed an issue where setting `NavigationLocationManager.desiredAccuracy` had no effect. [#1481](https://github.com/mapbox/mapbox-navigation-ios/pull/1481) + +## v0.18.0 (June 5, 2018) + +### User interface + +* Added support for generic route shields. Image-backed route shields also now display as generic (instead of plain text) while the SDK loads the image. [#1190](https://github.com/mapbox/mapbox-navigation-ios/issues/1190), [#1417](https://github.com/mapbox/mapbox-navigation-ios/pull/1417) +* Fixed an issue when going into overhead mode with a short route. [#1456](https://github.com/mapbox/mapbox-navigation-ios/pull/1456/) +* Adds support for Xcode 10 Beta 1. [#1499](https://github.com/mapbox/mapbox-navigation-ios/pull/1499), [#1478](https://github.com/mapbox/mapbox-navigation-ios/pull/1478) + +### Core Navigation + +* `TunnelIntersectionManagerDelegate` methods no longer take a completion handler argument. ([#1414](https://github.com/mapbox/mapbox-navigation-ios/pull/1414)) +* Added the ability to render more than 1 alternate route. [#1372](https://github.com/mapbox/mapbox-navigation-ios/pull/1372/) +* `NavigationMapViewDelegate.navigationMapView(_:shapeFor:)` Now expects an array of `Route`. The first route will be rendered as the main route, all subsequent routes will be rendered as alternate routes. +* Animating the user through tunnels and automatically switching the map style when entering a tunnel is now on by default. [#1449](https://github.com/mapbox/mapbox-navigation-ios/pull/1449) +* Adds `RouteControllerDelegate.routeController(_:shouldPreventReroutesWhenArrivingAt:waypoint:)` which is called each time a driver arrives at a waypoint. By default, this method returns true and prevents rerouting upon arriving. Progress updates still occur. [#1454](https://github.com/mapbox/mapbox-navigation-ios/pull/1454/) + +## v0.17.0 (May 14, 2018) + +### Packaging + +* Upgraded to the [Mapbox Maps SDK for iOS v4.0.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/ios-v4.0.0). If you have customized the route map’s appearance, you may need to migrate your code to use expressions instead of style functions. ([#1076](https://github.com/mapbox/mapbox-navigation-ios/pull/1076)) +* Added a Korean localization. ([#1346](https://github.com/mapbox/mapbox-navigation-ios/pull/1346)) + +### User interface + +* Exit indications are now drawn accurately with a correct exit heading. ([#1288](https://github.com/mapbox/mapbox-navigation-ios/pull/1288)) +* Added the `NavigationViewControllerDelegate.navigationViewController(_:roadNameAt:)` method for customizing the contents of the road name label that appears towards the bottom of the map view. ([#1309](https://github.com/mapbox/mapbox-navigation-ios/pull/1309)) +* If the SDK tries but fails to reroute the user, the “Rerouting…” status view no longer stays visible permanently. ([#1357](https://github.com/mapbox/mapbox-navigation-ios/pull/1357)) +* Completed waypoints now remain on the map but are slightly translucent. ([#1364](https://github.com/mapbox/mapbox-navigation-ios/pull/1364)) +* Fixed an issue preventing `NavigationViewController.navigationMapView(_:simplifiedShapeDescribing:)` (now `NavigationViewController.navigationMapView(_:simplifiedShapeFor:)`) from being called. ([#1413](https://github.com/mapbox/mapbox-navigation-ios/pull/1413)) + +### Spoken instructions + +* Fixed an issue causing the wrong instructions to be spoken. ([#1396](https://github.com/mapbox/mapbox-navigation-ios/pull/1396)) + +### User location + +* The `RouteController.routeProgress` property is now available in Objective-C. ([#1323](https://github.com/mapbox/mapbox-navigation-ios/pull/1323)) +* Added a `RouteController.tunnelSimulationEnabled` option that keeps the user location indicator moving steadily while the user travels through a tunnel and GPS reception is unreliable. ([#1218](https://github.com/mapbox/mapbox-navigation-ios/pull/1218)) + +### Other changes + +* `DistanceFormatter`, `ReplayLocationManager`, `SimulatedLocationManager`, `LanesView`, and `ManueverView` are now subclassable. ([#1345](https://github.com/mapbox/mapbox-navigation-ios/pull/1345)) +* Renamed many `NavigationViewController` and `NavigationMapViewDelegate` methods ([#1364](https://github.com/mapbox/mapbox-navigation-ios/pull/1364), [#1338](https://github.com/mapbox/mapbox-navigation-ios/pull/1338), [#1318](https://github.com/mapbox/mapbox-navigation-ios/pull/1318), [#1378](https://github.com/mapbox/mapbox-navigation-ios/pull/1378), [#1413](https://github.com/mapbox/mapbox-navigation-ios/pull/1413)): + * `NavigationViewControllerDelegate.navigationViewControllerDidCancelNavigation(_:)` to `NavigationViewControllerDelegate.navigationViewControllerDidDismiss(_:byCanceling:)` + * `-[MBNavigationViewControllerDelegate navigationViewController:didArriveAt:]` to `-[MBNavigationViewControllerDelegate navigationViewController:didArriveAtWaypoint:]` in Objective-C + * `NavigationViewControllerDelegate.navigationMapView(_:routeStyleLayerWithIdentifier:source:)` to `NavigationViewControllerDelegate.navigationViewController(_:routeStyleLayerWithIdentifier:source:)` + * `NavigationViewControllerDelegate.navigationMapView(_:routeCasingStyleLayerWithIdentifier:source:)` to `NavigationViewControllerDelegate.navigationViewController(_:routeCasingStyleLayerWithIdentifier:source:)` + * `NavigationViewControllerDelegate.navigationMapView(_:shapeFor:)` to `NavigationViewControllerDelegate.navigationViewController(_:shapeFor:)` + * `NavigationViewControllerDelegate.navigationMapView(_:simplifiedShapeFor:)` to `NavigationViewControllerDelegate.navigationViewController(_:simplifiedShapeFor:)` + * `NavigationViewControllerDelegate.navigationMapView(_:waypointStyleLayerWithIdentifier:source:)` to `NavigationViewControllerDelegate.navigationViewController(_:waypointStyleLayerWithIdentifier:source:)` + * `NavigationViewControllerDelegate.navigationMapView(_:waypointSymbolStyleLayerWithIdentifier:source:)` to `NavigationViewControllerDelegate.navigationViewController(_:waypointSymbolStyleLayerWithIdentifier:source:)` + * `NavigationViewControllerDelegate.navigationMapView(_:shapeFor:legIndex:)` to `NavigationViewControllerDelegate.navigationViewController(_:shapeFor:legIndex:)` + * `NavigationViewControllerDelegate.navigationMapView(_:didTap:)` to `NavigationViewControllerDelegate.navigationViewController(_:didSelect:)` + * `NavigationViewControllerDelegate.navigationMapView(_:imageFor:)` to `NavigationViewControllerDelegate.navigationViewController(_:imageFor:)` + * `NavigationViewControllerDelegate.navigationMapView(_:viewFor:)` to `NavigationViewControllerDelegate.navigationViewController(_:viewFor:)` + * `NavigationViewControllerDelegate.navigationViewController(_:didSend:feedbackType:)` to `NavigationViewControllerDelegate.navigationViewController(_:didSendFeedbackAssigned:feedbackType:)` + * `-[MBNavigationViewControllerDelegate navigationViewController:shouldDiscard:]` to `-[MBNavigationViewControllerDelegate navigationViewController:shouldDiscardLocation:]` in Objective-C + * `-[MBNavigationViewControllerDelegate navigationViewController:roadNameAt:]` to `-[MBNavigationViewControllerDelegate navigationViewController:roadNameAtLocation:]` + * `NavigationMapViewDelegate.navigationMapView(_:shapeDescribing:)` to `NavigationMapViewDelegate.navigationMapView(_:shapeFor:)`. + * `NavigationMapViewDelegate.navigationMapView(_:simplifiedShapeDescribing:)` to `NavigationMapViewDelegate.navigationMapView(_:simplifiedShapeFor:)`. + * `-[MBNavigationMapViewDelegate navigationMapView:shapeDescribingWaypoints:legIndex:]` to `-[MBNavigationMapViewDelegate navigationMapView:shapeForWaypoints:legIndex:]` in Objective-C +* `RouteController.recordFeedback(type:description:)` now returns a `UUID` instead of a string. Some `RouteController` methods have been renamed to accept `UUID`s as arguments instead of strings. ([#1413](https://github.com/mapbox/mapbox-navigation-ios/pull/1413)) +* Renamed `TunnelIntersectionManagerDelegate.tunnelIntersectionManager(_:willEnableAnimationAt:callback:)` to `TunnelIntersectionManagerDelegate.tunnelIntersectionManager(_:willEnableAnimationAt:completionHandler:)` and `TunnelIntersectionManagerDelegate.tunnelIntersectionManager(_:willDisableAnimationAt:callback:)` to `TunnelIntersectionManagerDelegate.tunnelIntersectionManager(_:willDisableAnimationAt:completionHandler:)`. ([#1413](https://github.com/mapbox/mapbox-navigation-ios/pull/1413)) + +## v0.16.2 (April 13, 2018) + +* Fixed a compiler error after installing the SDK using CocoaPods. ([#1296](https://github.com/mapbox/mapbox-navigation-ios/pull/1296)) + +## v0.16.1 (April 9, 2018) + +### User interface + +* Draws slight right and left turn icons for slight turns in the turn lane view. [#1270](https://github.com/mapbox/mapbox-navigation-ios/pull/1270) + +### Core Navigation + +* Fixed a crash that was caused by check the edit distance of an empty string. [#1281](https://github.com/mapbox/mapbox-navigation-ios/pull/1281/) +* Removes warnings when using Swift 4.1. [#1271](https://github.com/mapbox/mapbox-navigation-ios/pull/1271) + +### Spoken instructions + +* Fixed an issue that would preemptively fallback to the default speech synthesizer. [#1284](https://github.com/mapbox/mapbox-navigation-ios/pull/1284) + +## v0.16.0 (March 26, 2018) + +### User interface +* While the user travels through a tunnel, `NavigationMapView` temporarily applies a night style (a style whose `styleType` property is set to `StyleType.night`). ([#1127](https://github.com/mapbox/mapbox-navigation-ios/pull/1127)) +* The user can reveal the list of upcoming steps by swiping downward from the top banner. ([#1150](https://github.com/mapbox/mapbox-navigation-ios/pull/1150)) +* Renamed `StyleType.dayStyle` and `StyleType.nightStyle` to `StyleType.day` and `StyleType.night`, respectively. ([#1250](https://github.com/mapbox/mapbox-navigation-ios/pull/1250)) +* Fixed an issue causing the overview map to insist on centering the route upon each location update. ([#1223](https://github.com/mapbox/mapbox-navigation-ios/pull/1223)) +* Improved the contrast of `TimeRemainingLabel.trafficSevereColor` against `BottomBannerView.backgroundColor` in `NightStyle`. ([#1228](https://github.com/mapbox/mapbox-navigation-ios/pull/1228)) +* Fixed an issue where a slash appeared between two shields in the top banner. ([#1169](https://github.com/mapbox/mapbox-navigation-ios/pull/1169)) +* Fixed an issue where using `NavigationMapViewControllerDelegate.navigationMapView(_:imageFor:)` would not override the destination annotation. ([#1256](https://github.com/mapbox/mapbox-navigation-ios/pull/1256)) +* Adds a handle at the bottom of the banner to reveals additional instructions. ([#1253](https://github.com/mapbox/mapbox-navigation-ios/pull/1253)) + +### Spoken instructions +* Audio data for spoken instructions is cached in device storage to minimize data usage. ([#12296](https://github.com/mapbox/mapbox-navigation-ios/pull/1226)) + +### Core Navigation +* Renamed the `RouteController.reroutesOpportunistically` property to `RouteController.reroutesProactively`, `RouteControllerOpportunisticReroutingInterval` global variable to `RouteControllerProactiveReroutingInterval`, and the `RouteControllerNotificationUserInfoKey.isOpportunisticKey` value to `RouteControllerNotificationUserInfoKey.isProactiveKey`. ([#1230](https://github.com/mapbox/mapbox-navigation-ios/pull/1230)) +* Added a `RouteStepProgress.currentIntersection` property that is set to the intersection the user has most recently passed along the route. ([#1127](https://github.com/mapbox/mapbox-navigation-ios/pull/1127)) +* Fixed an issue where the `RouteStepProgress.upcomingIntersection` property was always set to the current step’s first intersection. ([#1127](https://github.com/mapbox/mapbox-navigation-ios/pull/1127)) +* Added support for using the Mapbox Map Matching API. [#1177](https://github.com/mapbox/mapbox-navigation-ios/pull/1177) + +### Other changes +* Added Arabic and European Portuguese localizations. ([#1252](https://github.com/mapbox/mapbox-navigation-ios/pull/1251)) + +## v0.15.0 (March 13, 2018) + +#### Breaking changes +* `NavigationMapViewDelegate` and `RouteMapViewControllerDelegate`: `navigationMapView(_:didTap:)` is now `navigationMapView(_:didSelect:)` [#1063](https://github.com/mapbox/mapbox-navigation-ios/pull/1063) +* The Constants that concern Route-Snapping logic have been re-named. The new names are: `RouteSnappingMinimumSpeed`, `RouteSnappingMaxManipulatedCourseAngle`, and `RouteSnappingMinimumHorizontalAccuracy`. + +#### User interface +* `StepsViewController` 's convenience initializer (`StepsViewController.init(routeProgress:)`) is now public. ([#1167](https://github.com/mapbox/mapbox-navigation-ios/pull/1167)) +* Fixed an issue preventing the distance from appearing in the turn banner when the system language was set to Hebrew and the system region was set to Israel or any other region that uses the metric system. ([#1176](https://github.com/mapbox/mapbox-navigation-ios/pull/1176)) +* Various views and view controllers correctly mirror right-to-left in Hebrew. ([#1182](https://github.com/mapbox/mapbox-navigation-ios/pull/1182)) + +#### Core Navigation +* `RoteController` now has a new property, `snappedLocation`. This property represents the raw location, snapped to the current route, if applicable. If not applicable, the value is `nil`. +* `RouteController`'s `MBRouteControllerProgressDidChange` notification now exposes the raw location in it's update, accessible by `MBRouteControllerRawLocationKey` + +#### Voice guidance + +* Fixed an issue that caused `RouteVoiceController` and `MabpboxVoiceController` to speak over one another. [#1213](https://github.com/mapbox/mapbox-navigation-ios/pull/1213) + +#### Other changes +* Fixed a crash while navigating that affected applications that do not use Mapbox-hosted styles or vector tiles. [#1183](https://github.com/mapbox/mapbox-navigation-ios/pull/1183) +* The `DistanceFormatter.attributedString(for:)` method is now implemented. It returns an attributed string representation of the distance in which the `NSAttributedStringKey.quantity` attribute is applied to the numeric quantity. ([#1176](https://github.com/mapbox/mapbox-navigation-ios/pull/1176)) +* Fixed an issue in which turn lanes were displayed in the wrong order when the system language was set to Hebrew. ([#1175](https://github.com/mapbox/mapbox-navigation-ios/pull/1175)) + +## v0.14.0 (February 22, 2018) + +#### Breaking changes + +* Removed the dependency on AWSPolly. Voice announcements are now coming directly from Mapbox and for free for all developers. Because of this, PollyVoiceController has been removed. [#617](https://github.com/mapbox/mapbox-navigation-ios/pull/617) +* MapboxDirections.swift version 0.17.x is now required. [#1085](https://github.com/mapbox/mapbox-navigation-ios/pull/1085) +* Removed the key `RouteControllerNotificationUserInfoKey.estimatedTimeUntilManeuverKey` from `.routeControllerProgressDidChange`. Please use `durationRemaining` instead which can be found on the `RouteProgress`. [#1126](https://github.com/mapbox/mapbox-navigation-ios/pull/1126/) +* Renamed notification names associated with `RouteController` in Objective-C code. [#1122](https://github.com/mapbox/mapbox-navigation-ios/pull/1122) +* The user info keys of `RouteController`-related notifications have been renamed and are now members of the `RouteControllerNotificationUserInfoKey` struct in Swift and the `MBRouteControllerNotificationUserInfoKey` extensible enumeration in Objective-C. [#1122](https://github.com/mapbox/mapbox-navigation-ios/pull/1122) + +
+Here is reference for the new notification names: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SwiftObjective-C
OldNewOldNew
Notification.Name.navigationSettingsDidChangeNotification.Name.navigationSettingsDidChangeMBNavigationSettingsDidChangeMBNavigationSettingsDidChangeNotification
Notification.Name.routeControllerProgressDidChangeNotification.Name.routeControllerProgressDidChangeMBRouteControllerNotificationProgressDidChangeMBRouteControllerProgressDidChangeNotification
Notification.Name.routeControllerDidPassSpokenInstructionPointNotification.Name.routeControllerDidPassSpokenInstructionPointMBRouteControllerDidPassSpokenInstructionPointMBRouteControllerDidPassSpokenInstructionPointNotification
Notification.Name.routeControllerWillRerouteNotification.Name.routeControllerWillRerouteMBRouteControllerWillRerouteMBRouteControllerWillRerouteNotification
Notification.Name.routeControllerDidRerouteNotification.Name.routeControllerDidRerouteMBRouteControllerDidRerouteMBRouteControllerDidRerouteNotification
Notification.Name.routeControllerDidFailToRerouteNotification.Name.routeControllerDidFailToRerouteMBRouteControllerDidFailToRerouteMBRouteControllerDidFailToRerouteNotification
RouteControllerProgressDidChangeNotificationProgressKeyRouteControllerNotificationUserInfoKey.routeProgressKeyMBRouteControllerProgressDidChangeNotificationProgressKeyMBRouteControllerRouteProgressKey
RouteControllerProgressDidChangeNotificationLocationKeyRouteControllerNotificationUserInfoKey.locationKeyMBRouteControllerProgressDidChangeNotificationLocationKeyMBRouteControllerLocationKey
RouteControllerProgressDidChangeNotificationSecondsRemainingOnStepKey🚮 (removed)MBRouteControllerProgressDidChangeNotificationSecondsRemainingOnStepKey🚮 (removed)
RouteControllerNotificationLocationKeyRouteControllerNotificationUserInfoKey.locationKeyMBRouteControllerNotificationLocationKeyMBRouteControllerLocationKey
RouteControllerNotificationRouteKey🚮 (unused)MBRouteControllerNotificationRouteKey🚮 (unused)
RouteControllerNotificationErrorKeyRouteControllerNotificationUserInfoKey.routingErrorKeyMBRouteControllerNotificationErrorKeyMBRouteControllerRoutingErrorKey
RouteControllerDidFindFasterRouteKeyRouteControllerNotificationUserInfoKey.isOpportunisticKeyMBRouteControllerDidFindFasterRouteKeyMBRouteControllerIsOpportunisticKey
RouteControllerDidPassSpokenInstructionPointRouteProgressKeyRouteControllerNotificationUserInfoKey.routeProgressKeyMBRouteControllerDidPassSpokenInstructionPointRouteProgressKeyMBRouteControllerRouteProgressKey
+
+ +## Core Navigation + +* Location updates sent via `.routeControllerProgressDidChange` are now always sent as long as the location is qualified. [#1126](https://github.com/mapbox/mapbox-navigation-ios/pull/1126/) +* Exposes `setOverheadCameraView(from:along:for:)` which is useful for fitting the camera to an overhead view for the remaining route coordinates. +* Changed the heuristics needed for a the users location to unsnap from the route line. [#1110](https://github.com/mapbox/mapbox-navigation-ios/pull/1122) +* Changes `routeController(:didDiscardLocation:)` to `routeController(:shouldDiscardLocation:)`. Now if implemented, developers can choose to keep a location when RouteController deems a location unqualified. [#1095](https://github.com/mapbox/mapbox-navigation-ios/pull/1095/) + +## User interface + +* Added a `NavigationMapView.localizeLabels()` method that should be called within `MGLMapViewDelegate.mapView(_:didFinishLoading:)` for standalone `NavigationMapView`s to ensure that map labels are in the correct language. [#1111](https://github.com/mapbox/mapbox-navigation-ios/pull/1122) +* The `/` delimiter is longer shown when a shield is shown on either side of the delimiter. This also removes the dependency SDWebImage. [#1046](https://github.com/mapbox/mapbox-navigation-ios/pull/1046) +* Exposes constants used for styling the route line. [#1124](https://github.com/mapbox/mapbox-navigation-ios/pull/1124/) +* Exposes `update(for:)` on `InstructionBannerView`. This is helpful for developers creating a custom user interface. [#1085](https://github.com/mapbox/mapbox-navigation-ios/pull/1085/) + +## Voice guidance + +* Exposes `RouteVoiceController.speak(_:)` which would allow custom subclass of MapboxVoiceController to override this method and pass a modified SpokenInstruction to our superclass implementation. + +## v0.13.1 (February 7, 2018) + +### Core Navigation + +* Fixes a bug where the `spokenInstructionIndex` was incremented beyond the number of instructions for a step. (#1080) +* Fixed a bug that crashed when navigating beyond the final waypoint. (#1087) +* Added `NavigationSettings.distanceUnit` to let a user override the default unit of measurement for the device’s region setting. (#1055) + +### User interface + +* Added support for spoken instructions in Danish. (#1041) +* Updated translations for Russian, Swedish, Spanish, Vietnamese, Hebrew, Ukrainian, and German. (#1064) +* Fixed a bug that prevented the user puck from laying flat when rotating the map. (#1090) +* Updated translations for Russian, Swedish, Spanish, Vietnamese, Hebrew, Ukrainian, and German. (#1064) (#1089) + +## v0.13.0 (January 22, 2018) + +### Packaging + +* Upgraded to MapboxDirections.swift [v0.16.0](https://github.com/mapbox/MapboxDirections.swift/releases/tag/v0.16.0), which makes `ManeuverType`, `ManeuverDirection`, and `TransportType` non-optional. (#1040) +* Added Danish and Hebrew localizations. (#1031, #1043) + +### User location + +* Removed `RouteControllerDelegate.routeController(_:shouldIncrementLegWhenArrivingAtWaypoint:)` and `NavigationViewControllerDelegate.navigationViewController(_:shouldIncrementLegWhenArrivingAtWaypoint:)`. `RouteControllerDelegate.routeController(_:didArriveAt:)` and `NavigationViewControllerDelegate.navigationViewController(_:didArriveAt:)` now return a Boolean that determines whether the route controller automatically advances to the next leg of the route. (#1038) +* Fixed an issue where `NavigationViewControllerDelegate.navigationViewController(_:didArriveAt:)` was called twice at the end of the route. (#1038) +* Improved the reliability of user location tracking when several location updates arrive simultaneously. (#1021) + +### User interface + +* Removed the `WayNameView` class in favor of `WayNameLabel` and renamed the `LanesContainerView` class to `LanesView`. (#981 ) +* Added a `NavigationMapView.tracksUserCourse` property for enabling course tracking mode when using the map view independently of `NavigationViewController`. (#1015) + +## v0.12.2 (January 12, 2018) + +Beginning with this release, we’ve compiled [a set of examples](https://docs.mapbox.com/ios/api/navigation/0.12.2/Examples.html) showing how to accomplish common tasks with this SDK. You can also check out the [navigation-ios-examples](https://github.com/mapbox/navigation-ios-examples) project and run the included application on your device. + +### User interface + +* Fixed a crash loading `NavigationViewController`. (#977) +* Fixed issues causing the user puck to animate at the wrong framerate while the device is unplugged. (#970) +* Fixed unexpected behavior that occurred if only one `Style` was specified when initializing `NavigationViewController`. (#990) + +### Core Navigation + +* If `RouteController` initially follows an alternative route, it now attempts to follow the most similar route after rerouting. (#995) +* Fixed an issue preventing the `RouteControllerDelegate.routeController(_:didArriveAt:)` method from being called if `navigationViewController(_:shouldIncrementLegWhenArrivingAtWaypoint:)` was unimplemented. (#984) +* Added a `VoiceControllerDelegate.voiceController(_:willSpeak:routeProgress:)` method for changing spoken instructions on an individual basis. (#988) + +## v0.12.1 (January 6, 2018) + +### User interface + +* Fixed an issue where the “then” banner appeared at the wrong times. (#957) +* Fixed an issue where the user location view spun around at the end of a leg. (#966) + +### Core Navigation + +* Fixed an issue that triggered unnecessary reroutes. (#959) +* The `RouteControllerDelegate.routeController(_:didArriveAt:)` method is now called when arriving at any waypoint, not just the last waypoint. (#972) +* Added a `RouteController.setEndOfRoute(_:comment:)` method for collecting feedback about the route before the user cancels it. (#965) + +## v0.12.0 (December 21, 2017) + +### Breaking changes 🚨 + +* If you install this SDK using Carthage, you must now include each of this SDK’s dependencies in your Run Script build phase: AWSCore.framework, AWSPolly.framework, Mapbox.framework, MapboxDirections.framework, MapboxMobileEvents.framework, Polyline.framework, SDWebImage.framework, Solar.framework, and Turf.framework. These dependencies are no longer embedded inside MapboxNavigation.framework. See [the Carthage documentation](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos) for details. (#930) +* This library no longer depends on [OSRM Text Instructions for Swift](https://github.com/Project-OSRM/osrm-text-instructions.swift/). If you have previously installed this SDK using Carthage, you may need to remove OSRMTextInstructions.framework from a Run Script build step. (#925) +* Notification names are now members of `Notification.Name`. (#943) + +### User interface + +* When the user approaches the final waypoint, a panel appears with options for sending feedback about the route. (#848) +* Fixed an issue preventing the “Then” banner from appearing. (#940) +* Fixed an issue that sometimes prevented the night style from being applied. (#904) +* The turn banner’s labels and route shield images are now derived from the Directions API response. (#767) +* Roundabout icons in the turn banner now go clockwise in regions that drive on the left. (#911) +* Fixed an issue that turned the estimated arrival time to black when traffic congestion data was unavailable. (#912) +* Added a Bulgarian localization. [Help us speak your language!](https://www.transifex.com/mapbox/mapbox-navigation-ios/) (#954) +* Updated Dutch, Spanish, Swedish, and Vietnamese translations. (#944) + +### Voice guidance + +* Tapping the mute button immediately silences any current announcement. (#936) +* Improved announcements near roundabouts and rotaries when using `NavigationRouteOptions`. You can also set the `RouteOptions.includesExitRoundaboutManeuver` property manually to take advantage of this improvement. (#945) +* You can customize the AWS region used for Amazon Polly spoken instructions using the `PollyVoiceController(identityPoolId:regionType:)` initializer. (#914) +* Certain roads [tagged with pronunciations in OpenStreetMap](https://wiki.openstreetmap.org/wiki/Key:name:pronunciation) are pronounced correctly when Amazon Polly is unavailable. (#624) +* Refined the appearance of the spoken instruction map labels that are enabled via the `NavigationViewController.annotatesSpokenInstructions` property. (#907) + +### User location + +* When `SimulatedLocationManager` is active, the user can swipe on the “Simulating Navigation” banner to adjust the rate of travel. (#915) +* Fixed unnecessary rerouting that sometimes occurred if the user advanced to a subsequent step earlier than expected. (#910) +* If your application’s Info.plist file lacks a location usage description, `NavigationViewController` will immediately fail a `precondition`. (#947) + +## v0.11.0 (November 29, 2017) + +Beginning with this release, the navigation SDK and Core Navigation are written in Swift 4 (#663). + +### Feedback + +* Removed the audio feedback recording feature. You no longer need to add an `NSMicrophoneUsageDescription` to your Info.plist. (#870) +* The Report Feedback button no longer appears after rerouting if `NavigationViewController.showsReportFeedback` is disabled. (#890) + +### User interface + +* Added a `StepsViewController` class for displaying the route’s upcoming steps in a table view. (#869) +* The bottom bar is more compact in landscape orientation. (#863) +* Fixed an issue where the “then” banner appeared too soon. (#865) +* Maneuver arrows are no longer shown for arrival maneuvers. (#884) +* Fixed a crash that sometimes occurred after returning to the application from the background. (#888) + +### Voice guidance + +* A new `RouteVoiceController.voiceControllerDelegate` property lets an object conforming to the `VoiceControllerDelegate` protocol know when a spoken instruction fails or gets interrupted by another instruction. (#800, #864) + +### User location + +* Fixed an issue that sometimes prevented `NavigationViewControllerDelegate.navigationViewController(_:didArriveAt:)` from getting called. (#883) +* Fixed an issue where the user location indicator floated around when starting a new leg. (#886) + +## v0.10.1 (November 16, 2017) + +### Packaging + +* Reverts a change that used AWS's repo for the Polly dependency. This will help with build times when using Carthage. #859 +* Updates Polly dependency to v2.6.5 #859 + +### Views + +* Aligns the instruction banner and the next banner better. #860 +* Fixes a bug on `InstructionsBannerView` and `StepInstructionsView` that prevented them from being styleable. #852 +* Fixes a few minor styleable elements on `DayStyle` and `NightStyle`. #858 + +### Map + +* `MGLMapView init(frame:styleURL:)` is exposed again on `NavigationMapView`. #850 + +### User location tracking + +* The refresh rate of the user puck remains throttled if the upcoming step is straight. #845 + +### Feedback + +* The `Report Feedback` button after rerouting is only displayed for 5 seconds. #853 + +## v0.10.0 (November 13, 2017) + +### Packaging + +* Xcode 9 is required for building the navigation SDK or Core Navigation. (#786) +* Added German and Dutch localizations. [Help us speak your language!](https://www.transifex.com/mapbox/mapbox-navigation-ios/dashboard/) (#778) +* To build and run the provided sample applications, you now have the option to create a plain text file named .mapbox containing a Mapbox access token and place it in your home folder. The SDK will read this file and automatically populate the `MGLMapboxAccessToken` of the `Info.plist` at build-time. (#817) + +### Instruction banner + +* Improved `NavigationViewController`’s layout on iPhone X. (#786, #816) +* Refined the turn banner’s appearance. (#745, #788) +* Added a reusable `InstructionBannerView` class that represents the turn banner. (#745) +* Route shields are displayed inline with road or place names in `InstructionBannerView`. (#745) +* When another step follows soon after the upcoming step, that subsequent step appears in a smaller banner beneath the main turn banner. (#819) + +### Map + +* The map zooms in and out dynamically to show more of the road ahead. (#769, #781) +* Replaced `NavigationMapView.showRoute(_:)` with `NavigationMapView.showRoutes(_:legIndex:)`, which can show alternative routes on the map. (#789) +* Added a `NavigationMapViewDelegate.navigationMapView(_:didSelect:)` method to respond to route selection on the map. (#789, #806) +* Added a `NavigationMapViewDelegate.navigationMapView(_:didSelect:)` method to respond to waypoint selection on the map. (#806) +* Fixed a bug preventing legs beyond the third waypoint from appearing. (#807) +* Decreased the map’s animation frame rate for improved battery life. (#760) + +### Voice guidance + +* Spoken instructions are determined by Directions API responses. (#614) +* When Polly is enabled, audio for spoken instructions is fetched over the network ahead of time, reducing latency. (#724, #768) +* The `NavigationViewController.annotatesSpokenInstructions` property, disabled by default, makes it easier to see where instructions will be read aloud along the route for debugging purposes. (#727, #826) +* Fixed an issue preventing `PollyVoiceController` from ducking background audio while the device is muted using the physical switch. (#805) + +### User location tracking + +* Fixed an issue causing poor user location tracking on iPhone X. (#833) +* The user location indicator is more stable while snapped to the route line. (#754) +* Renamed `RouteController.checkForFasterRouteInBackground` to `RouteController.reroutesOpportunistically`. (#826) +* Added a `RouteControllerOpportunisticReroutingInterval` constant for configuring the interval between opportunistic rerouting attempts. (#826) + +### Feedback + +* The `NavigationViewController.recordsAudioFeedback` property, disabled by default, allows the user to dictate feedback by long-pressing on a feedback item. This option requires the `NSMicrophoneUsageDescription` Info.plist option. (#719, #826) +* Options in the feedback interface are easier to discern from each other. (#761) +* Fixed an issue where the feedback interface appeared automatically after rerouting. (#749) +* Rearranged the feedback options. (#770, #779) + +## v0.9.0 (October 17, 2017) + +* `NavigationMapView` uses a custom course tracking mode created from the ground up. The view representing the user’s location (the “user puck”) is larger and easier to see at a glance, and it continues to point in the user’s direction of travel even in Overview mode. To customize the user puck, use the `NavigationMapView.userCourseView` property. (#402) +* Fixed an issue causing the user puck to slide downward from the center of the screen when beginning a new route. (#402) +* You can customize the user puck’s location on screen by implementing the `NavigationViewControllerDelegate.navigationViewController(_:mapViewUserAnchorPoint:)` method. (#402) +* Improved user course snapping while not moving. (#718) +* Throttled the map’s frame rate while the device is unplugged. (#709) +* Fixed an issue causing the “Rerouting” banner to persist even after a new route is received. (#707) +* A local user notification is no longer posted when rerouting. (#708) + +## v0.8.3 (October 9, 2017) + +* Pins the dependency `Solar` to v2.0.0. This should fix some build issues. #693 +* Increases the width of the upcoming maneuver arrow. #671 +* Improved user location snapping. #679 +* Improves simulation mode by using more accurate speeds. #683 +* Adopted [Turf](https://github.com/mapbox/turf-swift). The `wrap(_:min:max:)` function has been removed; use Turf’s `CLLocationDirection.wrap(min:max:)` instead. #653 +* Defaulted to `kCLLocationAccuracyBestForNavigation` for location accuracy. #670 + +## v0.8.2 (September 29, 2017) + +* Fixed a bug which caused the upcoming maneuver label in night mode to have a white background (#667). +* Fixed a bug which caused audio announcements to be repeated over one another (#661, #669). + +## v0.8.1 (September 28, 2017) + +* Fixed a build error that occurred if MapboxNavigation was installed via CocoaPods. (#632) +* The turn banner shows more of the upcoming road name before truncating. (#657) +* When entering a roundabout, the icon in the turn banner indicates the correct direction of travel. (#640) +* When beginning a new route, the SDK announces the initial road and direction of travel. (#654) +* Fixed an issue causing the user’s location to be snapped to the wrong part of the route near a U-turn. (#642) +* Core Navigation detects when the user performs a U-turn earlier than anticipated and promptly calculates a new route. (#646) +* If Amazon Polly is configured but unreachable, the SDK switches to AVSpeechSynthesizer sooner, before the instruction becomes outdated. (#652) +* When instructions are announced by Amazon Polly, [dynamic range compression](https://en.wikipedia.org/wiki/Dynamic_range_compression) is used to make the audio easier to hear over the din of a moving vehicle. (#635, #662) + +## v0.8.0 (September 19, 2017) + +### Location and guidance + +* Fixed an issue causing steps to be linked together too frequently. (#573) +* On a freeway, an announcement is read aloud at ¼ mile ahead of a maneuver instead of ½ mile ahead. (#569) +* Separate instructions are given for entering and exiting a roundabout. (#561) +* Rerouting occurs more promptly when the user makes a wrong turn at an intersection. (#560) +* More unreliable location updates are filtered out. (#579) +* Improved how Polly pronounces some road names and numbers. (#618, #622) +* Instructions are read by the higher-quality [Alex](https://support.apple.com/en-us/HT203077) voice if it is installed and Polly is unconfigured or unavailable. (#612) + +### User interface + +* Adjusted the night style to take effect closer to sunset. (#584) +* Fixed an issue where the map bore a day style while the surrounding UI bore a night style. (#572) +* Fixed an issue causing some elements on the map to disappear when switching styles. (#570) +* Fixed an issue causing slight turns to look like regular turns in the turn banner. (#602) +* Large, named roundabouts are symbolized as roundabouts instead of simple intersections in the turn banner. (#574) +* Fixed an issue producing confusing lane arrows at a fork in the road. (#586) +* The notification for a completed maneuver is removed as the user completes that step. (#577) +* The distance in the turn banner changes at a more regular interval. (#626) +* Updated the appearance of various controls in turn-by-turn mode. (#578, #587, #588, #591) +* Arrows in the turn banner can have a different appearance than arrows in the step table. (#571) +* Fixed overly aggressive abbreviation of road names in the turn banner. (#616) +* Fixed an issue preventing road names in the turn banner from being abbreviated when certain punctuation was present. (#618) +* Fixed a crash that occurred when an attempt to calculate a new route failed. (#585) +* Fixed an issue preventing the estimated arrival time from being updated as the user is stuck in traffic. (#595) +* Fixed a crash that sometimes occurred when starting turn-by-turn navigation. (#607) +* Fixed a flash that occurred when rerouting. (#605) +* Fixed memory leaks. (#609, #628) + +### Other changes + +* Fixed strings in the Hungarian, Swedish, and Vietnamese localizations that had reverted to English. (#619) +* Updated translations in Catalan, Hungarian, Lithuanian, Russian, Spanish, Swedish, and Vietnamese. (#619) +* Added methods to `NavigationViewControllerDelegate` that indicate when the user is sending feedback. (#599) +* Fixed an issue where `DistanceFormatter.string(fromMeters:)` used the wrong units. (#613) + +## v0.7.0 (August 30, 2017) + +### Packaging + +* Unpinned most dependencies to avoid various build issues introduced in v0.6.1. It is once again possible to use this SDK with the latest Mapbox iOS SDK. (#525) +* Added Russian, Slovenian, and Ukrainian localizations. (#505, #542) + +### User interface + +* `NavigationViewController` and its map automatically switch between daytime and nighttime styles. (#519) +* A banner appears when the device experiences weak GPS reception. (#490) +* A banner also appears when simulation mode is enabled. (#521) +* The time remaining in the bottom bar changes color based on the level of traffic congestion along the remaining route. (#403) +* Added `NavigationViewControllerDelegate.navigationMapView(_:viewFor:)` for providing a custom user location annotation and/or destination annotation. (#498) +* Moved various properties of `Style` to individual control classes. (#536) +* Added properties to `LaneArrowView` for customizing the appearance of lane indicators. (#490) +* Added a `Style.statusBarStyle` property for customizing the appearance of the status bar. (#512) +* A shield now appears in the turn banner on Puerto Rico routes. (#529) +* Fixed an issue preventing an arrow from appearing on the route line when the user swipes the turn banner to a future step. (#532) +* Fixed an issue causing the shield in the turn banner to go blank when the user swipes the turn banner backward. (#506) +* Fixed an issue that caused the camera to stutter when completing a maneuver. (#520) +* Fixed an issue causing the turn banner to remain on a future step after tapping Resume. (#508) +* Fixed an issue where the distance would sometimes be displayed as “0 mm”. (#517) +* Fixed a missing less-than sign in the bottom bar when little time remains on the step or route. (#527) + +### Voice guidance + +* Fixed an issue causing Polly to misread abbreviations such as “CR” in route numbers and letters such as “N” in street names. (#552) +* A tone is played when automatically switching to a faster route in the background. (#541) +* Polly now pronounces Italian instructions using an Italian voice. (#542) +* Fixed an issue preventing the SDK from falling back to AVFoundation when Polly is unavailable. (#544) +* Improved the wording of various instructions in Swedish. (Project-OSRM/osrm-text-instructions#138) +* The Spanish localization consistently uses _usted_ form. (Project-OSRM/osrm-text-instructions#137) + +### Core Navigation + +* A new `NavigationRouteOptions` class makes it easier to request a route optimized for turn-by-turn navigation. (#531) +* A trip can now consist of multiple legs. (#270) +* Added `SpokenInstructionFormatter` and `VisualInstructionFormatter` classes for turning `RouteStep`s into strings appropriate for speech synthesis and display, respectively. (#456) +* When the user is moving slowly, `RouteController` snaps the location and course to the route line more aggressively. (#540) +* `RouteController` more aggressively snaps the user’s location to the route line at greater distances than before. (#551) +* Added `NavigationLocationManager.automaticallyUpdatesDesiredAccuracy` to control whether the location manager’s desired accuracy changes based on the battery state. (#504) + +## v0.6.1 (August 14, 2017) + +* Pinned all dependencies to prevent downstream breaking changes from effecting this library. https://github.com/mapbox/mapbox-navigation-ios/commit/d5c7204b0c9f03564b634da5be135ae35930804c +* Improved the initial camera view when entering navigation. https://github.com/mapbox/mapbox-navigation-ios/pull/482 +* Adds support for iPads in the example app. https://github.com/mapbox/mapbox-navigation-ios/pull/477 +* Does a better job at unpacking Polly requests to prevent the UI from locking up. https://github.com/mapbox/mapbox-navigation-ios/pull/462 +* Inaccurate locations are now filtered out. https://github.com/mapbox/mapbox-navigation-ios/pull/441 +* Lanes are now only showed for `.high` and `.medium` alerts. https://github.com/mapbox/mapbox-navigation-ios/pull/444 +* The reroute sound is not played when muted. https://github.com/mapbox/mapbox-navigation-ios/pull/450 +* Adds a new `StatusView` for displaying reroute and location accuracy information. https://github.com/mapbox/mapbox-navigation-ios/commit/b942844c52c026342b6237186715468091c53c9a +* AlertLevel distances no longer incorporate user speed for knowing when to give an announcement. https://github.com/mapbox/mapbox-navigation-ios/pull/448 + +## v0.6.0 (July 28, 2017) + +### Packaging + +* By default, NavigationMapView displays the Navigation Guidance Day v2 style. A Navigation Preview Day v2 style (`mapbox://styles/mapbox/navigation-preview-day-v2`) is also available for applications that implement a preview map. (#387) +* By default, NavigationMapView now indicates the level of traffic congestion along each segment of the route line. (#359) +* Added Italian and Traditional Chinese localizations. [Help translate the SDK into your language!](https://www.transifex.com/mapbox/mapbox-navigation-ios/) (#413, #438) + +### User interface + +* A 🐞 button on the map allows the user to submit feedback about the current route. (#400) +* The turn banner and bottom bar display fractional mileages as decimal numbers instead of vulgar fractions. 🙊🙉 (#383) +* If a step leads to a freeway or freeway ramp, the turn banner generally displays a [control city](https://en.wikipedia.org/wiki/Control_city) or a textual representation of the route number (alongside the existing shield) instead of the freeway name. (#410, #417) +* As the user arrives at a waypoint, the turn banner displays the waypoint’s name instead of whitespace. (#419) +* The route line is now wider by default, to accommodate traffic congestion coloring. (#390) +* Moved the `snapsUserLocationAnnotationToRoute` property from RouteController to NavigationViewController. (#408) +* The road name label at the bottom of the map continues to display the current road name after the user ventures away from the route. (#408) +* If the upcoming maneuver travels along a [bannered route](https://en.wikipedia.org/wiki/Special_route), the parent route shield is no longer displayed in the turn banner. (#431) +* Fixed an issue causing the Mapbox logo to peek out from under the Recenter button. (#424) + +### Voice guidance + +* Suppressed the voice announcement upon rerouting if the first step of the new route is sufficiently long. (#395) +* The rerouting audio cue now unducks other applications’ audio afterwards. (#394) +* If a step leads to a freeway or freeway ramp, voice announcements for the step generally omit the name in favor of the route number. (#404, #412) +* Fixed an issue causing Amazon Polly to read parentheses aloud. (#418) + +### Navigation + +* Various methods of `NavigationMapViewDelegate` have more descriptive names in Objective-C. (#408) +* Fixed an issue causing `NavigationViewControllerDelegate.navigationViewController(_:didArriveAt:)` to be called twice in a row. (#414) +* Fixed a memory leak. (#399) + +### Core Navigation + +* Added a `RouteController.location` property that represents the user’s location snapped to the route line. (#408) +* Added a `RouteController.recordFeedback(type:description:)` method for sending user feedback to Mapbox servers. (#304) +* Fixed excessive rerouting while the user is located away from the route, such as in a parking lot. (#386) +* Fixed an issue where RouteController sometimes got stuck on slight turn maneuvers. (#378) +* When rerouting, Core Navigation connects to the same API endpoint with the same access token that was used to obtain the original route. (#405) +* The `ReplayLocationManager.location` and `SimulatedLocationManager.location` properties now return simulated locations instead of the device’s true location as reported by Core Location. (#411) +* You can enable the `RouteController.checkForFasterRouteInBackground` property to have Core Navigation periodically check for a faster route in the background. (#346) +* Fixed an issue preventing the `RouteControllerAlertLevelDidChange` notification from posting when transitioning from a high alert level on one step to a high alert level on another step. (#425) +* Improved the accuracy of location updates while the device is plugged in. (#432) +* Added anonymized metrics collection around significant events such as rerouting. This data will be used to improve the quality of Mapbox’s products, including the underlying OpenStreetMap road data, the Mapbox Directions API, and Core Navigation. (#304) + +## v0.5.0 (July 13, 2017) + +### Packaging + +* The map now uses a style specifically designed for turn-by-turn navigation. (#263) +* Added French, Hungarian, Lithuanian, Persian, and Spanish localizations. [Help translate the SDK into your language!](https://www.transifex.com/mapbox/mapbox-navigation-ios/) (#351) +* Upgraded to [OSRM Text Instructions v0.2.0](https://github.com/Project-OSRM/osrm-text-instructions.swift/releases/tag/v0.2.0) with localization improvements and support for upcoming exit numbers provided by the Directions API. (#348) +* Corrected the frameworks’ bundle identifiers. (#281) + +### User interface + +* The turn banner now indicates when the SDK is busy fetching a new route. (#269) +* More interface elements are now styleable. The `Style.fontFamily` property makes it easy to set the entire interface’s font face. (#330) +* The interface now supports Dynamic Type. (#330) +* Fixed an issue preventing the turn banner from displaying the distance to some freeway exits. (#262) +* Fixed an issue in which swiping the turn banner to the right caused NavigationViewController to navigate to the wrong step. (#266) +* Fixed a crash presenting NavigationViewController via a storyboard segue. (#314) +* Fixed an issue causing black lines to appear over all roads during turn-by-turn navigation. (#339) +* When `NavigationViewController.route` is set to a new value, the UI updates to reflect the new route. (#302) +* Widened the route line for improved visibility. (#358) +* Fixed an issue causing maneuver arrows along the route line to appear malformed. (#284) +* Maneuver arrows no longer appear along the route line when the map is zoomed out. (#295) +* The turn banner more reliably displays a route shield for applicable freeway on- and off-ramps. (#353) +* Fixed an issue causing the turn banner to show a shield for the wrong step after swiping between steps. (#290) +* Fixed an issue causing NavigationViewController and voice alerts to stop updating after a modal view controller is pushed atop NavigationViewController. (#306) +* The map displays attribution during turn-by-turn navigation. (#288) +* Added a `NavigationMapViewControllerDelegate.navigationMapView(_:imageFor:)` method for customizing the destination annotation. (#268) +* Fixed an issue where the wrong source was passed into `MGLMapViewDelegate.navigationMapView(_:routeCasingStyleLayerWithIdentifier:source:)`. (#265, #267) +* The turn banner abbreviates road names when using the Catalan, Lithuanian, Spanish, Swedish, or Vietnamese localization. (#254, #376) + +### Voice guidance + +* To use Amazon Polly for voice guidance, set the `NavigationViewController.voiceController` property. (#313) +* Fixed an issue that disabled Polly-powered voice guidance when the application went to the background. A message is printed to the console if the `audio` background mode is missing from the application’s Info.plist file. (#356) +* Fixed a crash that could occur when the device is muted and an instruction would normally be read aloud. (#275) +* By default, a short audio cue now plays when the user diverges from the route, requiring a new route to be fetched. (#269) +* Renamed `RouteStepFormatter.string(for:markUpWithSSML:)` to `RouteStepFormatter.string(for:legIndex:numberOfLegs:markUpWithSSML:)`. (#348) + +### Navigation + +* Fixed a crash after a simulated route causes the SDK to fetch a new route. (#344) +* Fixed an issue that stopped location updates after the application returned to the foreground from the background. (#343) +* Fixed excessive calls to `NavigationViewControllerDelegate.navigationViewController(_:didArriveAt:)`. (#347) +* Fixed crashes that occurred during turn-by-turn navigation. (#271, #336) +* Fixed a memory leak that occurs when `NavigationViewController.navigationDelegate` is set. (#316) + +### Core Navigation + +* RouteController now requests Always Location Services permissions if `NSLocationAlwaysAndWhenInUseUsageDescription` is set in Info.plist. (#342) +* RouteController now continues to track the user’s location after arriving at the destination. (#333) +* Fixed an issue causing RouteController to alternate rapidly between steps. (#258) +* The SimulatedLocationManager class now bridges to Objective-C. (#314) +* The DistanceFormatter class has been moved to Core Navigation. (#309) + +## v0.4.0 (June 1, 2017) + +### Packaging + +* Documentation is now available in Quick Help and code completion for most classes and methods. (#250) +* Added Catalan, Swedish, and Vietnamese localizations. (#203) + +### User interface + +* A new class, `Style`, makes it easy to customize the SDK’s appearance and vary it by size class. (#162) +* Fixed an issue causing the road name in the turn banner to be truncated. The road name may be abbreviated to fit the allotted space. (#215) +* Enlarged the distance in the turn banner. (#217) +* A button at the top-left corner of the map view displays a live overview of the route. (#106) +* A small label at the bottom of the map view displays the name of the street along which the user is currently traveling. (#155) +* `NavigationViewController` automatically adopts the tint color of the view controller that presents it. (#176) +* The user can no longer swipe the turn banner left of the current step to “preview” already completed steps. (#223) +* The U-turn icon in the turn banner is no longer flipped horizontally in countries that drive on the right. (#243) +* Distances are now measured in imperial units when the user’s language is set to British English. (#246) + +### Voice guidance + +* Fixed an issue causing voice instructions to be delivered by an Australian English voice regardless of the user’s region. (#187, #245) +* Fixed an issue causing a “continue” instruction to be repeated multiple times along the step. (#238) +* A final voice instruction is no longer delivered when merging onto a highway. (#239) + +### Core Navigation + +* `RouteController` is now responsible for the basic aspects of rerouting, including fetching the new route. A new `RouteControllerDelegate` protocol (mirrored by `NavigationViewControllerDelegate`) has methods for preventing or reacting to a rerouting attempt. (#251) +* A notification is posted as soon as Core Navigation successfully receives a new route or fails to receive a new route. (#251) +* When rerouting, any remaining intermediate waypoints are preserved in the new route. (#251) +* Improved the timing and accuracy of rerouting attempts. (#202, #228) +* Fixed an issue preventing the route progress (and thus the progress bar) from completing as the user arrives at the destination. (#157) +* Fixed an issue that affected Core Navigation’s accuracy near maneuvers. (#185) +* A simulated route performs maneuvers more realistically than before. (#226) +* Fixed an issue preventing a simulated route from reaching the end of the route. (#244) +* Resolved some compiler warnings related to the location manager. (#190) + +## v0.3.0 (April 25, 2017) + +* Renamed `RouteViewController` to `NavigationViewController`. (#133) +* Replaced the `NavigationUI.routeViewController(for:)` method with the `NavigationViewController(for:)` initializer. (#133) +* Fixed compatibility with MapboxDirections.swift v0.9.0. This library now depends on MapboxDirections.swift v0.9.x. (#139) +* Fixed an issue causing the SDK to ignore certain routing options when rerouting the user. (#139) +* Added a `NavigationViewController.simulatesLocationUpdates` property that causes the SDK to simulate location updates along a route. (#111) +* Added a `NavigationViewControllerDelegate.navigationViewController(_:didArriveAt:)` method that gets called when user arrives at the destination. (#158) +* Added methods to NavigationViewControllerDelegate to customize the appearance and shape of the route line. (#135) +* Fixed an issue preventing the volume setting from working when using the built-in system speech synthesizer. (#160) +* Added support for Russian and Spanish voices when using Amazon Polly for voice alerts. (#153) + +## v0.2.1 (April 15, 2017) + +* This library now requires MapboxDirections.swift v0.8.x as opposed to v0.9.0, which is incompatible. ([#150](https://github.com/mapbox/mapbox-navigation-ios/pull/150)) + +## v0.2.0 (April 14, 2017) + +* Renamed MapboxNavigation and MapboxNavigationUI to MapboxCoreNavigation and MapboxNavigation, respectively. MapboxNavigation provides the complete turn-by-turn navigation experience, including UI and voice announcements, while MapboxCoreNavigation provides the raw utilities for building your own UI. ([#129](https://github.com/mapbox/mapbox-navigation-ios/pull/129)) +* Exposed methods on NavigationMapView that you can override to customize the route line’s appearance on the map. ([#116](https://github.com/mapbox/mapbox-navigation-ios/pull/116)) +* Removed an unused dependency on MapboxGeocoder.swift. ([#112](https://github.com/mapbox/mapbox-navigation-ios/pull/112)) +* Fixed memory leaks. ([#120](https://github.com/mapbox/mapbox-navigation-ios/pull/120)) + +## v0.1.0 (March 30, 2017) + +* Adds MapboxNavigationUI for a drop in navigation experience +* Allows for Integration with [AWS Polly](https://aws.amazon.com/polly/) for improved voice announcements +* Adds optional user snapping to route line. This option also snaps the users course +* Fixes an issue where announcements with`Continue`would not announce the way names correctly +* Updates to Swift v3.1 +* Fixed an issue where the route line was not inserted below labels after re-routing. + +## v0.0.4 (January 24, 2017) + +- Fixed an issue where a `finalHeading` just below `360` and a user heading just above `0`, would not be less than `RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion` ([#25](https://github.com/mapbox/MapboxNavigation.swift/pull/25)) +- Better specified the swift version ([#26](https://github.com/mapbox/MapboxNavigation.swift/pull/26)) + +## v0.0.3 (January 19, 2017) + +- Fixes CocoaPod installation error + +## v0.0.2 (January 19, 2017) + +Initial public release \ No newline at end of file diff --git a/Examples/AdditionalExamples/AppDelegate.swift b/Examples/AdditionalExamples/AppDelegate.swift new file mode 100644 index 00000000000..03c8c6071b7 --- /dev/null +++ b/Examples/AdditionalExamples/AppDelegate.swift @@ -0,0 +1,26 @@ + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } +} + diff --git a/Examples/AdditionalExamples/Assets.xcassets/AccentColor.colorset/Contents.json b/Examples/AdditionalExamples/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000000..eb878970081 --- /dev/null +++ b/Examples/AdditionalExamples/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/AdditionalExamples/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/AdditionalExamples/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..13613e3ee1a --- /dev/null +++ b/Examples/AdditionalExamples/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/AdditionalExamples/Assets.xcassets/Contents.json b/Examples/AdditionalExamples/Assets.xcassets/Contents.json new file mode 100644 index 00000000000..73c00596a7f --- /dev/null +++ b/Examples/AdditionalExamples/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/AdditionalExamples/Assets.xcassets/turnleft.dataset/Contents.json b/Examples/AdditionalExamples/Assets.xcassets/turnleft.dataset/Contents.json new file mode 100644 index 00000000000..50e80bb476d --- /dev/null +++ b/Examples/AdditionalExamples/Assets.xcassets/turnleft.dataset/Contents.json @@ -0,0 +1,12 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "data" : [ + { + "idiom" : "universal", + "filename" : "turnleft.mp3" + } + ] +} \ No newline at end of file diff --git a/Examples/AdditionalExamples/Assets.xcassets/turnleft.dataset/turnleft.mp3 b/Examples/AdditionalExamples/Assets.xcassets/turnleft.dataset/turnleft.mp3 new file mode 100644 index 00000000000..4ba83190ddd Binary files /dev/null and b/Examples/AdditionalExamples/Assets.xcassets/turnleft.dataset/turnleft.mp3 differ diff --git a/Examples/AdditionalExamples/Assets.xcassets/turnright.dataset/Contents.json b/Examples/AdditionalExamples/Assets.xcassets/turnright.dataset/Contents.json new file mode 100644 index 00000000000..3036f5cbdbe --- /dev/null +++ b/Examples/AdditionalExamples/Assets.xcassets/turnright.dataset/Contents.json @@ -0,0 +1,12 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "data" : [ + { + "idiom" : "universal", + "filename" : "turnright.mp3" + } + ] +} \ No newline at end of file diff --git a/Examples/AdditionalExamples/Assets.xcassets/turnright.dataset/turnright.mp3 b/Examples/AdditionalExamples/Assets.xcassets/turnright.dataset/turnright.mp3 new file mode 100644 index 00000000000..d5d313c2188 Binary files /dev/null and b/Examples/AdditionalExamples/Assets.xcassets/turnright.dataset/turnright.mp3 differ diff --git a/Examples/AdditionalExamples/Base.lproj/LaunchScreen.storyboard b/Examples/AdditionalExamples/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000000..865e9329f37 --- /dev/null +++ b/Examples/AdditionalExamples/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/AdditionalExamples/Base.lproj/Main.storyboard b/Examples/AdditionalExamples/Base.lproj/Main.storyboard new file mode 100644 index 00000000000..ed44f59ec11 --- /dev/null +++ b/Examples/AdditionalExamples/Base.lproj/Main.storyboard @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/AdditionalExamples/Constants.swift b/Examples/AdditionalExamples/Constants.swift new file mode 100644 index 00000000000..a2591fac3d3 --- /dev/null +++ b/Examples/AdditionalExamples/Constants.swift @@ -0,0 +1,82 @@ +import Foundation +import UIKit + +typealias NamedController = ( + name: String, + description: String, + controller: UIViewController.Type, + storyboard: UIStoryboard?, // Is the example containined in a storyboard? If so, we assume the Initial View Controller of the storyboard. + pushExampleToViewController: Bool // If the example does not go directly into the example,(i.e. another map is shown) set this value to true +) + +let listOfExamples: [NamedController] = [ + ( + name: "Advanced Implementation", + description: """ + Demonstrates how to display a custom map style and how to apply stylized components in the UI. + This example also allows the user to select an alternate route. Long press on the map to begin. + NavigationViewController reuses a NavigationMapView instance, allowing for a seamless transition + between between a route preview and active turn-by-turn navigation. + Note: The Directions API will not always return alternative routes. + """, + controller: AdvancedViewController.self, + storyboard: nil, + pushExampleToViewController: true + ), + ( + name: "Basic", + description: "A basic hello world example showing how to create a navigation experience using the fewest lines of code possible.", + controller: BasicViewController.self, + storyboard: nil, + pushExampleToViewController: false + ), + ( + name: "Embedded View Controller", + description: "Demonstrates how to embed a NavigationViewController within a parent view controller.", + controller: EmbeddedExampleViewController.self, + storyboard: UIStoryboard(name: "EmbeddedExamples", bundle: nil), + pushExampleToViewController: true + ), + ( + name: "Styled UI Elements", + description: "Demonstrates how to customize various UI elements and also change the map style.", + controller: CustomStyleUIElements.self, + storyboard: nil, + pushExampleToViewController: false + ), + ( + name: "Directions API beta query parameters", + description: "Demonstrates how to subclass NavigationRouteOptions to take advantage of the beta query parameters available from the Directions API.", + controller: BetaQueryViewController.self, + storyboard: nil, + pushExampleToViewController: true + ), + ( + name: "Custom Voice Controller", + description: "Add custom audio recordings for your instructions.", + controller: CustomVoiceControllerUI.self, + storyboard: nil, + pushExampleToViewController: false + ), + ( + name: "Custom Top & Bottom Bars", + description: "Use a custom UI for top and bottom bars during navigation.", + controller: CustomBarsViewController.self, + storyboard: nil, + pushExampleToViewController: false + ), + ( + name: "Offline Regions", + description: "Demonstrates how to create a custom TileStore and handle offline regions.", + controller: OfflineRegionsViewController.self, + storyboard: nil, + pushExampleToViewController: true + ), + ( + name: "History Recording", + description: "Demonstrates how to create history files in Free drive and Active turn-by-turn navigation.", + controller: HistoryRecordingViewController.self, + storyboard: nil, + pushExampleToViewController: true + ) +] diff --git a/Examples/AdditionalExamples/ExampleContainerViewController.swift b/Examples/AdditionalExamples/ExampleContainerViewController.swift new file mode 100644 index 00000000000..30a98be001f --- /dev/null +++ b/Examples/AdditionalExamples/ExampleContainerViewController.swift @@ -0,0 +1,66 @@ +import Foundation +import UIKit + +var simulationIsEnabled = true + +class ExampleContainerViewController: UITableViewController { + + @IBOutlet weak var beginNavigation: UIButton! + @IBOutlet weak var simulateNavigation: UISwitch! + + var exampleClass: UIViewController.Type? + var exampleName: String? + var exampleDescription: String? + var exampleStoryboard: UIStoryboard? + var hasEnteredExample = false + var pushExampleToViewController = false + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.title = exampleName + + if exampleClass == nil { + beginNavigation.setTitle("Example Not Found", for: .normal) + beginNavigation.isEnabled = false + simulateNavigation.isEnabled = false + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + if hasEnteredExample { + view.subviews.last?.removeFromSuperview() + children.last?.removeFromParent() + hasEnteredExample = false + } + } + + @IBAction func didTapBeginNavigation(_ sender: Any) { + let controller = instantiate(example: exampleClass!, from: exampleStoryboard) + embed(controller: controller, shouldPush: pushExampleToViewController) + } + + private func instantiate(example: T.Type, from storyboard: UIStoryboard? = nil) -> T { + return storyboard?.instantiateInitialViewController() as? T ?? example.init() + } + + private func embed(controller: UIViewController, shouldPush: Bool) { + addChild(controller) + view.addSubview(controller.view) + + controller.didMove(toParent: self) + if shouldPush { + navigationController?.pushViewController(controller, animated: true) + } + hasEnteredExample = true + } + + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + guard let exampleDescription = exampleDescription else { return nil } + return section == tableView.numberOfSections - 1 ? exampleDescription : nil + } + + @IBAction func didToggleSimulateNavigation(_ sender: Any) { + simulationIsEnabled = simulateNavigation.isOn + } +} diff --git a/Examples/AdditionalExamples/ExampleTableViewController.swift b/Examples/AdditionalExamples/ExampleTableViewController.swift new file mode 100644 index 00000000000..5056fa2e7b5 --- /dev/null +++ b/Examples/AdditionalExamples/ExampleTableViewController.swift @@ -0,0 +1,42 @@ + +import Foundation +import UIKit + +class ExampleTableViewController: UITableViewController { + override func viewDidLoad() { + self.clearsSelectionOnViewWillAppear = false + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return listOfExamples.count + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) + cell.textLabel?.text = listOfExamples[indexPath.row].name + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + performSegue(withIdentifier: "TableToExampleSegue", sender: self) + tableView.deselectRow(at: indexPath, animated: true) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + guard segue.identifier == "TableToExampleSegue", + let controller = segue.destination as? ExampleContainerViewController, + let selectedCell = self.tableView.indexPathForSelectedRow else { return } + + let example = listOfExamples[selectedCell[1]] + + controller.exampleClass = example.controller + controller.exampleName = example.name + controller.exampleDescription = example.description + controller.exampleStoryboard = example.storyboard + controller.pushExampleToViewController = example.pushExampleToViewController + } +} diff --git a/Examples/AdditionalExamples/Examples/Advanced.swift b/Examples/AdditionalExamples/Examples/Advanced.swift new file mode 100644 index 00000000000..12308c459e8 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Advanced.swift @@ -0,0 +1,214 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/advanced + */ + +import UIKit +import MapboxNavigationCore +import MapboxNavigationUIKit +import MapboxMaps +import MapboxDirections + +class AdvancedViewController: UIViewController, NavigationMapViewDelegate, NavigationViewControllerDelegate { + + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + // For demonstration purposes, simulate locations if the Simulate Navigation option is on. + locationSource: simulationIsEnabled ? .simulation( + initialLocation: nil + ) : .live + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + var navigationMapView: NavigationMapView! { + didSet { + if oldValue != nil { + oldValue.removeFromSuperview() + } + + navigationMapView.translatesAutoresizingMaskIntoConstraints = false + + view.insertSubview(navigationMapView, at: 0) + + NSLayoutConstraint.activate([ + navigationMapView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationMapView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + navigationMapView.topAnchor.constraint(equalTo: view.topAnchor), + navigationMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } + } + + var navigationRoutes: NavigationRoutes? { + didSet { + showCurrentRoute() + } + } + + func showCurrentRoute() { + guard let navigationRoutes = navigationRoutes else { + navigationMapView.removeRoutes() + return + } + navigationMapView.showcase(navigationRoutes) + } + + var startButton: UIButton! + + // MARK: - UIViewController lifecycle methods + + override func viewDidLoad() { + super.viewDidLoad() + + navigationMapView = .init( + location: mapboxNavigation.navigation().locationMatching.map(\.location).eraseToAnyPublisher(), + routeProgress: mapboxNavigation.navigation().routeProgress.map(\.?.routeProgress).eraseToAnyPublisher(), + predictiveCacheManager: mapboxNavigationProvider.predictiveCacheManager + ) + navigationMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + navigationMapView.delegate = self + navigationMapView.mapView.mapboxMap.loadStyle(StyleURI.dark) + navigationMapView.puckType = .puck2D(.navigationDefault) + + view.addSubview(navigationMapView) + + startButton = UIButton() + startButton.setTitle("Start Navigation", for: .normal) + startButton.translatesAutoresizingMaskIntoConstraints = false + startButton.backgroundColor = .blue + startButton.contentEdgeInsets = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20) + startButton.addTarget(self, action: #selector(tappedButton(sender:)), for: .touchUpInside) + startButton.isHidden = true + view.addSubview(startButton) + + startButton.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true + startButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true + view.setNeedsLayout() + + mapboxNavigation.tripSession().startFreeDrive() + } + + // Override layout lifecycle callback to be able to style the start button. + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + startButton.layer.cornerRadius = startButton.bounds.midY + startButton.clipsToBounds = true + startButton.setNeedsDisplay() + } + + @objc func tappedButton(sender: UIButton) { + guard let navigationRoutes = navigationRoutes else { return } + + let navigationOptions = NavigationOptions( + mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager(), + styles: [NightStyle()], + predictiveCacheManager: mapboxNavigationProvider.predictiveCacheManager, + // Replace default `NavigationMapView` instance with instance that is used in preview mode. + navigationMapView: navigationMapView + ) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.delegate = self + navigationViewController.modalPresentationStyle = .fullScreen + + startButton.isHidden = true + + // Hide top and bottom container views before animating their presentation. + navigationViewController.navigationView.bottomBannerContainerView.hide(animated: false) + navigationViewController.navigationView.topBannerContainerView.hide(animated: false) + + // Hide `WayNameView`, `FloatingStackView` and `SpeedLimitView` to smoothly present them. + navigationViewController.navigationView.wayNameView.alpha = 0.0 + navigationViewController.navigationView.floatingStackView.alpha = 0.0 + navigationViewController.navigationView.speedLimitView.alpha = 0.0 + + present(navigationViewController, animated: false) { + // Animate top and bottom banner views presentation. + let duration = 1.0 + navigationViewController.navigationView.bottomBannerContainerView.show(duration: duration, + animations: { + navigationViewController.navigationView.wayNameView.alpha = 1.0 + navigationViewController.navigationView.floatingStackView.alpha = 1.0 + navigationViewController.navigationView.speedLimitView.alpha = 1.0 + }) + navigationViewController.navigationView.topBannerContainerView.show(duration: duration) + } + } + + func requestRoute(destination: CLLocationCoordinate2D) { + guard let userLocation = navigationMapView.mapView.location.latestLocation else { return } + + let location = CLLocation(latitude: userLocation.coordinate.latitude, + longitude: userLocation.coordinate.longitude) + + let userWaypoint = Waypoint(location: location, + name: "user") + + let destinationWaypoint = Waypoint(coordinate: destination) + + let navigationRouteOptions = NavigationRouteOptions(waypoints: [userWaypoint, destinationWaypoint]) + + let task = mapboxNavigation.routingProvider().calculateRoutes(options: navigationRouteOptions) + + Task { [weak self] in + switch await task.result { + case .failure(let error): + print(error.localizedDescription) + case .success(let response): + guard let self = self else { return } + + self.navigationRoutes = response + self.startButton?.isHidden = false + } + } + } + + func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { + let duration = 1.0 + navigationViewController.navigationView.topBannerContainerView.hide(duration: duration) + navigationViewController.navigationView.bottomBannerContainerView.hide(duration: duration, + animations: { + navigationViewController.navigationView.wayNameView.alpha = 0.0 + navigationViewController.navigationView.floatingStackView.alpha = 0.0 + navigationViewController.navigationView.speedLimitView.alpha = 0.0 + }, + completion: { [weak self] _ in + navigationViewController.dismiss(animated: false) { + guard let self = self else { return } + + // Show previously hidden button that allows to start active navigation. + self.startButton.isHidden = false + + // Since `NavigationViewController` assigns `NavigationMapView`'s delegate to itself, + // delegate should be re-assigned back to `NavigationMapView` that is used in preview mode. + self.navigationMapView.delegate = self + + // Replace `NavigationMapView` instance with instance that was used in active navigation. + self.navigationMapView = navigationViewController.navigationMapView + + // Showcase originally requested routes. + self.showCurrentRoute() + } + }) + } + + // MARK: NavigationMapViewDelegate implementation + + func navigationMapView(_ navigationMapView: NavigationMapView, userDidLongTap mapPoint: MapPoint) { + requestRoute(destination: mapPoint.coordinate) + } + + // Delegate method called when the user selects a route + func navigationMapView(_ navigationMapView: NavigationMapView, didSelect alternativeRoute: AlternativeRoute) { + Task { + guard let selectedRoutes = await self.navigationRoutes?.selecting(alternativeRoute: alternativeRoute) else { return } + self.navigationRoutes = selectedRoutes + } + } +} diff --git a/Examples/AdditionalExamples/Examples/Basic.swift b/Examples/AdditionalExamples/Examples/Basic.swift new file mode 100644 index 00000000000..7bb853ce342 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Basic.swift @@ -0,0 +1,56 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/basic + */ + +import Foundation +import UIKit +import MapboxNavigationCore +import MapboxNavigationUIKit +import CoreLocation + +class BasicViewController: UIViewController { + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: .init( + latitude: 37.77440680146262, + longitude: -122.43539772352648 + ) + ) : .live + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + override func viewDidLoad() { + super.viewDidLoad() + + let origin = CLLocationCoordinate2DMake(37.77440680146262, -122.43539772352648) + let destination = CLLocationCoordinate2DMake(37.76556957793795, -122.42409811526268) + let options = NavigationRouteOptions(coordinates: [origin, destination]) + + let request = mapboxNavigation.routingProvider().calculateRoutes(options: options) + + Task { + switch await request.result { + case .failure(let error): + print(error.localizedDescription) + case .success(let navigationRoutes): + + // For demonstration purposes, simulate locations if the Simulate Navigation option is on. + let navigationOptions = NavigationOptions(mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager()) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.modalPresentationStyle = .fullScreen + // Render part of the route that has been traversed with full transparency, to give the illusion of a disappearing route. + navigationViewController.routeLineTracksTraversal = true + + present(navigationViewController, animated: true, completion: nil) + } + } + } +} diff --git a/Examples/AdditionalExamples/Examples/Beta-Query-Parameters.swift b/Examples/AdditionalExamples/Examples/Beta-Query-Parameters.swift new file mode 100644 index 00000000000..8977e712256 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Beta-Query-Parameters.swift @@ -0,0 +1,205 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples + */ + +import UIKit +import MapboxNavigationCore +import MapboxNavigationUIKit +import MapboxDirections +import MapboxMaps + +class BetaQueryViewController: UIViewController, NavigationMapViewDelegate, NavigationViewControllerDelegate { + + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: nil + ) : .live + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + var navigationMapView: NavigationMapView! + + var navigationRoutes: NavigationRoutes? { + didSet { + guard let navigationRoutes = navigationRoutes else { + navigationMapView.removeRoutes() + return + } + navigationMapView.showcase(navigationRoutes) + } + } + + var startButton: UIButton! + var datePicker: UIDatePicker! + var dateTextField: UITextField! + var departureTime: Date! + + // MARK: - UIViewController lifecycle methods + + override func viewDidLoad() { + super.viewDidLoad() + + navigationMapView = .init( + location: mapboxNavigation.navigation().locationMatching.map(\.location).eraseToAnyPublisher(), + routeProgress: mapboxNavigation.navigation().routeProgress.map(\.?.routeProgress).eraseToAnyPublisher(), + predictiveCacheManager: mapboxNavigationProvider.predictiveCacheManager + ) + navigationMapView.translatesAutoresizingMaskIntoConstraints = false + navigationMapView.delegate = self + + view.addSubview(navigationMapView) + + NSLayoutConstraint.activate([ + navigationMapView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationMapView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + navigationMapView.topAnchor.constraint(equalTo: view.topAnchor), + navigationMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + + startButton = UIButton() + startButton.setTitle("Start Navigation", for: .normal) + startButton.translatesAutoresizingMaskIntoConstraints = false + startButton.backgroundColor = .blue + startButton.contentEdgeInsets = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20) + startButton.addTarget(self, action: #selector(tappedStartButton(sender:)), for: .touchUpInside) + startButton.isHidden = true + view.addSubview(startButton) + + startButton.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true + startButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true + view.setNeedsLayout() + + setupDateProperties() + + mapboxNavigation.tripSession().startFreeDrive() + } + + // Override layout lifecycle callback to be able to style the start button. + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + startButton.layer.cornerRadius = startButton.bounds.midY + startButton.clipsToBounds = true + startButton.setNeedsDisplay() + } + + func setupDateProperties() { + dateTextField = UITextField(frame: CGRect(x: 75, y: 100, width: 200, height: 35)) + dateTextField.placeholder = "Select departure time" + dateTextField.backgroundColor = UIColor.white + dateTextField.borderStyle = .roundedRect + dateTextField.center.x = view.center.x + dateTextField.isHidden = false + showDatePicker() + view.addSubview(dateTextField) + } + + func showDatePicker() { + datePicker = UIDatePicker() + datePicker.datePickerMode = .time + datePicker.preferredDatePickerStyle = .wheels + datePicker.minimumDate = Date() + + let toolbar = UIToolbar() + toolbar.sizeToFit() + + let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(doneButtonPressed)) + toolbar.setItems([doneButton], animated: true) + + dateTextField?.inputAccessoryView = toolbar + dateTextField?.inputView = datePicker + } + + @objc func doneButtonPressed() { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm" // format date correctly + dateTextField.text = dateFormatter.string(from: datePicker.date) + self.view.endEditing(true) + } + + @objc func tappedStartButton(sender: UIButton) { + guard let navigationRoutes else { return } + + let navigationOptions = NavigationOptions( + mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager() + ) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.delegate = self + + present(navigationViewController, animated: true, completion: nil) + } + + func requestRoute(destination: CLLocationCoordinate2D) { + guard let userLocation = navigationMapView.mapView.location.latestLocation else { return } + + let location = CLLocation(latitude: userLocation.coordinate.latitude, + longitude: userLocation.coordinate.longitude) + + let userWaypoint = Waypoint(location: location, + name: "user") + + let destinationWaypoint = Waypoint(coordinate: destination) + let navigationRouteOptions = MopedRouteOptions(waypoints: [userWaypoint, destinationWaypoint], departTime: dateTextField.text!) + + let request = mapboxNavigation.routingProvider().calculateRoutes(options: navigationRouteOptions) + + Task { + switch await request.result { + case .failure(let error): + print(error.localizedDescription) + case .success(let response): + self.navigationRoutes = response + self.startButton?.isHidden = false + self.dateTextField?.isHidden = true + } + } + } + + func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { + dismiss(animated: true, completion: nil) + } + + // MARK: NavigationMapViewDelegate implementation + + func navigationMapView(_ navigationMapView: NavigationMapView, userDidLongTap mapPoint: MapPoint) { + guard dateTextField?.text != nil else { return } + requestRoute(destination: mapPoint.coordinate) + } +} + +class MopedRouteOptions: NavigationRouteOptions { + var departureTime: String! + + // add departureTime to URLQueryItems + override var urlQueryItems: [URLQueryItem] { + var items = super.urlQueryItems + items.append(URLQueryItem(name: "depart_at", value: departureTime)) + return items + } + + // create initializer to take in the departure time + public init(waypoints: [Waypoint], departTime: String) { + departureTime = departTime + super.init(waypoints: waypoints) + } + + required init(from decoder: Decoder) throws { + fatalError("init(from:) has not been implemented") + } + + required init(waypoints: [Waypoint], profileIdentifier: ProfileIdentifier? = .automobileAvoidingTraffic) { + fatalError("init(waypoints:profileIdentifier:) has not been implemented") + } + + required init(waypoints: [Waypoint], profileIdentifier: ProfileIdentifier? = .automobileAvoidingTraffic, queryItems: [URLQueryItem]? = nil) { + fatalError("init(waypoints:profileIdentifier:queryItems:) has not been implemented") + } +} diff --git a/Examples/AdditionalExamples/Examples/Custom-Voice-Controller.swift b/Examples/AdditionalExamples/Examples/Custom-Voice-Controller.swift new file mode 100644 index 00000000000..0ced8d9d5e7 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Custom-Voice-Controller.swift @@ -0,0 +1,202 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/custom-voice-controller/ + */ + +import Foundation +import UIKit +import MapboxNavigationCore +import MapboxNavigationUIKit +import MapboxDirections +import AVFoundation +import CoreLocation +import Combine + +class CustomVoiceControllerUI: UIViewController { + let mapboxNavigationProvider: MapboxNavigationProvider = { + var coreConfig = CoreConfig( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: .init( + latitude: 37.77440680146262, + longitude: -122.43539772352648 + ) + ) : .live + ) + let provider = MapboxNavigationProvider(coreConfig: coreConfig) + coreConfig.ttsConfig = .custom( + speechSynthesizer: + // `MultiplexedSpeechSynthesizer` will provide "a backup" functionality to cover cases, which + // our custom implementation cannot handle. + MultiplexedSpeechSynthesizer( + mapboxSpeechApiConfiguration: coreConfig.credentials.speech, + skuTokenProvider: provider.skuTokenProvider.skuToken, + customSpeechSynthesizers: [CustomVoiceController()] + ) + ) + provider.apply(coreConfig: coreConfig) + return provider + }() + + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + override func viewDidLoad() { + super.viewDidLoad() + + let origin = CLLocationCoordinate2DMake(37.77440680146262, -122.43539772352648) + let destination = CLLocationCoordinate2DMake(37.76556957793795, -122.42409811526268) + let routeOptions = NavigationRouteOptions(coordinates: [origin, destination]) + + Task { + switch await mapboxNavigation.routingProvider().calculateRoutes(options: routeOptions).result { + case .failure(let error): + print(error.localizedDescription) + case .success(let navigationRoutes): + self.presentNavigationWithCustomVoiceController(navigationRoutes: navigationRoutes) + } + } + } + + func presentNavigationWithCustomVoiceController(navigationRoutes: NavigationRoutes) { + let navigationOptions = NavigationOptions(mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager()) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.modalPresentationStyle = .fullScreen + + present(navigationViewController, animated: true, completion: nil) + } +} + +class CustomVoiceController: NSObject, SpeechSynthesizing, AVAudioPlayerDelegate { + private let _voiceInstructions: PassthroughSubject = .init() + public var voiceInstructions: AnyPublisher { + _voiceInstructions.eraseToAnyPublisher() + } + + // MARK: Speech Configuration + + public var muted: Bool = false { + didSet { + if isSpeaking { + interruptSpeaking() + } + } + } + + public var volume: VolumeMode = .system { + didSet { + switch volume { + case .system: + players.forEach { + $0?.volume = 1.0 + } + case .override(let value): + players.forEach { + $0?.volume = value + } + @unknown default: + print("unknown volume value") + } + } + } + + public var locale: Locale? = Locale.autoupdatingCurrent + var isSpeaking: Bool { + players.contains { + $0?.isPlaying ?? false + } + } + var managesAudioSession: Bool = true + + func prepareIncomingSpokenInstructions(_ instructions: [MapboxNavigationCore.SpokenInstruction], locale: Locale?) { + // do nothing, we don't need to pre-load anything. + } + + func stopSpeaking() { + players.forEach { + $0?.stop() + } + } + + func interruptSpeaking() { + players.forEach { + $0?.stop() + } + } + + // You will need audio files for as many or few cases as you'd like to handle + // This example just covers left and right. All other cases will fail the Custom Voice Controller and + // force a backup Speech to kick in. + let turnLeftPlayer = try? AVAudioPlayer(data: NSDataAsset(name: "turnleft")!.data) + let turnRightPlayer = try? AVAudioPlayer(data: NSDataAsset(name: "turnright")!.data) + var players: [AVAudioPlayer?] { + [turnLeftPlayer, turnRightPlayer] + } + + var currentInstruction: SpokenInstruction? = nil + + override init() { + super.init() + + players.forEach { + $0?.delegate = self + } + } + + func speak(_ instruction: SpokenInstruction, during legProgress: RouteLegProgress, locale: Locale? = nil) { + guard let nextStep = legProgress.upcomingStep, + let player = audio(for: nextStep) else { + // When `MultiplexedSpeechSynthesizer` receives an error from one of it's Speech Synthesizers, + // it requests the next on the list + _voiceInstructions.send( + VoiceInstructionEvents.EncounteredError( + error: SpeechError.noData( + instruction: instruction, + options: .init(text: instruction.text, + locale: locale ?? self.locale ?? .current) + ) + ) + ) + return + } + _voiceInstructions.send( + VoiceInstructionEvents.WillSpeak( + instruction: instruction + ) + ) + if let currentInstruction { + interruptSpeaking() + _voiceInstructions.send( + VoiceInstructionEvents.DidInterrupt( + interruptedInstruction: currentInstruction, + interruptingInstruction: instruction) + ) + } + currentInstruction = instruction + player.play() + } + + func audio(for step: RouteStep) -> AVAudioPlayer? { + switch step.maneuverDirection { + case .left: + return turnLeftPlayer + case .right: + return turnRightPlayer + default: + return nil // this will force report that Custom Voice Controller is unable to handle this case + } + } + + // MARK: AVAudioPlayerDelegate implementation + func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { + if let currentInstruction { + _voiceInstructions.send( + VoiceInstructionEvents.DidSpeak(instruction: currentInstruction) + ) + } + currentInstruction = nil + } +} diff --git a/Examples/AdditionalExamples/Examples/CustomBars/CustomBarsViewController.swift b/Examples/AdditionalExamples/Examples/CustomBars/CustomBarsViewController.swift new file mode 100644 index 00000000000..e517642565b --- /dev/null +++ b/Examples/AdditionalExamples/Examples/CustomBars/CustomBarsViewController.swift @@ -0,0 +1,208 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/custom-banner + */ + +import Foundation +import UIKit +import MapboxNavigationCore +import MapboxNavigationUIKit +import MapboxDirections +import CoreLocation + +class CustomBarsViewController: UIViewController { + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: .init( + latitude: 37.77440680146262, + longitude: -122.43539772352648 + ) + ) : .live + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + override func viewDidLoad() { + super.viewDidLoad() + + let origin = CLLocationCoordinate2DMake(37.77440680146262, -122.43539772352648) + let destination = CLLocationCoordinate2DMake(37.76556957793795, -122.42409811526268) + let options = NavigationRouteOptions(coordinates: [origin, destination]) + + let request = mapboxNavigation.routingProvider().calculateRoutes(options: options) + + Task { + switch await request.result { + case .failure(let error): + print(error.localizedDescription) + case .success(let navigationRoutes): + // Pass your custom implementations of `topBanner` and/or `bottomBanner` to `NavigationOptions` + // If you do not specify them explicitly, `TopBannerViewController` and `BottomBannerViewController` will be used by default. + // Those are `Open`, so you can also check thier source for more examples of using standard UI controls! + let topBanner = CustomTopBarViewController() + let bottomBanner = CustomBottomBarViewController() + let navigationOptions = NavigationOptions(mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager(), + topBanner: topBanner, + bottomBanner: bottomBanner) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + + bottomBanner.navigationViewController = navigationViewController + + let parentSafeArea = navigationViewController.view.safeAreaLayoutGuide + let bannerHeight: CGFloat = 80.0 + let verticalOffset: CGFloat = 20.0 + let horizontalOffset: CGFloat = 10.0 + + // To change top and bottom banner size and position change layout constraints directly. + topBanner.view.topAnchor.constraint(equalTo: parentSafeArea.topAnchor).isActive = true + + bottomBanner.view.heightAnchor.constraint(equalToConstant: bannerHeight).isActive = true + bottomBanner.view.bottomAnchor.constraint(equalTo: parentSafeArea.bottomAnchor, constant: -verticalOffset).isActive = true + bottomBanner.view.leadingAnchor.constraint(equalTo: parentSafeArea.leadingAnchor, constant: horizontalOffset).isActive = true + bottomBanner.view.trailingAnchor.constraint(equalTo: parentSafeArea.trailingAnchor, constant: -horizontalOffset).isActive = true + + navigationViewController.modalPresentationStyle = .fullScreen + + present(navigationViewController, animated: true, completion: nil) + navigationViewController.floatingButtons = [] + navigationViewController.showsSpeedLimits = false + } + } + } +} + +// MARK: - CustomTopBarViewController + +class CustomTopBarViewController: ContainerViewController { + private lazy var instructionsBannerTopOffsetConstraint = { + return instructionsBannerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10) + }() + private lazy var centerOffset: CGFloat = calculateCenterOffset(with: view.bounds.size) + private lazy var instructionsBannerCenterOffsetConstraint = { + return instructionsBannerView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0) + }() + private lazy var instructionsBannerWidthConstraint = { + return instructionsBannerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9) + }() + + // You can Include one of the existing Views to display route-specific info + lazy var instructionsBannerView: InstructionsBannerView = { + let banner = InstructionsBannerView() + banner.translatesAutoresizingMaskIntoConstraints = false + banner.heightAnchor.constraint(equalToConstant: 100.0).isActive = true + banner.layer.cornerRadius = 25 + banner.layer.opacity = 0.75 + banner.separatorView.isHidden = true + return banner + }() + + override func viewDidLoad() { + view.addSubview(instructionsBannerView) + + setupConstraints() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateConstraints() + } + + private func setupConstraints() { + instructionsBannerCenterOffsetConstraint.isActive = true + instructionsBannerTopOffsetConstraint.isActive = true + instructionsBannerWidthConstraint.isActive = true + } + + private func updateConstraints() { + instructionsBannerCenterOffsetConstraint.constant = centerOffset + } + + // MARK: - Device rotation + + private func calculateCenterOffset(with size: CGSize) -> CGFloat { + return (size.height < size.width ? -size.width / 5 : 0) + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + centerOffset = calculateCenterOffset(with: size) + } + + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + updateConstraints() + } + + // MARK: - NavigationComponent implementation + + func onRouteProgressUpdated(_ progress: RouteProgress) { + // pass updated data to sub-views which also implement `NavigationComponent` + instructionsBannerView.updateDistance(for: progress.currentLegProgress.currentStepProgress) + } + + func onDidPassVisualInstructionPoint(_ instruction: VisualInstructionBanner) { + instructionsBannerView.update(for: instruction) + } +} + +// MARK: - CustomBottomBarViewController + +class CustomBottomBarViewController: ContainerViewController, CustomBottomBannerViewDelegate { + + weak var navigationViewController: NavigationViewController? + + // Or you can implement your own UI elements + lazy var bannerView: CustomBottomBannerView = { + let banner = CustomBottomBannerView() + banner.translatesAutoresizingMaskIntoConstraints = false + banner.delegate = self + return banner + }() + + override func loadView() { + super.loadView() + + view.addSubview(bannerView) + + let safeArea = view.layoutMarginsGuide + NSLayoutConstraint.activate([ + bannerView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor), + bannerView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor), + bannerView.heightAnchor.constraint(equalTo: view.heightAnchor), + bannerView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor) + ]) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + setupConstraints() + } + + private func setupConstraints() { + if let superview = view.superview?.superview { + view.bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor).isActive = true + } + } + + // MARK: - NavigationComponent implementation + + func onRouteProgressUpdated(_ progress: RouteProgress) { + // Update your controls manually + bannerView.progress = Float(progress.fractionTraveled) + bannerView.eta = "~\(Int(round(progress.durationRemaining / 60))) min" + } + + // MARK: - CustomBottomBannerViewDelegate implementation + + func customBottomBannerDidCancel(_ banner: CustomBottomBannerView) { + navigationViewController?.dismiss(animated: true, + completion: nil) + } +} diff --git a/Examples/AdditionalExamples/Examples/CustomBars/CustomBottomBannerView.swift b/Examples/AdditionalExamples/Examples/CustomBars/CustomBottomBannerView.swift new file mode 100644 index 00000000000..dbd503b7ec7 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/CustomBars/CustomBottomBannerView.swift @@ -0,0 +1,69 @@ +import UIKit +import MapboxNavigationUIKit + +protocol CustomBottomBannerViewDelegate: AnyObject { + func customBottomBannerDidCancel(_ banner: CustomBottomBannerView) +} + +class CustomBottomBannerView: UIView { + + @IBOutlet var contentView: UIView! + @IBOutlet weak var etaLabel: UILabel! + @IBOutlet weak var progressBar: UIProgressView! + @IBOutlet weak var cancelButton: UIButton! + + var progress: Float { + get { + return progressBar.progress + } + set { + progressBar.setProgress(newValue, animated: false) + } + } + + var eta: String? { + get { + return etaLabel.text + } + set { + etaLabel.text = newValue + } + } + + weak var delegate: CustomBottomBannerViewDelegate? + + private func initFromNib() { + Bundle.main.loadNibNamed(String(describing: CustomBottomBannerView.self), + owner: self, + options: nil) + addSubview(contentView) + contentView.frame = bounds + contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + progressBar.progressTintColor = .systemGreen + progressBar.layer.borderColor = UIColor.black.cgColor + progressBar.layer.borderWidth = 2 + progressBar.layer.cornerRadius = 5 + + cancelButton.backgroundColor = .systemGray + cancelButton.layer.cornerRadius = 5 + cancelButton.setTitleColor(.darkGray, for: .highlighted) + + backgroundColor = UIColor.black.withAlphaComponent(0.3) + layer.cornerRadius = 10 + } + + override init(frame: CGRect) { + super.init(frame: frame) + initFromNib() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + initFromNib() + } + + @IBAction func onCancel(_ sender: Any) { + delegate?.customBottomBannerDidCancel(self) + } +} diff --git a/Examples/AdditionalExamples/Examples/CustomBars/CustomBottomBannerView.xib b/Examples/AdditionalExamples/Examples/CustomBars/CustomBottomBannerView.xib new file mode 100644 index 00000000000..9d647004375 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/CustomBars/CustomBottomBannerView.xib @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/AdditionalExamples/Examples/Embedded-Navigation.swift b/Examples/AdditionalExamples/Examples/Embedded-Navigation.swift new file mode 100644 index 00000000000..5cb1a3aae86 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Embedded-Navigation.swift @@ -0,0 +1,99 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/embedded-navigation + */ + +import Foundation +import MapboxNavigationCore +import MapboxNavigationUIKit +import MapboxDirections +import MapboxMaps +import UIKit + +class EmbeddedExampleViewController: UIViewController { + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: .init( + latitude: 37.77440680146262, + longitude: -122.43539772352648 + ) + ) : .live + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + @IBOutlet weak var reroutedLabel: UILabel! + @IBOutlet weak var container: UIView! + var navigationRoutes: NavigationRoutes? + + lazy var routeOptions: NavigationRouteOptions = { + let origin = CLLocationCoordinate2DMake(37.77440680146262, -122.43539772352648) + let destination = CLLocationCoordinate2DMake(37.76556957793795, -122.42409811526268) + return NavigationRouteOptions(coordinates: [origin, destination]) + }() + + override func viewDidLoad() { + super.viewDidLoad() + + reroutedLabel.isHidden = true + calculateDirections() + } + + func calculateDirections() { + Task { + switch await mapboxNavigation.routingProvider().calculateRoutes(options: routeOptions).result { + case .failure(let error): + print(error.localizedDescription) + case .success(let response): + + self.navigationRoutes = response + self.startEmbeddedNavigation() + } + } + } + + func flashReroutedLabel() { + reroutedLabel.isHidden = false + reroutedLabel.alpha = 1.0 + UIView.animate(withDuration: 1.0, delay: 1, options: .curveEaseIn, animations: { + self.reroutedLabel.alpha = 0.0 + }, completion: { _ in + self.reroutedLabel.isHidden = true + }) + } + + func startEmbeddedNavigation() { + // For demonstration purposes, simulate locations if the Simulate Navigation option is on. + guard let navigationRoutes else { return } + let navigationOptions = NavigationOptions(mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager()) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + + navigationViewController.delegate = self + addChild(navigationViewController) + container.addSubview(navigationViewController.view) + navigationViewController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + navigationViewController.view.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0), + navigationViewController.view.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: 0), + navigationViewController.view.topAnchor.constraint(equalTo: container.topAnchor, constant: 0), + navigationViewController.view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 0) + ]) + self.didMove(toParent: self) + } +} + +extension EmbeddedExampleViewController: NavigationViewControllerDelegate { + func navigationViewController(_ navigationViewController: NavigationViewController, didRerouteAlong route: Route) { + flashReroutedLabel() + } + + func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { + navigationController?.popViewController(animated: true) + } +} diff --git a/Examples/AdditionalExamples/Examples/EmbeddedExamples.storyboard b/Examples/AdditionalExamples/Examples/EmbeddedExamples.storyboard new file mode 100644 index 00000000000..9d4e656d783 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/EmbeddedExamples.storyboard @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/AdditionalExamples/Examples/History-Recording.swift b/Examples/AdditionalExamples/Examples/History-Recording.swift new file mode 100644 index 00000000000..1d290ce0e6c --- /dev/null +++ b/Examples/AdditionalExamples/Examples/History-Recording.swift @@ -0,0 +1,225 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples + */ + +import UIKit +import MapboxNavigationUIKit +import MapboxNavigationCore +import MapboxDirections +import MapboxMaps + +func defaultHistoryDirectoryURL() -> URL { + let basePath: String + if let applicationSupportPath = + NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first { + basePath = applicationSupportPath + } else { + basePath = NSTemporaryDirectory() + } + let historyDirectoryURL = URL(fileURLWithPath: basePath, isDirectory: true) + .appendingPathComponent("com.mapbox.Example") + .appendingPathComponent("NavigationHistory") + + if FileManager.default.fileExists(atPath: historyDirectoryURL.path) == false { + try? FileManager.default.createDirectory(at: historyDirectoryURL, + withIntermediateDirectories: true, + attributes: nil) + } + return historyDirectoryURL +} + +class HistoryRecordingViewController: UIViewController, NavigationMapViewDelegate, NavigationViewControllerDelegate { + var navigationMapView: NavigationMapView! { + didSet { + if let navigationMapView = oldValue { + navigationMapView.removeFromSuperview() + } + + if navigationMapView != nil { + configure() + } + } + } + + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: nil + ) : .live, + // setting up the custom history repository location. + // If not set, the default directory will be used. + historyRecordingConfig: HistoryRecordingConfig(historyDirectoryURL: defaultHistoryDirectoryURL()) + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + var navigationRoutes: NavigationRoutes? { + didSet { + showCurrentRoute() + } + } + + func showCurrentRoute() { + guard let navigationRoutes else { + navigationMapView.removeRoutes() + return + } + navigationMapView.showcase(navigationRoutes) + } + + var startButton: UIButton! + + func loadNavigationViewIfNeeded() { + if navigationMapView == nil { + navigationMapView = .init( + location: mapboxNavigation.navigation().locationMatching.map(\.location).eraseToAnyPublisher(), + routeProgress: mapboxNavigation.navigation().routeProgress.map(\.?.routeProgress).eraseToAnyPublisher(), + predictiveCacheManager: mapboxNavigationProvider.predictiveCacheManager + ) + } + } + + override func viewDidLoad() { + super.viewDidLoad() + loadNavigationViewIfNeeded() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + mapboxNavigation.historyRecorder()?.startRecordingHistory() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + mapboxNavigation.historyRecorder()?.stopRecordingHistory { historyFileUrl in + guard let historyFileUrl = historyFileUrl else { return } + print("Free Drive History file has been successfully saved at the path: \(historyFileUrl.path)") + } + } + + private func configure() { + setupNavigationMapView() + startFreeDrive() + + // set start button + startButton = UIButton() + startButton.setTitle("Start Navigation", for: .normal) + startButton.translatesAutoresizingMaskIntoConstraints = false + startButton.backgroundColor = .blue + startButton.contentEdgeInsets = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20) + startButton.addTarget(self, action: #selector(tappedButton(sender:)), for: .touchUpInside) + startButton.isHidden = true + view.addSubview(startButton) + startButton.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true + startButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true + view.setNeedsLayout() + + } + + private func startFreeDrive() { + mapboxNavigation.tripSession().startFreeDrive() + } + + private func setupNavigationMapView() { + navigationMapView.delegate = self + navigationMapView.translatesAutoresizingMaskIntoConstraints = false + + view.insertSubview(navigationMapView, at: 0) + + NSLayoutConstraint.activate([ + navigationMapView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationMapView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + navigationMapView.topAnchor.constraint(equalTo: view.topAnchor), + navigationMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + + } + + func requestRoute(destination: CLLocationCoordinate2D) { + guard let userLocation = navigationMapView.mapView.location.latestLocation else { return } + let location = CLLocation(latitude: userLocation.coordinate.latitude, + longitude: userLocation.coordinate.longitude) + + let userWaypoint = Waypoint(location: location, + name: "user") + + let destinationWaypoint = Waypoint(coordinate: destination) + + let navigationRouteOptions = NavigationRouteOptions(waypoints: [userWaypoint, destinationWaypoint]) + + Task { + switch await mapboxNavigation.routingProvider().calculateRoutes(options: navigationRouteOptions).result { + case .failure(let error): + print(error.localizedDescription) + case .success(let response): + self.navigationRoutes = response + self.startButton?.isHidden = false + } + } + } + + // Override layout lifecycle callback to be able to style the start button. + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + startButton.layer.cornerRadius = startButton.bounds.midY + startButton.clipsToBounds = true + startButton.setNeedsDisplay() + } + + @objc func tappedButton(sender: UIButton) { + guard let navigationRoutes else { return } + + let navigationOptions = NavigationOptions( + mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager() + ) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.delegate = self + navigationViewController.modalPresentationStyle = .fullScreen + navigationViewController.routeLineTracksTraversal = true + + presentAndRemoveNaviagationMapView(navigationViewController) + } + + func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { + mapboxNavigation.historyRecorder()?.stopRecordingHistory { historyFileUrl in + guard let historyFileUrl = historyFileUrl else { return } + print("Active Guidance History file has been successfully saved at the path: \(historyFileUrl.path)") + } + dismiss(animated: true, completion: nil) + loadNavigationViewIfNeeded() + } + + func presentAndRemoveNaviagationMapView(_ navigationViewController: NavigationViewController, + animated: Bool = true, + completion: CompletionHandler? = nil) { + + navigationViewController.modalPresentationStyle = .fullScreen + present(navigationViewController, animated: animated) { + completion?() + self.navigationMapView = nil + + self.mapboxNavigation.historyRecorder()?.startRecordingHistory() + } + } + + // MARK: NavigationMapViewDelegate implementation + + func navigationMapView(_ navigationMapView: NavigationMapView, userDidLongTap mapPoint: MapPoint) { + requestRoute(destination: mapPoint.coordinate) + } + + // Delegate method called when the user selects a route + func navigationMapView(_ navigationMapView: NavigationMapView, didSelect alternativeRoute: AlternativeRoute) { + Task { + guard let selectedRoutes = await self.navigationRoutes?.selecting(alternativeRoute: alternativeRoute) else { return } + self.navigationRoutes = selectedRoutes + } + } +} diff --git a/Examples/AdditionalExamples/Examples/Offline-Regions.swift b/Examples/AdditionalExamples/Examples/Offline-Regions.swift new file mode 100644 index 00000000000..1d8b68d420b --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Offline-Regions.swift @@ -0,0 +1,330 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples + */ + +import UIKit +import MapboxNavigationCore +import MapboxNavigationNative +import MapboxMaps +import MapboxNavigationUIKit +import MapboxDirections + +class OfflineRegionsViewController: UIViewController { + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + // For demonstration purposes, simulate locations if the Simulate Navigation option is on. + locationSource: simulationIsEnabled ? .simulation( + initialLocation: nil + ) : .live, + // Though not recommended, the tile store can also be configure with custom storage location. + tilestoreConfig: .default + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + // MARK: Setup variables for Tile Management + let styleURI: StyleURI = .streets + var region: Region? + let zoomMin: UInt8 = 0 + let zoomMax: UInt8 = 16 + let offlineManager = OfflineManager() + var tileStoreConfiguration: TileStoreConfiguration { + mapboxNavigationProvider.coreConfig.tilestoreConfig + } + var tileStoreLocation: TileStoreConfiguration.Location { + tileStoreConfiguration.navigatorLocation + } + var tileStore: TileStore { + tileStoreLocation.tileStore + } + + var currentLocation: CLLocation? { + mapboxNavigation.navigation().currentLocationMatching?.mapMatchingResult.enhancedLocation + } + + var downloadButton = UIButton() + var startButton = UIButton() + var navigationMapView: NavigationMapView? + var options: NavigationRouteOptions? + + var navigationRoutes: NavigationRoutes? { + didSet { + showRoutes() + showStartNavigationAlert() + } + } + + struct Region { + var bbox: [CLLocationCoordinate2D] + var identifier: String + } + + // MARK: Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + setupNavigationMapView() + addDownloadButton() + addStartButton() + } + + func setupNavigationMapView() { + let navigationMapView = NavigationMapView( + location: mapboxNavigation.navigation().locationMatching.map(\.location).eraseToAnyPublisher(), + routeProgress: mapboxNavigation.navigation().routeProgress.map(\.?.routeProgress).eraseToAnyPublisher(), + predictiveCacheManager: mapboxNavigationProvider.predictiveCacheManager + ) + navigationMapView.delegate = self + navigationMapView.translatesAutoresizingMaskIntoConstraints = false + + view.addSubview(navigationMapView) + + NSLayoutConstraint.activate([ + navigationMapView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationMapView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + navigationMapView.topAnchor.constraint(equalTo: view.topAnchor), + navigationMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + self.navigationMapView = navigationMapView + + mapboxNavigation.tripSession().startFreeDrive() + } + + func addDownloadButton() { + downloadButton.setTitle("Download Offline Region", for: .normal) + downloadButton.backgroundColor = .blue + downloadButton.layer.cornerRadius = 5 + downloadButton.translatesAutoresizingMaskIntoConstraints = false + downloadButton.addTarget(self, action: #selector(tappedDownloadButton(sender:)), for: .touchUpInside) + view.addSubview(downloadButton) + + downloadButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50).isActive = true + downloadButton.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true + downloadButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) + downloadButton.sizeToFit() + downloadButton.titleLabel?.font = UIFont.systemFont(ofSize: 25) + } + + func addStartButton() { + startButton.setTitle("Start Offline Navigation", for: .normal) + startButton.backgroundColor = .blue + startButton.layer.cornerRadius = 5 + startButton.translatesAutoresizingMaskIntoConstraints = false + startButton.addTarget(self, action: #selector(tappedStartButton(sender:)), for: .touchUpInside) + showStartButton(false) + view.addSubview(startButton) + + startButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50).isActive = true + startButton.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true + startButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) + startButton.sizeToFit() + startButton.titleLabel?.font = UIFont.systemFont(ofSize: 25) + } + + func showStartButton(_ show: Bool = true) { + startButton.isHidden = !show + startButton.isEnabled = show + } + + @objc func tappedDownloadButton(sender: UIButton) { + downloadButton.isHidden = true + downloadTileRegion() + } + + @objc func tappedStartButton(sender: UIButton) { + showStartButton(false) + startNavigation() + } + + // MARK: Offline navigation + + func showRoutes() { + guard let navigationRoutes else { return } + navigationMapView?.showsRestrictedAreasOnRoute = true + navigationMapView?.showcase(navigationRoutes, routeAnnotationKinds: [.routeDurations]) + } + + func showStartNavigationAlert() { + let alertController = UIAlertController(title: "Start navigation", + message: "Turn off network access to start active navigation", + preferredStyle: .alert) + let approveAction = UIAlertAction(title: "OK", style: .default, handler: {_ in self.showStartButton()}) + alertController.addAction(approveAction) + self.present(alertController, animated: true, completion: nil) + } + + func requestRoute() { + guard let options = options else { return } + + Task { [weak self] in + guard let self else { return } + switch await self.mapboxNavigation.routingProvider().calculateRoutes(options: options).result { + case .failure(let error): + print("Failed to request route with error: \(error.localizedDescription)") + case .success(let response): + self.navigationRoutes = response + } + } + } + + func startNavigation() { + guard let navigationRoutes else { return } + + let navigationOptions = NavigationOptions( + mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager() + ) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.delegate = self + navigationViewController.modalPresentationStyle = .fullScreen + + present(navigationViewController, animated: true) { + self.navigationMapView = nil + } + } + + // MARK: Create regions + + func createRegion() { + guard let location = currentLocation?.coordinate else { return } + if region == nil { + // Generate a rectangle based on current user location + let distance: CLLocationDistance = 1e4 + let directions: [CLLocationDegrees] = [45, 135, 225, 315, 45] + let coordinates = directions.map { location.coordinate(at: distance, facing: $0) } + region = Region(bbox: coordinates, identifier: "Current location") + } + addRegionBoxLine() + } + + func addRegionBoxLine() { + guard let style = navigationMapView?.mapView.mapboxMap, + let coordinates = region?.bbox else { return } + do { + let identifier = "regionBox" + var source = GeoJSONSource(id: identifier) + source.data = .geometry(.lineString(.init(coordinates))) + try style.addSource(source) + + var layer = LineLayer(id: identifier, source: identifier) + layer.lineWidth = .constant(3.0) + layer.lineColor = .constant(.init(.red)) + try style.addPersistentLayer(layer) + } catch { + print("Error \(error.localizedDescription) occured while adding box for region boundary.") + } + } + + // MARK: Download offline Regions + + func downloadTileRegion() { + // Create style package + self.createRegion() + guard let region = region, + let stylePackLoadOptions = StylePackLoadOptions(glyphsRasterizationMode: nil, + metadata: [:]) else { + return + } + _ = offlineManager.loadStylePack(for: styleURI, loadOptions: stylePackLoadOptions, completion: { [weak self] result in + guard let self = self else { return } + switch result { + case .success(let stylePack): + print("Style pack \(stylePack.styleURI) downloaded!") + self.download(region: region) + case .failure(let error): + print("Error while downloading style pack: \(error).") + } + }) + } + + func download(region: Region) { + guard let loadOptions = tileRegionLoadOptions(for: region) else { return } + // loadTileRegions returns a Cancelable that allows developers to cancel downloading a region + _ = self.tileStore.loadTileRegion(forId: region.identifier, loadOptions: loadOptions, progress: { progress in + print("\(progress.loadedResourceSize)/\(progress.completedResourceSize)") + }, completion: { result in + switch result { + case .success(let region): + print("\(region.id) downloaded!") + self.showDownloadCompletionAlert() + case .failure(let error): + print("Error while downloading region: \(error)") + self.showDownloadFailedAlert(with: error) + } + }) + } + + // Helper method for creating TileRegionLoadOptions that are needed to download regions + func tileRegionLoadOptions(for region: Region) -> TileRegionLoadOptions? { + let tilesetDescriptorOptions = TilesetDescriptorOptions(styleURI: styleURI, + zoomRange: zoomMin...zoomMax, + tilesets: [ + // for more details about tileseets, see documentation page + // `https://docs.mapbox.com/data/tilesets/reference/` + "mapbox://mapbox.mapbox-streets-v8", + "mapbox://mapbox.mapbox-terrain-v2" + ]) + let mapsDescriptor = offlineManager.createTilesetDescriptor(for: tilesetDescriptorOptions) + return TileRegionLoadOptions( + geometry: Polygon([region.bbox]).geometry, + descriptors: [ mapsDescriptor, mapboxNavigationProvider.getLatestNavigationTilesetDescriptor() ], + metadata: nil, + acceptExpired: true, + networkRestriction: .none + ) + } + + func showDownloadCompletionAlert() { + DispatchQueue.main.async { + let alertController = UIAlertController(title: "Downloading completed", + message: "Long press location inside the box to get directions", + preferredStyle: .alert) + let approveAction = UIAlertAction(title: "OK", style: .default, handler: nil) + alertController.addAction(approveAction) + self.present(alertController, animated: true, completion: nil) + } + } + + func showDownloadFailedAlert(with error: Error) { + DispatchQueue.main.async { + let alertController = UIAlertController(title: "Error while downloading region", + message: error.localizedDescription, + preferredStyle: .alert) + let approveAction = UIAlertAction(title: "OK", style: .default, handler: nil) + alertController.addAction(approveAction) + self.present(alertController, animated: true, completion: nil) + } + } +} + +extension OfflineRegionsViewController: NavigationMapViewDelegate { + func navigationMapView(_ navigationMapView: NavigationMapView, userDidLongTap mapPoint: MapPoint) { + guard downloadButton.isHidden == true, + let currentCoordinate = currentLocation?.coordinate else { return } + + options = NavigationRouteOptions(coordinates: [currentCoordinate, mapPoint.coordinate]) + requestRoute() + } + + // Delegate method called when the user selects a route + func navigationMapView(_ navigationMapView: NavigationMapView, didSelect alternativeRoute: AlternativeRoute) { + Task { + guard let selectedRoutes = await self.navigationRoutes?.selecting(alternativeRoute: alternativeRoute) else { return } + self.navigationRoutes = selectedRoutes + } + } +} + +extension OfflineRegionsViewController: NavigationViewControllerDelegate { + func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { + navigationViewController.dismiss(animated: false) { + self.setupNavigationMapView() + self.addStartButton() + } + } +} diff --git a/Examples/AdditionalExamples/Examples/Styled-UI-Elements.swift b/Examples/AdditionalExamples/Examples/Styled-UI-Elements.swift new file mode 100644 index 00000000000..0ea5c1c1160 --- /dev/null +++ b/Examples/AdditionalExamples/Examples/Styled-UI-Elements.swift @@ -0,0 +1,169 @@ +/* + This code example is part of the Mapbox Navigation SDK for iOS demo app, + which you can build and run: https://github.com/mapbox/mapbox-navigation-ios-examples + To learn more about each example in this app, including descriptions and links + to documentation, see our docs: https://docs.mapbox.com/ios/navigation/examples/styled-ui-elements + */ + +import Foundation +import UIKit +import CoreLocation +import MapboxNavigationCore +import MapboxNavigationUIKit +import MapboxDirections + +class CustomStyleUIElements: UIViewController { + let mapboxNavigationProvider = MapboxNavigationProvider( + coreConfig: .init( + locationSource: simulationIsEnabled ? .simulation( + initialLocation: .init( + latitude: 37.77440680146262, + longitude: -122.43539772352648 + ) + ) : .live + ) + ) + lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation + + override func viewDidLoad() { + super.viewDidLoad() + + let origin = CLLocationCoordinate2DMake(37.77440680146262, -122.43539772352648) + let destination = CLLocationCoordinate2DMake(37.76556957793795, -122.42409811526268) + let options = NavigationRouteOptions(coordinates: [origin, destination]) + + let request = mapboxNavigation.routingProvider().calculateRoutes(options: options) + + Task { + switch await request.result { + case .failure(let error): + print(error.localizedDescription) + case .success(let navigationRoutes): + let navigationOptions = NavigationOptions(mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager(), + // Passing styles with the rest of the options. + styles: [CustomDayStyle(), CustomNightStyle()]) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + + navigationViewController.modalPresentationStyle = .fullScreen + // Render part of the route that has been traversed with full transparency, to give the illusion of a disappearing route. + navigationViewController.routeLineTracksTraversal = true + + // Congestion colors are configured directly in `NavigationMapView`. + let colors = CongestionColorsConfiguration.Colors( + low: .red, + moderate: .purple, + heavy: .orange, + severe: .yellow, + unknown: .gray + ) + navigationViewController.navigationMapView?.congestionConfiguration = .init( + colors: .init( + mainRouteColors: colors, + alternativeRouteColors: colors + ), + ranges: .default + ) + + present(navigationViewController, animated: true, completion: nil) + } + } + } +} + +class CustomDayStyle: DayStyle { + + private let backgroundColor = #colorLiteral(red: 0.06276176125, green: 0.6164312959, blue: 0.3432356119, alpha: 1) + private let darkBackgroundColor = #colorLiteral(red: 0.0473754704, green: 0.4980872273, blue: 0.2575169504, alpha: 1) + private let secondaryBackgroundColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + private let blueColor = #colorLiteral(red: 0.26683864, green: 0.5903761983, blue: 1, alpha: 1) + private let lightGrayColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1) + private let darkGrayColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) + private let primaryLabelColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) + private let secondaryLabelColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.9) + + required init() { + super.init() + mapStyleURL = URL(string: "mapbox://styles/mapbox/satellite-streets-v9")! + styleType = .day + } + + override func apply() { + super.apply() + + let traitCollection = UIScreen.main.traitCollection + ArrivalTimeLabel.appearance(for: traitCollection).textColor = lightGrayColor + BottomBannerView.appearance(for: traitCollection).backgroundColor = secondaryBackgroundColor + BottomPaddingView.appearance(for: traitCollection).backgroundColor = secondaryBackgroundColor + Button.appearance(for: traitCollection).textColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + CancelButton.appearance(for: traitCollection).tintColor = lightGrayColor + DistanceLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).unitTextColor = secondaryLabelColor + DistanceLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).valueTextColor = primaryLabelColor + DistanceLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [StepInstructionsView.self]).unitTextColor = lightGrayColor + DistanceLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [StepInstructionsView.self]).valueTextColor = darkGrayColor + DistanceRemainingLabel.appearance(for: traitCollection).textColor = lightGrayColor + DismissButton.appearance(for: traitCollection).textColor = darkGrayColor + FloatingButton.appearance(for: traitCollection).backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1) + FloatingButton.appearance(for: traitCollection).tintColor = blueColor + TopBannerView.appearance(for: traitCollection).backgroundColor = backgroundColor + InstructionsBannerView.appearance(for: traitCollection).backgroundColor = backgroundColor + LanesView.appearance(for: traitCollection).backgroundColor = darkBackgroundColor + LaneView.appearance(for: traitCollection).primaryColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + ManeuverView.appearance(for: traitCollection).backgroundColor = backgroundColor + ManeuverView.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).primaryColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + ManeuverView.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).secondaryColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.5) + ManeuverView.appearance(for: traitCollection, whenContainedInInstancesOf: [NextBannerView.self]).primaryColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + ManeuverView.appearance(for: traitCollection, whenContainedInInstancesOf: [NextBannerView.self]).secondaryColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.5) + ManeuverView.appearance(for: traitCollection, whenContainedInInstancesOf: [StepInstructionsView.self]).primaryColor = darkGrayColor + ManeuverView.appearance(for: traitCollection, whenContainedInInstancesOf: [StepInstructionsView.self]).secondaryColor = lightGrayColor + NextBannerView.appearance(for: traitCollection).backgroundColor = backgroundColor + NextInstructionLabel.appearance(for: traitCollection).textColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1) + NavigationMapView.appearance(for: traitCollection).tintColor = blueColor + PrimaryLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).normalTextColor = primaryLabelColor + PrimaryLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [StepInstructionsView.self]).normalTextColor = darkGrayColor + ResumeButton.appearance(for: traitCollection).backgroundColor = secondaryBackgroundColor + ResumeButton.appearance(for: traitCollection).tintColor = blueColor + SecondaryLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [InstructionsBannerView.self]).normalTextColor = secondaryLabelColor + SecondaryLabel.appearance(for: traitCollection, whenContainedInInstancesOf: [StepInstructionsView.self]).normalTextColor = darkGrayColor + TimeRemainingLabel.appearance(for: traitCollection).textColor = lightGrayColor + TimeRemainingLabel.appearance(for: traitCollection).trafficLowColor = darkBackgroundColor + TimeRemainingLabel.appearance(for: traitCollection).trafficUnknownColor = darkGrayColor + WayNameLabel.appearance(for: traitCollection).normalTextColor = blueColor + WayNameView.appearance(for: traitCollection).backgroundColor = secondaryBackgroundColor + } +} + +class CustomNightStyle: NightStyle { + + private let backgroundColor = #colorLiteral(red: 0.06276176125, green: 0.6164312959, blue: 0.3432356119, alpha: 1) + private let darkBackgroundColor = #colorLiteral(red: 0.0473754704, green: 0.4980872273, blue: 0.2575169504, alpha: 1) + private let secondaryBackgroundColor = #colorLiteral(red: 0.1335069537, green: 0.133641988, blue: 0.1335278749, alpha: 1) + private let blueColor = #colorLiteral(red: 0.26683864, green: 0.5903761983, blue: 1, alpha: 1) + private let lightGrayColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1) + private let darkGrayColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) + private let primaryTextColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) + private let secondaryTextColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.9) + + required init() { + super.init() + mapStyleURL = URL(string: "mapbox://styles/mapbox/satellite-streets-v9")! + styleType = .night + } + + override func apply() { + super.apply() + + let traitCollection = UIScreen.main.traitCollection + DistanceRemainingLabel.appearance(for: traitCollection).normalTextColor = primaryTextColor + BottomBannerView.appearance(for: traitCollection).backgroundColor = secondaryBackgroundColor + BottomPaddingView.appearance(for: traitCollection).backgroundColor = secondaryBackgroundColor + FloatingButton.appearance(for: traitCollection).backgroundColor = #colorLiteral(red: 0.1434620917, green: 0.1434366405, blue: 0.1819391251, alpha: 0.9037466989) + TimeRemainingLabel.appearance(for: traitCollection).textColor = primaryTextColor + TimeRemainingLabel.appearance(for: traitCollection).trafficLowColor = primaryTextColor + TimeRemainingLabel.appearance(for: traitCollection).trafficUnknownColor = primaryTextColor + ResumeButton.appearance(for: traitCollection).backgroundColor = #colorLiteral(red: 0.1434620917, green: 0.1434366405, blue: 0.1819391251, alpha: 0.9037466989) + ResumeButton.appearance(for: traitCollection).tintColor = blueColor + } +} diff --git a/Examples/AdditionalExamples/Info.plist b/Examples/AdditionalExamples/Info.plist new file mode 100644 index 00000000000..5eb459b1aa1 --- /dev/null +++ b/Examples/AdditionalExamples/Info.plist @@ -0,0 +1,34 @@ + + + + + MBXAccessToken + YOUR_MAPBOX_ACCESS_TOKEN + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIBackgroundModes + + audio + location + + UILaunchScreen + + + diff --git a/Examples/AdditionalExamples/SceneDelegate.swift b/Examples/AdditionalExamples/SceneDelegate.swift new file mode 100644 index 00000000000..c60de1caa80 --- /dev/null +++ b/Examples/AdditionalExamples/SceneDelegate.swift @@ -0,0 +1,46 @@ + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/Examples/CoreSDKExample/CoreSDKExampleApp.swift b/Examples/CoreSDKExample/CoreSDKExampleApp.swift new file mode 100644 index 00000000000..655628e8ff7 --- /dev/null +++ b/Examples/CoreSDKExample/CoreSDKExampleApp.swift @@ -0,0 +1,13 @@ +import SwiftUI + +@main +@MainActor +struct CoreSDKExampleApp: App { + private let navigation = Navigation() + + var body: some Scene { + WindowGroup { + ContentView(navigation: navigation) + } + } +} diff --git a/Examples/CoreSDKExample/Navigation.swift b/Examples/CoreSDKExample/Navigation.swift new file mode 100644 index 00000000000..97c949a477f --- /dev/null +++ b/Examples/CoreSDKExample/Navigation.swift @@ -0,0 +1,118 @@ +import Combine +import CoreLocation +import MapboxNavigationCore + +@MainActor +final class Navigation: ObservableObject { + let predictiveCacheManager: PredictiveCacheManager? + + @Published private(set) var isInActiveNavigation: Bool = false + @Published private(set) var currentPreviewRoutes: NavigationRoutes? + @Published private(set) var activeNavigationRoutes: NavigationRoutes? + @Published private(set) var visualInstruction: VisualInstructionBanner? + @Published private(set) var routeProgress: RouteProgress? + @Published private(set) var currentLocation: CLLocation? + @Published var cameraState: NavigationCameraState = .idle + @Published var profileIdentifier: ProfileIdentifier = .automobileAvoidingTraffic + @Published var shouldRequestMapMatching = false + + private var waypoints: [Waypoint] = [] + private let core: MapboxNavigation + + init() { + let config = CoreConfig( + credentials: .init() // You can pass a custom token if you need to + ) + let navigationProvider = MapboxNavigationProvider(coreConfig: config) + self.core = navigationProvider.mapboxNavigation + self.predictiveCacheManager = navigationProvider.predictiveCacheManager + observeNavigation() + } + + private func observeNavigation() { + core.tripSession().session + .map { + if case .activeGuidance = $0.state { return true } + return false + } + .removeDuplicates() + .assign(to: &$isInActiveNavigation) + + core.navigation().bannerInstructions + .map { $0.visualInstruction } + .assign(to: &$visualInstruction) + + core.navigation().routeProgress + .map { $0?.routeProgress } + .assign(to: &$routeProgress) + + core.tripSession().navigationRoutes + .assign(to: &$activeNavigationRoutes) + + core.navigation().locationMatching + .map { $0.location } + .assign(to: &$currentLocation) + } + + func startFreeDrive() { + core.tripSession().startFreeDrive() + } + + func cancelPreview() { + waypoints = [] + currentPreviewRoutes = nil + cameraState = .following + } + + func startActiveNavigation() { + guard let previewRoutes = currentPreviewRoutes else { return } + core.tripSession().startActiveGuidance(with: previewRoutes, startLegIndex: 0) + cameraState = .following + currentPreviewRoutes = nil + waypoints = [] + } + + func stopActiveNavigation() { + core.tripSession().startFreeDrive() + cameraState = .following + } + + func selectAlternativeRoute(at index: Int) async { + if let previewRoutes = currentPreviewRoutes { + currentPreviewRoutes = await previewRoutes.selectingAlternativeRoute(at: index) + } else { + core.navigation().selectAlternativeRoute(at: index) + } + } + + func requestRoutes(to mapPoint: MapPoint) async throws { + guard !isInActiveNavigation, let currentLocation else { return } + + waypoints.append(Waypoint(coordinate: mapPoint.coordinate, name: mapPoint.name)) + var userWaypoint = Waypoint(location: currentLocation) + if currentLocation.course >= 0, !shouldRequestMapMatching { + userWaypoint.heading = currentLocation.course + userWaypoint.headingAccuracy = 90 + } + var optionsWaypoints = waypoints + optionsWaypoints.insert(userWaypoint, at: 0) + + let provider = core.routingProvider() + if shouldRequestMapMatching { + let mapMatchingOptions = NavigationMatchOptions( + waypoints: optionsWaypoints, + profileIdentifier: profileIdentifier + ) + let previewRoutes = try await provider.calculateRoutes(options: mapMatchingOptions).value + currentPreviewRoutes = previewRoutes + } else { + let routeOptions = NavigationRouteOptions( + waypoints: optionsWaypoints, + profileIdentifier: profileIdentifier + ) + let previewRoutes = try await provider.calculateRoutes(options: routeOptions).value + currentPreviewRoutes = previewRoutes + } + cameraState = .idle + } +} diff --git a/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/AppIcon.appiconset/AppIcon.png new file mode 100644 index 00000000000..a52b106c62f Binary files /dev/null and b/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/AppIcon.appiconset/AppIcon.png differ diff --git a/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..cefcc878e08 --- /dev/null +++ b/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "AppIcon.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/Contents.json b/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/Contents.json new file mode 100644 index 00000000000..73c00596a7f --- /dev/null +++ b/Examples/CoreSDKExample/SupportingFiles/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/CoreSDKExample/SupportingFiles/Info.plist b/Examples/CoreSDKExample/SupportingFiles/Info.plist new file mode 100644 index 00000000000..79116aa501c --- /dev/null +++ b/Examples/CoreSDKExample/SupportingFiles/Info.plist @@ -0,0 +1,13 @@ + + + + + MBXAccessToken + PLACEHOLDER FOR MAPBOX TOKEN + UIBackgroundModes + + audio + location + + + diff --git a/Examples/CoreSDKExample/Views/ContentView.swift b/Examples/CoreSDKExample/Views/ContentView.swift new file mode 100644 index 00000000000..65d8ab68c88 --- /dev/null +++ b/Examples/CoreSDKExample/Views/ContentView.swift @@ -0,0 +1,41 @@ +import MapboxNavigationCore +import SwiftUI + +struct ContentView: View { + @ObservedObject var navigation: Navigation + + var body: some View { + ZStack { + VStack { + MapView(navigation: navigation) + .ignoresSafeArea(.all) + HStack { + if navigation.currentPreviewRoutes == nil, !navigation.isInActiveNavigation { + Text("Long press anywhere to build a route") + } else if navigation.currentPreviewRoutes != nil { + Button("Clear") { + navigation.cancelPreview() + } + Spacer() + Button("Start navigation") { + navigation.startActiveNavigation() + } + } + } + .padding() + .frame(maxWidth: .infinity, minHeight: 45) + } + if navigation.isInActiveNavigation { + NavigationControlsView(navigation: navigation) + } else { + SettingsControlsView(navigation: navigation) + } + } + } +} + +#if swift(>=5.9) +#Preview { + ContentView(navigation: Navigation()) +} +#endif diff --git a/Examples/CoreSDKExample/Views/MapView.swift b/Examples/CoreSDKExample/Views/MapView.swift new file mode 100644 index 00000000000..4e43036800c --- /dev/null +++ b/Examples/CoreSDKExample/Views/MapView.swift @@ -0,0 +1,12 @@ +import SwiftUI +import UIKit + +struct MapView: UIViewControllerRepresentable { + let navigation: Navigation + + func makeUIViewController(context: Context) -> UIViewController { + MapViewController(navigation: navigation) + } + + func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} +} diff --git a/Examples/CoreSDKExample/Views/MapViewController.swift b/Examples/CoreSDKExample/Views/MapViewController.swift new file mode 100644 index 00000000000..95ede027752 --- /dev/null +++ b/Examples/CoreSDKExample/Views/MapViewController.swift @@ -0,0 +1,121 @@ +import Combine +import CoreLocation +import Foundation +import MapboxMaps +import MapboxNavigationCore +import UIKit + +@MainActor +final class MapViewController: UIViewController { + private static let styleUrl = "mapbox://styles/mapbox-dash/standard-navigation" + + private let navigation: Navigation + private let navigationMapView: NavigationMapView + + private var lifetimeSubscriptions: Set = [] + + init(navigation: Navigation) { + self.navigation = navigation + + self.navigationMapView = NavigationMapView( + location: navigation.$currentLocation.compactMap { $0 }.eraseToAnyPublisher(), + routeProgress: navigation.$routeProgress.eraseToAnyPublisher(), + predictiveCacheManager: navigation.predictiveCacheManager + ) + + // Customize viewport padding + navigationMapView.viewportPadding = UIEdgeInsets(top: 20, left: 20, bottom: 80, right: 20) + + super.init(nibName: nil, bundle: nil) + + setupMapView() + observePreviewRoute() + observeCamera() + } + + override func viewDidLoad() { + super.viewDidLoad() + + Task { + navigation.cameraState = .following + navigation.startFreeDrive() + } + } + + override func loadView() { + view = navigationMapView + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupMapView() { + navigationMapView.mapView.mapboxMap.loadStyle(StyleURI(rawValue: Self.styleUrl)!) + navigationMapView.mapView.ornaments.compassView.isHidden = true + navigationMapView.delegate = self + // Possible configuration + navigationMapView.showsTrafficOnRouteLine = true + } + + private func observePreviewRoute() { + navigation.$currentPreviewRoutes + .removeDuplicates() + .combineLatest(navigation.$activeNavigationRoutes) + .dropFirst() + .sink { [weak self] previewRoutes, routes in + guard let self else { return } + if let previewRoutes { + navigationMapView.showcase(previewRoutes, animated: true) + } else if let routes { + navigationMapView.show(routes, routeAnnotationKinds: [.relativeDurationsOnAlternativeManuever]) + } else { + navigationMapView.removeRoutes() + } + } + .store(in: &lifetimeSubscriptions) + } + + func observeCamera() { + navigation.$cameraState + .removeDuplicates() + .sink { [weak self] cameraState in + self?.navigationMapView.update(navigationCameraState: cameraState) + }.store(in: &lifetimeSubscriptions) + } + + private func presentAlert(_ title: String? = nil, message: String? = nil) { + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in + alertController.dismiss(animated: true, completion: nil) + })) + + present(alertController, animated: true, completion: nil) + } + + private func requestRoute(to mapPoint: MapPoint) async { + do { + try await navigation.requestRoutes(to: mapPoint) + } catch { + presentAlert(message: "Request failed: \(error.localizedDescription)") + } + } +} + +extension MapViewController: NavigationMapViewDelegate { + func navigationMapView(_ navigationMapView: NavigationMapView, didSelectRouteIndexes routeIndexes: [Int]) { + guard let index = routeIndexes.first else { return } + Task { + await navigation.selectAlternativeRoute(at: index - 1) + } + } + + func navigationMapView(_ navigationMapView: NavigationMapView, userDidTap mapPoint: MapPoint) { + Task { await requestRoute(to: mapPoint) } + } + + func navigationMapView(_ navigationMapView: NavigationMapView, userDidLongTap mapPoint: MapPoint) { + Task { await requestRoute(to: mapPoint) } + } +} diff --git a/Examples/CoreSDKExample/Views/NavigationControlsView.swift b/Examples/CoreSDKExample/Views/NavigationControlsView.swift new file mode 100644 index 00000000000..6109f24c7ba --- /dev/null +++ b/Examples/CoreSDKExample/Views/NavigationControlsView.swift @@ -0,0 +1,198 @@ +import CoreLocation +import MapboxNavigationCore +import SwiftUI + +struct NavigationControlsView: View { + @ObservedObject var navigation: Navigation + + var body: some View { + VStack(spacing: 12) { + NextInstructionView(visualInstruction: navigation.visualInstruction) + + HStack { + Spacer() + CameraButtonView(cameraState: $navigation.cameraState) + } + + Spacer() + + NavigationProgressView(routeProgress: navigation.routeProgress) { + navigation.stopActiveNavigation() + } + } + .padding(12) + } +} + +struct NextInstructionView: View { + let visualInstruction: VisualInstructionBanner? + + var body: some View { + VStack(alignment: .leading) { + if let distanceRemaining { + Text(distanceFormatter.string(fromMeters: distanceRemaining)) + .font(.title) + } + if let text = visualInstruction?.primaryInstruction.text { + Text(text) + .font(.title2) + } + } + .padding() + .foregroundColor(Color(.label)) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color(.systemBackground)) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .shadow(radius: 5) + } + + private var distanceRemaining: CLLocationDistance? { + visualInstruction?.distanceAlongStep + } + + private let distanceFormatter: LengthFormatter = { + let formatter = LengthFormatter() + formatter.unitStyle = .medium + let numberFormatter = NumberFormatter() + numberFormatter.maximumFractionDigits = 0 + formatter.numberFormatter = numberFormatter + return formatter + }() +} + +struct CameraButtonView: View { + @Binding var cameraState: NavigationCameraState + + var body: some View { + Button { + cameraState = newCameraState + } label: { + Image(systemName: imageName) + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundColor(.blue) + .frame(width: 40, height: 40) + .padding() + .animation(nil, value: imageName) + } + .background(Color(.systemBackground)) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .shadow(radius: 5) + } + + private var imageName: String { + switch cameraState { + case .idle, .overview: + return "location.circle" + case .following: + return "location.north.line" + @unknown default: + return "location.circle" + } + } + + private var newCameraState: NavigationCameraState { + switch cameraState { + case .idle, .overview: + return .following + case .following: + return .overview + @unknown default: + return .overview + } + } +} + +struct NavigationProgressView: View { + let routeProgress: RouteProgress? + let onStopNavigation: () -> Void + + var body: some View { + HStack { + etaView + Spacer() + endNavigationButton + } + .padding() + .background(Color(.systemBackground)) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .frame(maxWidth: .infinity) + .shadow(radius: 5) + } + + private var endNavigationButton: some SwiftUI.View { + Button { + onStopNavigation() + } label: { + Image(systemName: "xmark.circle") + .resizable() + .renderingMode(.template) + .foregroundColor(Color(.label)) + .frame(width: 50, height: 50) + } + } + + private var etaView: some SwiftUI.View { + VStack(alignment: .leading, spacing: 0) { + Text(arrivalTimeText) + .font(.title3) + .foregroundColor(Color(.label)) + Text(durationRemainingText) + .font(.body) + .foregroundColor(Color(.secondaryLabel)) + Text(distanceRemainingText) + .font(.body) + .foregroundColor(Color(.secondaryLabel)) + } + } + + private var arrivalTimeText: String { + durationRemaining + .flatMap { Date().addingTimeInterval($0) } + .flatMap { timeFormatter.string(from: $0).lowercased() } ?? "-" + } + + private var distanceRemainingText: String { + distanceRemaining.flatMap(distanceFormatter.string(fromMeters:)) ?? "-" + } + + private var durationRemainingText: String { + durationRemaining.flatMap(durationRemainingFormatter.string(from:)) ?? "-" + } + + private var durationRemaining: TimeInterval? { + routeProgress?.currentLegProgress.durationRemaining + } + + private var distanceRemaining: CLLocationDistance? { + routeProgress?.currentLegProgress.distanceRemaining + } + + private let timeFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.timeStyle = .short + return formatter + }() + + private let distanceFormatter: LengthFormatter = { + let formatter = LengthFormatter() + formatter.unitStyle = .medium + let numberFormatter = NumberFormatter() + numberFormatter.maximumFractionDigits = 1 + formatter.numberFormatter = numberFormatter + return formatter + }() + + private let durationRemainingFormatter: DateComponentsFormatter = { + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .full + formatter.allowedUnits = [.day, .hour, .minute] + return formatter + }() +} + +#if swift(>=5.9) +#Preview { + ContentView(navigation: Navigation()) +} +#endif diff --git a/Examples/CoreSDKExample/Views/SettingsView.swift b/Examples/CoreSDKExample/Views/SettingsView.swift new file mode 100644 index 00000000000..72879b33ee4 --- /dev/null +++ b/Examples/CoreSDKExample/Views/SettingsView.swift @@ -0,0 +1,74 @@ +import MapboxNavigationCore +import SwiftUI + +struct SettingsView: View { + @ObservedObject var navigation: Navigation + + var body: some View { + NavigationView { + Form { + Toggle("Map Matching Request", isOn: $navigation.shouldRequestMapMatching) + Picker("Navigation Profile", selection: $navigation.profileIdentifier) { + ForEach(SettingsView.profiles, id: \.self) { profile in + Text(profile.displayName).tag(profile) + } + } + } + .navigationTitle("Settings") + } + } + + private static let profiles: [ProfileIdentifier] = [ + .automobileAvoidingTraffic, + .automobile, + .cycling, + .walking, + ] +} + +struct SettingsControlsView: View { + @ObservedObject var navigation: Navigation + @State private var settingsVisible = false + + var body: some View { + VStack { + HStack { + Spacer() + Button { + settingsVisible.toggle() + } label: { + Image(systemName: "gear") + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundColor(.blue) + .frame(width: 30, height: 30) + } + .padding() + .background(Color(.systemBackground)) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .padding() + } + Spacer() + } + .sheet(isPresented: $settingsVisible) { + SettingsView(navigation: navigation) + } + } +} + +extension ProfileIdentifier { + var displayName: String { + switch self { + case .automobile: + return "driving" + case .automobileAvoidingTraffic: + return "driving with traffic" + case .cycling: + return "cycling" + case .walking: + return "walking" + default: + return "-" + } + } +} diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..0966e9c82dc --- /dev/null +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -0,0 +1,1001 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 2C6A3C7A2BA3AE780039BBC9 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6A3C792BA3AE780039BBC9 /* Navigation.swift */; }; + 2C72A2CC2BC99C050097715C /* MapboxNavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = 2C72A2CB2BC99C050097715C /* MapboxNavigationCore */; }; + 2C72A2CE2BC99C090097715C /* MapboxNavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = 2C72A2CD2BC99C090097715C /* MapboxNavigationCore */; }; + 2C72A2D02BC99C090097715C /* MapboxNavigationUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2C72A2CF2BC99C090097715C /* MapboxNavigationUIKit */; }; + 2CA319EF2BC986EA0071176E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CE469152BA31C200075A32B /* Assets.xcassets */; }; + 2CA31A112BC9878A0071176E /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA319F82BC9878A0071176E /* Constants.swift */; }; + 2CA31A122BC9878A0071176E /* ExampleContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA319F92BC9878A0071176E /* ExampleContainerViewController.swift */; }; + 2CA31A132BC9878A0071176E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CA319FA2BC9878A0071176E /* Assets.xcassets */; }; + 2CA31A142BC9878A0071176E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2CA319FB2BC9878A0071176E /* LaunchScreen.storyboard */; }; + 2CA31A152BC9878A0071176E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2CA319FD2BC9878A0071176E /* Main.storyboard */; }; + 2CA31A162BC9878A0071176E /* Styled-UI-Elements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A002BC9878A0071176E /* Styled-UI-Elements.swift */; }; + 2CA31A172BC9878A0071176E /* History-Recording.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A012BC9878A0071176E /* History-Recording.swift */; }; + 2CA31A182BC9878A0071176E /* Advanced.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A022BC9878A0071176E /* Advanced.swift */; }; + 2CA31A192BC9878A0071176E /* Custom-Voice-Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A032BC9878A0071176E /* Custom-Voice-Controller.swift */; }; + 2CA31A1A2BC9878A0071176E /* Offline-Regions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A042BC9878A0071176E /* Offline-Regions.swift */; }; + 2CA31A1B2BC9878A0071176E /* Embedded-Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A052BC9878A0071176E /* Embedded-Navigation.swift */; }; + 2CA31A1C2BC9878A0071176E /* Basic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A062BC9878A0071176E /* Basic.swift */; }; + 2CA31A1D2BC9878A0071176E /* EmbeddedExamples.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2CA31A072BC9878A0071176E /* EmbeddedExamples.storyboard */; }; + 2CA31A1E2BC9878A0071176E /* Beta-Query-Parameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A082BC9878A0071176E /* Beta-Query-Parameters.swift */; }; + 2CA31A1F2BC9878A0071176E /* CustomBottomBannerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CA31A0A2BC9878A0071176E /* CustomBottomBannerView.xib */; }; + 2CA31A202BC9878A0071176E /* CustomBarsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A0B2BC9878A0071176E /* CustomBarsViewController.swift */; }; + 2CA31A212BC9878A0071176E /* CustomBottomBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A0C2BC9878A0071176E /* CustomBottomBannerView.swift */; }; + 2CA31A222BC9878A0071176E /* ExampleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A0D2BC9878A0071176E /* ExampleTableViewController.swift */; }; + 2CA31A232BC9878A0071176E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A0E2BC9878A0071176E /* AppDelegate.swift */; }; + 2CA31A252BC9878A0071176E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A102BC9878A0071176E /* SceneDelegate.swift */; }; + 2CA31A742BC9925B0071176E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8586BD2BB4902500A6E5C5 /* SettingsView.swift */; }; + 2CA31A752BC9925B0071176E /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE469282BA31FF00075A32B /* MapViewController.swift */; }; + 2CA31A762BC9925B0071176E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE469132BA31C1F0075A32B /* ContentView.swift */; }; + 2CA31A772BC9925B0071176E /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE469262BA31FE30075A32B /* MapView.swift */; }; + 2CA31A782BC9925B0071176E /* NavigationControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6A3C7B2BA466AA0039BBC9 /* NavigationControlsView.swift */; }; + 2CA31A8C2BC9927D0071176E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2CA31A7B2BC9927D0071176E /* LaunchScreen.storyboard */; }; + 2CA31A8D2BC9927D0071176E /* NavigationView+CameraOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A7E2BC9927D0071176E /* NavigationView+CameraOptions.swift */; }; + 2CA31A8E2BC9927D0071176E /* SceneDelegate+PreviewViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A7F2BC9927D0071176E /* SceneDelegate+PreviewViewControllerDelegate.swift */; }; + 2CA31A8F2BC9927D0071176E /* SceneDelegate+BannerDismissalViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A802BC9927D0071176E /* SceneDelegate+BannerDismissalViewControllerDelegate.swift */; }; + 2CA31A902BC9927D0071176E /* SceneDelegate+DestinationPreviewViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A812BC9927D0071176E /* SceneDelegate+DestinationPreviewViewControllerDelegate.swift */; }; + 2CA31A912BC9927D0071176E /* SceneDelegate+NavigationViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A822BC9927D0071176E /* SceneDelegate+NavigationViewControllerDelegate.swift */; }; + 2CA31A922BC9927D0071176E /* SceneDelegate+RoutesPreviewViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A832BC9927D0071176E /* SceneDelegate+RoutesPreviewViewControllerDelegate.swift */; }; + 2CA31A932BC9927D0071176E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A842BC9927D0071176E /* AppDelegate.swift */; }; + 2CA31A942BC9927D0071176E /* SceneDelegate+UIViewControllerTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A862BC9927D0071176E /* SceneDelegate+UIViewControllerTransitioningDelegate.swift */; }; + 2CA31A952BC9927D0071176E /* DismissalAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A872BC9927D0071176E /* DismissalAnimator.swift */; }; + 2CA31A962BC9927D0071176E /* PresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A882BC9927D0071176E /* PresentationAnimator.swift */; }; + 2CA31A982BC9927D0071176E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA31A8A2BC9927D0071176E /* SceneDelegate.swift */; }; + 2CA31A992BC9929A0071176E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CE469152BA31C200075A32B /* Assets.xcassets */; }; + 2CA31A9B2BC992DB0071176E /* MapboxNavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = 2CA31A9A2BC992DB0071176E /* MapboxNavigationCore */; }; + 2CA31A9D2BC992DB0071176E /* MapboxNavigationUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2CA31A9C2BC992DB0071176E /* MapboxNavigationUIKit */; }; + 2CA31AA02BC994060071176E /* MapboxGeocoder in Frameworks */ = {isa = PBXBuildFile; productRef = 2CA31A9F2BC994060071176E /* MapboxGeocoder */; }; + 2CE469122BA31C1F0075A32B /* CoreSDKExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE469112BA31C1F0075A32B /* CoreSDKExampleApp.swift */; }; + 2CE469162BA31C200075A32B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CE469152BA31C200075A32B /* Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 2CA319F02BC986EA0071176E /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 2CA31A6D2BC991C80071176E /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + DF4660812BBC75C400A0B2E4 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2C6A3C792BA3AE780039BBC9 /* Navigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Navigation.swift; sourceTree = ""; }; + 2C6A3C7B2BA466AA0039BBC9 /* NavigationControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationControlsView.swift; sourceTree = ""; }; + 2C8586BD2BB4902500A6E5C5 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 2CA319F52BC986EA0071176E /* AdditionalExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AdditionalExamples.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 2CA319F82BC9878A0071176E /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + 2CA319F92BC9878A0071176E /* ExampleContainerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleContainerViewController.swift; sourceTree = ""; }; + 2CA319FA2BC9878A0071176E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 2CA319FC2BC9878A0071176E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 2CA319FE2BC9878A0071176E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 2CA31A002BC9878A0071176E /* Styled-UI-Elements.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Styled-UI-Elements.swift"; sourceTree = ""; }; + 2CA31A012BC9878A0071176E /* History-Recording.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "History-Recording.swift"; sourceTree = ""; }; + 2CA31A022BC9878A0071176E /* Advanced.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Advanced.swift; sourceTree = ""; }; + 2CA31A032BC9878A0071176E /* Custom-Voice-Controller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Custom-Voice-Controller.swift"; sourceTree = ""; }; + 2CA31A042BC9878A0071176E /* Offline-Regions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Offline-Regions.swift"; sourceTree = ""; }; + 2CA31A052BC9878A0071176E /* Embedded-Navigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Embedded-Navigation.swift"; sourceTree = ""; }; + 2CA31A062BC9878A0071176E /* Basic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Basic.swift; sourceTree = ""; }; + 2CA31A072BC9878A0071176E /* EmbeddedExamples.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = EmbeddedExamples.storyboard; sourceTree = ""; }; + 2CA31A082BC9878A0071176E /* Beta-Query-Parameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Beta-Query-Parameters.swift"; sourceTree = ""; }; + 2CA31A0A2BC9878A0071176E /* CustomBottomBannerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomBottomBannerView.xib; sourceTree = ""; }; + 2CA31A0B2BC9878A0071176E /* CustomBarsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomBarsViewController.swift; sourceTree = ""; }; + 2CA31A0C2BC9878A0071176E /* CustomBottomBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomBottomBannerView.swift; sourceTree = ""; }; + 2CA31A0D2BC9878A0071176E /* ExampleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleTableViewController.swift; sourceTree = ""; }; + 2CA31A0E2BC9878A0071176E /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 2CA31A0F2BC9878A0071176E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2CA31A102BC9878A0071176E /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 2CA31A722BC991C80071176E /* UIKitExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIKitExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 2CA31A7C2BC9927D0071176E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 2CA31A7E2BC9927D0071176E /* NavigationView+CameraOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NavigationView+CameraOptions.swift"; sourceTree = ""; }; + 2CA31A7F2BC9927D0071176E /* SceneDelegate+PreviewViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+PreviewViewControllerDelegate.swift"; sourceTree = ""; }; + 2CA31A802BC9927D0071176E /* SceneDelegate+BannerDismissalViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+BannerDismissalViewControllerDelegate.swift"; sourceTree = ""; }; + 2CA31A812BC9927D0071176E /* SceneDelegate+DestinationPreviewViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+DestinationPreviewViewControllerDelegate.swift"; sourceTree = ""; }; + 2CA31A822BC9927D0071176E /* SceneDelegate+NavigationViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+NavigationViewControllerDelegate.swift"; sourceTree = ""; }; + 2CA31A832BC9927D0071176E /* SceneDelegate+RoutesPreviewViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+RoutesPreviewViewControllerDelegate.swift"; sourceTree = ""; }; + 2CA31A842BC9927D0071176E /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 2CA31A862BC9927D0071176E /* SceneDelegate+UIViewControllerTransitioningDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+UIViewControllerTransitioningDelegate.swift"; sourceTree = ""; }; + 2CA31A872BC9927D0071176E /* DismissalAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DismissalAnimator.swift; sourceTree = ""; }; + 2CA31A882BC9927D0071176E /* PresentationAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationAnimator.swift; sourceTree = ""; }; + 2CA31A892BC9927D0071176E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2CA31A8A2BC9927D0071176E /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 2CE4690E2BA31C1F0075A32B /* CoreSDKExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CoreSDKExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 2CE469112BA31C1F0075A32B /* CoreSDKExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreSDKExampleApp.swift; sourceTree = ""; }; + 2CE469132BA31C1F0075A32B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 2CE469152BA31C200075A32B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 2CE469202BA31CF20075A32B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2CE469262BA31FE30075A32B /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; + 2CE469282BA31FF00075A32B /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + DF92974F2BBD4A910047329A /* mapbox-navigation-ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "mapbox-navigation-ios"; path = ..; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2CA319EC2BC986EA0071176E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C72A2D02BC99C090097715C /* MapboxNavigationUIKit in Frameworks */, + 2C72A2CE2BC99C090097715C /* MapboxNavigationCore in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2CA31A6A2BC991C80071176E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA31A9D2BC992DB0071176E /* MapboxNavigationUIKit in Frameworks */, + 2CA31AA02BC994060071176E /* MapboxGeocoder in Frameworks */, + 2CA31A9B2BC992DB0071176E /* MapboxNavigationCore in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2CE4690B2BA31C1F0075A32B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C72A2CC2BC99C050097715C /* MapboxNavigationCore in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2C6A3C762BA389D90039BBC9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 2C6A3C7D2BA478EC0039BBC9 /* SupportingFiles */ = { + isa = PBXGroup; + children = ( + 2CE469152BA31C200075A32B /* Assets.xcassets */, + 2CE469202BA31CF20075A32B /* Info.plist */, + ); + path = SupportingFiles; + sourceTree = ""; + }; + 2C6A3C7E2BA478FC0039BBC9 /* Views */ = { + isa = PBXGroup; + children = ( + 2CE469262BA31FE30075A32B /* MapView.swift */, + 2C6A3C7B2BA466AA0039BBC9 /* NavigationControlsView.swift */, + 2CE469282BA31FF00075A32B /* MapViewController.swift */, + 2CE469132BA31C1F0075A32B /* ContentView.swift */, + 2C8586BD2BB4902500A6E5C5 /* SettingsView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 2CA319F72BC9878A0071176E /* AdditionalExamples */ = { + isa = PBXGroup; + children = ( + 2CA319F82BC9878A0071176E /* Constants.swift */, + 2CA319F92BC9878A0071176E /* ExampleContainerViewController.swift */, + 2CA319FA2BC9878A0071176E /* Assets.xcassets */, + 2CA319FB2BC9878A0071176E /* LaunchScreen.storyboard */, + 2CA319FD2BC9878A0071176E /* Main.storyboard */, + 2CA319FF2BC9878A0071176E /* Examples */, + 2CA31A0D2BC9878A0071176E /* ExampleTableViewController.swift */, + 2CA31A0E2BC9878A0071176E /* AppDelegate.swift */, + 2CA31A0F2BC9878A0071176E /* Info.plist */, + 2CA31A102BC9878A0071176E /* SceneDelegate.swift */, + ); + path = AdditionalExamples; + sourceTree = ""; + }; + 2CA319FF2BC9878A0071176E /* Examples */ = { + isa = PBXGroup; + children = ( + 2CA31A002BC9878A0071176E /* Styled-UI-Elements.swift */, + 2CA31A012BC9878A0071176E /* History-Recording.swift */, + 2CA31A022BC9878A0071176E /* Advanced.swift */, + 2CA31A032BC9878A0071176E /* Custom-Voice-Controller.swift */, + 2CA31A042BC9878A0071176E /* Offline-Regions.swift */, + 2CA31A052BC9878A0071176E /* Embedded-Navigation.swift */, + 2CA31A062BC9878A0071176E /* Basic.swift */, + 2CA31A072BC9878A0071176E /* EmbeddedExamples.storyboard */, + 2CA31A082BC9878A0071176E /* Beta-Query-Parameters.swift */, + 2CA31A092BC9878A0071176E /* CustomBars */, + ); + path = Examples; + sourceTree = ""; + }; + 2CA31A092BC9878A0071176E /* CustomBars */ = { + isa = PBXGroup; + children = ( + 2CA31A0A2BC9878A0071176E /* CustomBottomBannerView.xib */, + 2CA31A0B2BC9878A0071176E /* CustomBarsViewController.swift */, + 2CA31A0C2BC9878A0071176E /* CustomBottomBannerView.swift */, + ); + path = CustomBars; + sourceTree = ""; + }; + 2CA31A792BC9927D0071176E /* UIKitExample */ = { + isa = PBXGroup; + children = ( + 2CA31A7B2BC9927D0071176E /* LaunchScreen.storyboard */, + 2CA31A7D2BC9927D0071176E /* Extensions */, + 2CA31A842BC9927D0071176E /* AppDelegate.swift */, + 2CA31A852BC9927D0071176E /* Transitions */, + 2CA31A892BC9927D0071176E /* Info.plist */, + 2CA31A8A2BC9927D0071176E /* SceneDelegate.swift */, + ); + path = UIKitExample; + sourceTree = ""; + }; + 2CA31A7D2BC9927D0071176E /* Extensions */ = { + isa = PBXGroup; + children = ( + 2CA31A7E2BC9927D0071176E /* NavigationView+CameraOptions.swift */, + 2CA31A7F2BC9927D0071176E /* SceneDelegate+PreviewViewControllerDelegate.swift */, + 2CA31A802BC9927D0071176E /* SceneDelegate+BannerDismissalViewControllerDelegate.swift */, + 2CA31A812BC9927D0071176E /* SceneDelegate+DestinationPreviewViewControllerDelegate.swift */, + 2CA31A822BC9927D0071176E /* SceneDelegate+NavigationViewControllerDelegate.swift */, + 2CA31A832BC9927D0071176E /* SceneDelegate+RoutesPreviewViewControllerDelegate.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 2CA31A852BC9927D0071176E /* Transitions */ = { + isa = PBXGroup; + children = ( + 2CA31A862BC9927D0071176E /* SceneDelegate+UIViewControllerTransitioningDelegate.swift */, + 2CA31A872BC9927D0071176E /* DismissalAnimator.swift */, + 2CA31A882BC9927D0071176E /* PresentationAnimator.swift */, + ); + path = Transitions; + sourceTree = ""; + }; + 2CE469052BA31C1F0075A32B = { + isa = PBXGroup; + children = ( + 2CA31A792BC9927D0071176E /* UIKitExample */, + 2CA319F72BC9878A0071176E /* AdditionalExamples */, + 2CE469102BA31C1F0075A32B /* CoreSDKExample */, + DF92974F2BBD4A910047329A /* mapbox-navigation-ios */, + 2CE4690F2BA31C1F0075A32B /* Products */, + 2C6A3C762BA389D90039BBC9 /* Frameworks */, + ); + sourceTree = ""; + }; + 2CE4690F2BA31C1F0075A32B /* Products */ = { + isa = PBXGroup; + children = ( + 2CE4690E2BA31C1F0075A32B /* CoreSDKExample.app */, + 2CA319F52BC986EA0071176E /* AdditionalExamples.app */, + 2CA31A722BC991C80071176E /* UIKitExample.app */, + ); + name = Products; + sourceTree = ""; + }; + 2CE469102BA31C1F0075A32B /* CoreSDKExample */ = { + isa = PBXGroup; + children = ( + 2C6A3C7E2BA478FC0039BBC9 /* Views */, + 2C6A3C7D2BA478EC0039BBC9 /* SupportingFiles */, + 2C6A3C792BA3AE780039BBC9 /* Navigation.swift */, + 2CE469112BA31C1F0075A32B /* CoreSDKExampleApp.swift */, + ); + path = CoreSDKExample; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2CA319E22BC986EA0071176E /* AdditionalExamples */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2CA319F22BC986EA0071176E /* Build configuration list for PBXNativeTarget "AdditionalExamples" */; + buildPhases = ( + 2CA319E42BC986EA0071176E /* Sources */, + 2CA319EC2BC986EA0071176E /* Frameworks */, + 2CA319EE2BC986EA0071176E /* Resources */, + 2CA319F02BC986EA0071176E /* Embed Frameworks */, + 2CA319F12BC986EA0071176E /* Apply Mapbox Tokens */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AdditionalExamples; + packageProductDependencies = ( + 2C72A2CD2BC99C090097715C /* MapboxNavigationCore */, + 2C72A2CF2BC99C090097715C /* MapboxNavigationUIKit */, + ); + productName = CoreSDKExample; + productReference = 2CA319F52BC986EA0071176E /* AdditionalExamples.app */; + productType = "com.apple.product-type.application"; + }; + 2CA31A612BC991C80071176E /* UIKitExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2CA31A6F2BC991C80071176E /* Build configuration list for PBXNativeTarget "UIKitExample" */; + buildPhases = ( + 2CA31A622BC991C80071176E /* Sources */, + 2CA31A6A2BC991C80071176E /* Frameworks */, + 2CA31A6B2BC991C80071176E /* Resources */, + 2CA31A6D2BC991C80071176E /* Embed Frameworks */, + 2CA31A6E2BC991C80071176E /* Apply Mapbox Tokens */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UIKitExample; + packageProductDependencies = ( + 2CA31A9A2BC992DB0071176E /* MapboxNavigationCore */, + 2CA31A9C2BC992DB0071176E /* MapboxNavigationUIKit */, + 2CA31A9F2BC994060071176E /* MapboxGeocoder */, + ); + productName = CoreSDKExample; + productReference = 2CA31A722BC991C80071176E /* UIKitExample.app */; + productType = "com.apple.product-type.application"; + }; + 2CE4690D2BA31C1F0075A32B /* CoreSDKExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2CE4691C2BA31C200075A32B /* Build configuration list for PBXNativeTarget "CoreSDKExample" */; + buildPhases = ( + 2CE4690A2BA31C1F0075A32B /* Sources */, + 2CE4690B2BA31C1F0075A32B /* Frameworks */, + 2CE4690C2BA31C1F0075A32B /* Resources */, + DF4660812BBC75C400A0B2E4 /* Embed Frameworks */, + 2CE4691F2BA31C8F0075A32B /* Apply Mapbox Tokens */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CoreSDKExample; + packageProductDependencies = ( + 2C72A2CB2BC99C050097715C /* MapboxNavigationCore */, + ); + productName = CoreSDKExample; + productReference = 2CE4690E2BA31C1F0075A32B /* CoreSDKExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2CE469062BA31C1F0075A32B /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1530; + TargetAttributes = { + 2CE4690D2BA31C1F0075A32B = { + CreatedOnToolsVersion = 15.3; + }; + }; + }; + buildConfigurationList = 2CE469092BA31C1F0075A32B /* Build configuration list for PBXProject "Examples" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 2CE469052BA31C1F0075A32B; + packageReferences = ( + 2CA31A9E2BC994060071176E /* XCRemoteSwiftPackageReference "mapboxgeocoder" */, + ); + productRefGroup = 2CE4690F2BA31C1F0075A32B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2CE4690D2BA31C1F0075A32B /* CoreSDKExample */, + 2CA319E22BC986EA0071176E /* AdditionalExamples */, + 2CA31A612BC991C80071176E /* UIKitExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2CA319EE2BC986EA0071176E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA31A142BC9878A0071176E /* LaunchScreen.storyboard in Resources */, + 2CA31A132BC9878A0071176E /* Assets.xcassets in Resources */, + 2CA31A1F2BC9878A0071176E /* CustomBottomBannerView.xib in Resources */, + 2CA319EF2BC986EA0071176E /* Assets.xcassets in Resources */, + 2CA31A1D2BC9878A0071176E /* EmbeddedExamples.storyboard in Resources */, + 2CA31A152BC9878A0071176E /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2CA31A6B2BC991C80071176E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA31A8C2BC9927D0071176E /* LaunchScreen.storyboard in Resources */, + 2CA31A992BC9929A0071176E /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2CE4690C2BA31C1F0075A32B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CE469162BA31C200075A32B /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2CA319F12BC986EA0071176E /* Apply Mapbox Tokens */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)", + ); + name = "Apply Mapbox Tokens"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "$SRCROOT/Scripts/apply-mapbox-access-token.sh\n"; + showEnvVarsInLog = 0; + }; + 2CA31A6E2BC991C80071176E /* Apply Mapbox Tokens */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)", + ); + name = "Apply Mapbox Tokens"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "$SRCROOT/Scripts/apply-mapbox-access-token.sh\n"; + showEnvVarsInLog = 0; + }; + 2CE4691F2BA31C8F0075A32B /* Apply Mapbox Tokens */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)", + ); + name = "Apply Mapbox Tokens"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "$SRCROOT/Scripts/apply-mapbox-access-token.sh\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2CA319E42BC986EA0071176E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA31A222BC9878A0071176E /* ExampleTableViewController.swift in Sources */, + 2CA31A1B2BC9878A0071176E /* Embedded-Navigation.swift in Sources */, + 2CA31A162BC9878A0071176E /* Styled-UI-Elements.swift in Sources */, + 2CA31A252BC9878A0071176E /* SceneDelegate.swift in Sources */, + 2CA31A1C2BC9878A0071176E /* Basic.swift in Sources */, + 2CA31A192BC9878A0071176E /* Custom-Voice-Controller.swift in Sources */, + 2CA31A212BC9878A0071176E /* CustomBottomBannerView.swift in Sources */, + 2CA31A172BC9878A0071176E /* History-Recording.swift in Sources */, + 2CA31A1E2BC9878A0071176E /* Beta-Query-Parameters.swift in Sources */, + 2CA31A122BC9878A0071176E /* ExampleContainerViewController.swift in Sources */, + 2CA31A112BC9878A0071176E /* Constants.swift in Sources */, + 2CA31A182BC9878A0071176E /* Advanced.swift in Sources */, + 2CA31A232BC9878A0071176E /* AppDelegate.swift in Sources */, + 2CA31A1A2BC9878A0071176E /* Offline-Regions.swift in Sources */, + 2CA31A202BC9878A0071176E /* CustomBarsViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2CA31A622BC991C80071176E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA31A912BC9927D0071176E /* SceneDelegate+NavigationViewControllerDelegate.swift in Sources */, + 2CA31A952BC9927D0071176E /* DismissalAnimator.swift in Sources */, + 2CA31A962BC9927D0071176E /* PresentationAnimator.swift in Sources */, + 2CA31A942BC9927D0071176E /* SceneDelegate+UIViewControllerTransitioningDelegate.swift in Sources */, + 2CA31A8F2BC9927D0071176E /* SceneDelegate+BannerDismissalViewControllerDelegate.swift in Sources */, + 2CA31A902BC9927D0071176E /* SceneDelegate+DestinationPreviewViewControllerDelegate.swift in Sources */, + 2CA31A8E2BC9927D0071176E /* SceneDelegate+PreviewViewControllerDelegate.swift in Sources */, + 2CA31A982BC9927D0071176E /* SceneDelegate.swift in Sources */, + 2CA31A932BC9927D0071176E /* AppDelegate.swift in Sources */, + 2CA31A922BC9927D0071176E /* SceneDelegate+RoutesPreviewViewControllerDelegate.swift in Sources */, + 2CA31A8D2BC9927D0071176E /* NavigationView+CameraOptions.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2CE4690A2BA31C1F0075A32B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA31A742BC9925B0071176E /* SettingsView.swift in Sources */, + 2CA31A772BC9925B0071176E /* MapView.swift in Sources */, + 2CA31A762BC9925B0071176E /* ContentView.swift in Sources */, + 2C6A3C7A2BA3AE780039BBC9 /* Navigation.swift in Sources */, + 2CE469122BA31C1F0075A32B /* CoreSDKExampleApp.swift in Sources */, + 2CA31A782BC9925B0071176E /* NavigationControlsView.swift in Sources */, + 2CA31A752BC9925B0071176E /* MapViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 2CA319FB2BC9878A0071176E /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2CA319FC2BC9878A0071176E /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 2CA319FD2BC9878A0071176E /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2CA319FE2BC9878A0071176E /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 2CA31A7B2BC9927D0071176E /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2CA31A7C2BC9927D0071176E /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2CA319F32BC986EA0071176E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GJZR2MEM28; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AdditionalExamples/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Get the user location for navigation purposes."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.navigation.AdditionalExamples; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2CA319F42BC986EA0071176E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GJZR2MEM28; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AdditionalExamples/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Get the user location for navigation purposes."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.navigation.AdditionalExamples; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 2CA31A702BC991C80071176E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GJZR2MEM28; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = UIKitExample/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.navigation.UIKitExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2CA31A712BC991C80071176E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GJZR2MEM28; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = UIKitExample/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.navigation.UIKitExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 2CE4691A2BA31C200075A32B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_TREAT_WARNINGS_AS_ERRORS = YES; + }; + name = Debug; + }; + 2CE4691B2BA31C200075A32B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_TREAT_WARNINGS_AS_ERRORS = YES; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 2CE4691D2BA31C200075A32B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GJZR2MEM28; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = CoreSDKExample/SupportingFiles/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.navigation.CoreSDKExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2CE4691E2BA31C200075A32B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GJZR2MEM28; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = CoreSDKExample/SupportingFiles/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "Get user location"; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Get user location"; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.navigation.CoreSDKExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2CA319F22BC986EA0071176E /* Build configuration list for PBXNativeTarget "AdditionalExamples" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CA319F32BC986EA0071176E /* Debug */, + 2CA319F42BC986EA0071176E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2CA31A6F2BC991C80071176E /* Build configuration list for PBXNativeTarget "UIKitExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CA31A702BC991C80071176E /* Debug */, + 2CA31A712BC991C80071176E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2CE469092BA31C1F0075A32B /* Build configuration list for PBXProject "Examples" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CE4691A2BA31C200075A32B /* Debug */, + 2CE4691B2BA31C200075A32B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2CE4691C2BA31C200075A32B /* Build configuration list for PBXNativeTarget "CoreSDKExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CE4691D2BA31C200075A32B /* Debug */, + 2CE4691E2BA31C200075A32B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 2CA31A9E2BC994060071176E /* XCRemoteSwiftPackageReference "mapboxgeocoder" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/mapbox/mapboxgeocoder.swift"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.14.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 2C72A2CB2BC99C050097715C /* MapboxNavigationCore */ = { + isa = XCSwiftPackageProductDependency; + productName = MapboxNavigationCore; + }; + 2C72A2CD2BC99C090097715C /* MapboxNavigationCore */ = { + isa = XCSwiftPackageProductDependency; + productName = MapboxNavigationCore; + }; + 2C72A2CF2BC99C090097715C /* MapboxNavigationUIKit */ = { + isa = XCSwiftPackageProductDependency; + productName = MapboxNavigationUIKit; + }; + 2CA31A9A2BC992DB0071176E /* MapboxNavigationCore */ = { + isa = XCSwiftPackageProductDependency; + productName = MapboxNavigationCore; + }; + 2CA31A9C2BC992DB0071176E /* MapboxNavigationUIKit */ = { + isa = XCSwiftPackageProductDependency; + productName = MapboxNavigationUIKit; + }; + 2CA31A9F2BC994060071176E /* MapboxGeocoder */ = { + isa = XCSwiftPackageProductDependency; + package = 2CA31A9E2BC994060071176E /* XCRemoteSwiftPackageReference "mapboxgeocoder" */; + productName = MapboxGeocoder; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 2CE469062BA31C1F0075A32B /* Project object */; +} diff --git a/Examples/Examples.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Examples/Examples.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000000..919434a6254 --- /dev/null +++ b/Examples/Examples.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000000..f58edfcb87d --- /dev/null +++ b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,32 @@ +{ + "pins" : [ + { + "identity" : "mapbox-common-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mapbox/mapbox-common-ios.git", + "state" : { + "revision" : "15aed0b292a0fe0672113c1b69be04bd350c8bb3", + "version" : "24.3.1" + } + }, + { + "identity" : "mapbox-navigation-native-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mapbox/mapbox-navigation-native-ios.git", + "state" : { + "revision" : "07c5743dfd8283badae9020d4c47c0e7f9d605c3", + "version" : "305.0.0" + } + }, + { + "identity" : "mapboxgeocoder.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mapbox/mapboxgeocoder.swift", + "state" : { + "revision" : "10c497840c9e1142194563f402ddc903310a935d", + "version" : "0.15.0" + } + } + ], + "version" : 2 +} diff --git a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/AdditionalExamples.xcscheme b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/AdditionalExamples.xcscheme new file mode 100644 index 00000000000..6b018ea4f07 --- /dev/null +++ b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/AdditionalExamples.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/CoreSDKExample.xcscheme b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/CoreSDKExample.xcscheme new file mode 100644 index 00000000000..5a72ae11e20 --- /dev/null +++ b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/CoreSDKExample.xcscheme @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/UIKitExample.xcscheme b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/UIKitExample.xcscheme new file mode 100644 index 00000000000..a1b8ab49110 --- /dev/null +++ b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/UIKitExample.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Package.swift b/Examples/Package.swift new file mode 100644 index 00000000000..bcbdbf1bdbd --- /dev/null +++ b/Examples/Package.swift @@ -0,0 +1,8 @@ +import PackageDescription + +// This empty Swift package is used to exclude its parent folder from MapboxNavigation package source-tree. +let package = Package( + name: "", + products: [], + targets: [] +) diff --git a/Examples/Scripts/apply-mapbox-access-token.sh b/Examples/Scripts/apply-mapbox-access-token.sh new file mode 100755 index 00000000000..0ec8e3b7c71 --- /dev/null +++ b/Examples/Scripts/apply-mapbox-access-token.sh @@ -0,0 +1,14 @@ +# This script helps to keep the navigation SDK’s developers from exposing their own access tokens during development. +# See for more information. If you are developing an application privately, +# you may add the MBXAccessToken key directly to your Info.plist file and delete Apply Mapbox Access Token +# Run Script Phase in Build Phases. +token_file=~/.mapbox +token_file2=~/mapbox +token="$(cat $token_file 2>/dev/null || cat $token_file2 2>/dev/null)" +if [ "$token" ]; then + plutil -replace MBXAccessToken -string $token "$TARGET_BUILD_DIR/$INFOPLIST_PATH" +else + echo 'warning: Missing Mapbox access token' + open 'https://www.mapbox.com/account/access-tokens/' + echo "warning: Get an access token from , then create a new file at $token_file or $token_file2 that contains the access token." +fi diff --git a/Examples/UIKitExample/AppDelegate.swift b/Examples/UIKitExample/AppDelegate.swift new file mode 100644 index 00000000000..ee6af8d4ec4 --- /dev/null +++ b/Examples/UIKitExample/AppDelegate.swift @@ -0,0 +1,26 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + // Request authorization to user notifications to be able to list application in + // iOS settings menu. + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in + // No-op + } + + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions) -> UISceneConfiguration { + return UISceneConfiguration(name: "Default Configuration", + sessionRole: connectingSceneSession.role) + } +} diff --git a/Examples/UIKitExample/Assets.xcassets/AccentColor.colorset/Contents.json b/Examples/UIKitExample/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000000..eb878970081 --- /dev/null +++ b/Examples/UIKitExample/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/UIKitExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/UIKitExample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..9221b9bb1a3 --- /dev/null +++ b/Examples/UIKitExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/UIKitExample/Assets.xcassets/Contents.json b/Examples/UIKitExample/Assets.xcassets/Contents.json new file mode 100644 index 00000000000..73c00596a7f --- /dev/null +++ b/Examples/UIKitExample/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/UIKitExample/Base.lproj/LaunchScreen.storyboard b/Examples/UIKitExample/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000000..f25e499e746 --- /dev/null +++ b/Examples/UIKitExample/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/UIKitExample/Extensions/NavigationView+CameraOptions.swift b/Examples/UIKitExample/Extensions/NavigationView+CameraOptions.swift new file mode 100644 index 00000000000..b5554a373d6 --- /dev/null +++ b/Examples/UIKitExample/Extensions/NavigationView+CameraOptions.swift @@ -0,0 +1,34 @@ +import MapboxNavigationUIKit +import UIKit + +extension NavigationView { + + func configureViewportPadding() { + navigationMapView.viewportPadding = previewCameraPadding() + } + + private func previewCameraPadding() -> UIEdgeInsets { + let topInset: CGFloat + let bottomInset: CGFloat + let leftInset: CGFloat + let rightInset: CGFloat + let spacing = 50.0 + + if traitCollection.verticalSizeClass == .regular { + topInset = topBannerContainerView.frame.height + bottomInset = bottomBannerContainerView.frame.height + leftInset = 0 + rightInset = 0 + } else { + topInset = 0 + bottomInset = 0 + leftInset = bottomBannerContainerView.frame.width + rightInset = 0 + } + + return UIEdgeInsets(top: topInset + spacing, + left: leftInset + spacing, + bottom: bottomInset + spacing, + right: rightInset + spacing) + } +} diff --git a/Examples/UIKitExample/Extensions/SceneDelegate+BannerDismissalViewControllerDelegate.swift b/Examples/UIKitExample/Extensions/SceneDelegate+BannerDismissalViewControllerDelegate.swift new file mode 100644 index 00000000000..eeb0a012e3f --- /dev/null +++ b/Examples/UIKitExample/Extensions/SceneDelegate+BannerDismissalViewControllerDelegate.swift @@ -0,0 +1,24 @@ +import MapboxNavigationUIKit + +// MARK: - BannerDismissalViewControllerDelegate methods + +extension SceneDelegate: BannerDismissalViewControllerDelegate { + + func didTapDismissBannerButton(_ bannerDismissalViewController: BannerDismissalViewController) { + previewViewController.dismissBanner(at: .bottomLeading, + animated: shouldAnimate, + duration: animationDuration) + + // In case if there are no more bottom banners - dismiss top banner as well. + if previewViewController.topBanner(at: .bottomLeading) == nil { + previewViewController.dismissBanner(at: .topLeading, + animated: shouldAnimate, + duration: animationDuration, + animations: { + self.previewViewController.navigationView.topBannerContainerView.alpha = 0.0 + }, completion: { + self.previewViewController.navigationView.topBannerContainerView.alpha = 1.0 + }) + } + } +} diff --git a/Examples/UIKitExample/Extensions/SceneDelegate+DestinationPreviewViewControllerDelegate.swift b/Examples/UIKitExample/Extensions/SceneDelegate+DestinationPreviewViewControllerDelegate.swift new file mode 100644 index 00000000000..9856781f032 --- /dev/null +++ b/Examples/UIKitExample/Extensions/SceneDelegate+DestinationPreviewViewControllerDelegate.swift @@ -0,0 +1,45 @@ +import MapboxNavigationUIKit +import MapboxNavigationCore +import CoreLocation + +// MARK: - DestinationPreviewViewControllerDelegate methods + +extension SceneDelegate: DestinationPreviewViewControllerDelegate { + + func didTapPreviewRoutesButton(_ destinationPreviewViewController: DestinationPreviewViewController) { + guard let destinationPreviewViewController = previewViewController.topBanner(at: .bottomLeading) as? DestinationPreviewViewController else { + return + } + + Task { [weak self] in + guard let self, + let routes = await self.requestRoute(between: destinationPreviewViewController.destinationOptions.coordinates) else { + return + } + + self.preview(routes, animated: self.shouldAnimate, duration: self.animationDuration) + } + } + + func didTapBeginActiveNavigationButton(_ destinationPreviewViewController: DestinationPreviewViewController) { + Task { [weak self] in + guard let self, + let routes = await self.requestRoute(between: destinationPreviewViewController.destinationOptions.coordinates) else { + return + } + + self.previewViewController.navigationView.navigationMapView.show(routes, routeAnnotationKinds: [.relativeDurationsOnAlternative]) + self.startActiveNavigation(for: routes) + } + } + + private func requestRoute(between coordinates: [CLLocationCoordinate2D]) async -> NavigationRoutes? { + do { + let navigationRouteOptions = NavigationRouteOptions(coordinates: coordinates) + return try await navigationProvider.routingProvider().calculateRoutes(options: navigationRouteOptions).value + } catch { + print("Error occured while requesting routes: \(error.localizedDescription)") + return nil + } + } +} diff --git a/Examples/UIKitExample/Extensions/SceneDelegate+NavigationViewControllerDelegate.swift b/Examples/UIKitExample/Extensions/SceneDelegate+NavigationViewControllerDelegate.swift new file mode 100644 index 00000000000..7abcf8fbf45 --- /dev/null +++ b/Examples/UIKitExample/Extensions/SceneDelegate+NavigationViewControllerDelegate.swift @@ -0,0 +1,53 @@ +import MapboxNavigationUIKit +import UIKit + +extension SceneDelegate: NavigationViewControllerDelegate { + + public func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, + byCanceling canceled: Bool) { + // Hide top and bottom banner containers and after that dismiss `NavigationViewController`. + navigationViewController.navigationView.topBannerContainerView.hide(animated: shouldAnimate, + duration: animationDuration, + animations: { + navigationViewController.navigationView.topBannerContainerView.alpha = 0.0 + }) + + navigationViewController.navigationView.bottomBannerContainerView.hide(animated: shouldAnimate, + duration: animationDuration, + animations: { + navigationViewController.navigationView.bottomBannerContainerView.alpha = 0.0 + navigationViewController.navigationView.speedLimitView.alpha = 0.0 + navigationViewController.navigationView.wayNameView.alpha = 0.0 + navigationViewController.navigationView.floatingStackView.alpha = 0.0 + }, + completion: { _ in + navigationViewController.dismiss(animated: true) { [weak self] in + guard let self = self else { return } + + let navigationView = self.previewViewController.navigationView + let navigationMapView = navigationView.navigationMapView + + navigationMapView.delegate = self + + navigationMapView.removeRoutes() + + self.showcase(navigationRoutes: navigationViewController.navigationRoutes!, + animated: self.shouldAnimate, + duration: self.animationDuration) + + navigationView.topBannerContainerView.show(animated: self.shouldAnimate, + duration: self.animationDuration, + animations: { + navigationView.topBannerContainerView.alpha = 1.0 + }) + + navigationView.bottomBannerContainerView.show(animated: self.shouldAnimate, + duration: self.animationDuration, + animations: { + navigationView.floatingStackView.alpha = 1.0 + navigationView.bottomBannerContainerView.alpha = 1.0 + }) + } + }) + } +} diff --git a/Examples/UIKitExample/Extensions/SceneDelegate+PreviewViewControllerDelegate.swift b/Examples/UIKitExample/Extensions/SceneDelegate+PreviewViewControllerDelegate.swift new file mode 100644 index 00000000000..cd1ff44c4b1 --- /dev/null +++ b/Examples/UIKitExample/Extensions/SceneDelegate+PreviewViewControllerDelegate.swift @@ -0,0 +1,207 @@ +import CoreLocation +import MapboxGeocoder +import MapboxNavigationUIKit +import MapboxNavigationCore + +// MARK: - NavigationMapViewDelegate methods + +extension SceneDelegate: NavigationMapViewDelegate { + + func navigationMapView(_ navigationMapView: NavigationMapView, didSelect alternativeRoute: AlternativeRoute) { + guard let routePreviewViewController = previewViewController.topBanner(at: .bottomLeading) as? RoutePreviewViewController else { + return + } + + previewViewController.dismissBanner(at: .bottomLeading, + animated: false) + Task { [weak self] in + guard let previewRoutes = await routePreviewViewController.routePreviewOptions.navigationRoutes + .selecting(alternativeRoute: alternativeRoute) else { return } + self?.preview(previewRoutes, animated: false) + } + + } + + func navigationMapView(_ navigationMapView: NavigationMapView, userDidLongTap mapPoint: MapPoint) { + guard let originCoordinate = navigationMapView.mapView.location.latestLocation?.coordinate else { return } + + let destinationCoordinate = mapPoint.coordinate + let coordinates = [ + originCoordinate, + destinationCoordinate, + ] + + let topmostBottomBanner = previewViewController.topBanner(at: .bottomLeading) + + // In case if `RoutePreviewViewController` is shown - don't do anything. + if topmostBottomBanner is RoutePreviewViewController { + return + } + + // In case if `DestinationPreviewViewController` is shown - dismiss it and after that show new one. + if topmostBottomBanner is DestinationPreviewViewController { + previewViewController.dismissBanner(at: .bottomLeading, + animated: false) + preview(coordinates, + animated: false) + } else { + if shouldAnimate { + previewViewController.navigationView.topBannerContainerView.alpha = 0.0 + previewViewController.navigationView.bottomBannerContainerView.alpha = 0.0 + } + + preview(coordinates, + animated: shouldAnimate, + duration: animationDuration, + animations: { [self] in + self.previewViewController.navigationView.topBannerContainerView.alpha = 1.0 + self.previewViewController.navigationView.bottomBannerContainerView.alpha = 1.0 + }) + } + } +} + +// MARK: - PreviewViewControllerDelegate methods + +extension SceneDelegate: PreviewViewControllerDelegate { + + func previewViewController(_ previewViewController: PreviewViewController, + willPresent banner: Banner) { + guard let destinationPreviewViewController = banner as? DestinationPreviewViewController, + let destinationCoordinate = destinationPreviewViewController.destinationOptions.coordinates.last else { + return + } + + // While presenting `DestinationPreviewViewController` - override its initial primary text + // to reverse-geocoded name. + reverseGeocode(destinationCoordinate) { placemarkName in + destinationPreviewViewController.destinationOptions.primaryText = NSAttributedString(string: placemarkName) + } + + previewViewController.navigationView.wayNameView.isHidden = true + previewViewController.navigationView.speedLimitView.isAlwaysHidden = true + previewViewController.navigationView.navigationMapView.navigationCamera.stop() + } + + func previewViewController(_ previewViewController: PreviewViewController, + didPresent banner: Banner) { + // No-op + } + + func previewViewController(_ previewViewController: PreviewViewController, + willDismiss banner: Banner) { + if banner is DestinationPreviewViewController { + // TODO: Implement the ability to remove final destination annotations. + previewViewController.navigationMapView.removeRoutes() + } else if banner is RoutePreviewViewController { + previewViewController.navigationMapView.removeRoutes() + } + } + + func previewViewController(_ previewViewController: PreviewViewController, + didDismiss banner: Banner) { + if previewViewController.topBanner(at: .bottomLeading) == nil { + previewViewController.navigationView.wayNameView.isHidden = false + previewViewController.navigationView.speedLimitView.isAlwaysHidden = false + } + } + + // MARK: - Helper methods + + func startActiveNavigation(for navigationRoutes: NavigationRoutes) { + previewViewController.navigationView.topBannerContainerView.hide(animated: shouldAnimate, + duration: animationDuration, + animations: { [weak self] in + guard let self = self else { return } + + self.previewViewController.navigationView.topBannerContainerView.alpha = 0.0 + }) + + previewViewController.navigationView.bottomBannerContainerView.hide(animated: shouldAnimate, + duration: animationDuration, + animations: { [weak self] in + guard let self = self else { return } + + self.previewViewController.navigationView.floatingStackView.alpha = 0.0 + self.previewViewController.navigationView.bottomBannerContainerView.alpha = 0.0 + }, completion: { [weak self] _ in + guard let self = self else { return } + + let navigationViewController = NavigationViewController( + navigationRoutes: navigationRoutes, + navigationOptions: NavigationOptions( + mapboxNavigation: self.navigationProvider, + voiceController: self.navigationProvider.routeVoiceController, + eventsManager: self.navigationProvider.eventsManager(), + styles: [NightStyle()], + predictiveCacheManager: self.navigationProvider.predictiveCacheManager + ) + ) + navigationViewController.modalPresentationStyle = .fullScreen + navigationViewController.transitioningDelegate = self + // Make `SceneDelegate` delegate of `NavigationViewController` to be notified about + // its dismissal. + navigationViewController.delegate = self + + self.previewViewController.present(navigationViewController, + animated: true, + completion: { [weak self] in + guard let self = self else { return } + + // Render part of the route that has been traversed with full transparency, to give the illusion of a disappearing route. + navigationViewController.routeLineTracksTraversal = true + + // Hide top and bottom container views before animating their presentation. + navigationViewController.navigationView.topBannerContainerView.hide(animated: false) + navigationViewController.navigationView.bottomBannerContainerView.hide(animated: false) + + if self.shouldAnimate { + navigationViewController.navigationView.speedLimitView.alpha = 0.0 + navigationViewController.navigationView.wayNameView.alpha = 0.0 + navigationViewController.navigationView.floatingStackView.alpha = 0.0 + navigationViewController.navigationView.topBannerContainerView.alpha = 0.0 + navigationViewController.navigationView.bottomBannerContainerView.alpha = 0.0 + } + + navigationViewController.navigationView.topBannerContainerView.show(animated: self.shouldAnimate, + duration: self.animationDuration, + animations: { + navigationViewController.navigationView.speedLimitView.alpha = 1.0 + navigationViewController.navigationView.wayNameView.alpha = 1.0 + navigationViewController.navigationView.floatingStackView.alpha = 1.0 + navigationViewController.navigationView.topBannerContainerView.alpha = 1.0 + }) + + navigationViewController.navigationView.bottomBannerContainerView.show(animated: self.shouldAnimate, + duration: self.animationDuration, + animations: { + navigationViewController.navigationView.bottomBannerContainerView.alpha = 1.0 + }) + }) + }) + } + + func reverseGeocode(_ coordinate: CLLocationCoordinate2D, + completion: @escaping (_ placemarkName: String) -> Void) { + let reverseGeocodeOptions = ReverseGeocodeOptions(coordinate: coordinate) + reverseGeocodeOptions.focalLocation = CLLocationManager().location + reverseGeocodeOptions.locale = Locale.autoupdatingCurrent.languageCode == "en" ? nil : .autoupdatingCurrent + reverseGeocodeOptions.allowedScopes = .all + reverseGeocodeOptions.maximumResultCount = 1 + reverseGeocodeOptions.includesRoutableLocations = true + + Geocoder.shared.geocode(reverseGeocodeOptions, completionHandler: { (placemarks, _, error) in + if let error = error { + print("Reverse geocoding failed with error: \(error.localizedDescription)") + return + } + + guard let placemark = placemarks?.first else { + print("Placemark was not found") + return + } + + completion(placemark.formattedName) + }) + } +} diff --git a/Examples/UIKitExample/Extensions/SceneDelegate+RoutesPreviewViewControllerDelegate.swift b/Examples/UIKitExample/Extensions/SceneDelegate+RoutesPreviewViewControllerDelegate.swift new file mode 100644 index 00000000000..3d4e0773036 --- /dev/null +++ b/Examples/UIKitExample/Extensions/SceneDelegate+RoutesPreviewViewControllerDelegate.swift @@ -0,0 +1,10 @@ +import MapboxNavigationUIKit + +// MARK: - RoutePreviewViewControllerDelegate methods + +extension SceneDelegate: RoutePreviewViewControllerDelegate { + + func didPressBeginActiveNavigationButton(_ routePreviewViewController: RoutePreviewViewController) { + startActiveNavigation(for: routePreviewViewController.routePreviewOptions.navigationRoutes) + } +} diff --git a/Examples/UIKitExample/Info.plist b/Examples/UIKitExample/Info.plist new file mode 100644 index 00000000000..ba5d8e00e46 --- /dev/null +++ b/Examples/UIKitExample/Info.plist @@ -0,0 +1,34 @@ + + + + + MBXAccessToken + PASTE MAPBOX ACCESS TOKEN HERE + MGLMapboxMetricsEnabledSettingShownInApp + YES + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + UIBackgroundModes + + audio + location + + UILaunchScreen + + + diff --git a/Examples/UIKitExample/SceneDelegate.swift b/Examples/UIKitExample/SceneDelegate.swift new file mode 100644 index 00000000000..5907d09d25b --- /dev/null +++ b/Examples/UIKitExample/SceneDelegate.swift @@ -0,0 +1,114 @@ +import UIKit +import CoreLocation +import MapboxNavigationUIKit +import MapboxNavigationCore +import MapboxDirections +import MapboxMaps + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + var previewViewController: PreviewViewController! + + let shouldAnimate = true + + let animationDuration = 0.5 + let navigationProvider = MapboxNavigationProvider(coreConfig: CoreConfig()) + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let windowScene = (scene as? UIWindowScene) else { return } + + window = UIWindow(windowScene: windowScene) + + previewViewController = PreviewViewController( + PreviewOptions( + locationMatching: navigationProvider.navigation().locationMatching, + routeProgress: navigationProvider.navigation().routeProgress + .map(\.?.routeProgress) + .eraseToAnyPublisher(), + predictiveCacheManager: navigationProvider.predictiveCacheManager + ) + ) + navigationProvider.tripSession().startFreeDrive() + previewViewController.delegate = self + previewViewController.navigationMapView.delegate = self + + window?.rootViewController = previewViewController + window?.makeKeyAndVisible() + } + + // MARK: - Gesture recognizers and presentation methods + + func presentBannerDismissalViewControllerIfNeeded(_ animated: Bool, + duration: TimeInterval) { + if previewViewController.topBanner(at: .topLeading) is BannerDismissalViewController { + return + } + + let bannerDismissalViewController = BannerDismissalViewController() + bannerDismissalViewController.delegate = self + previewViewController.present(bannerDismissalViewController, + animated: animated, + duration: duration) + } + + func preview(_ coordinates: [CLLocationCoordinate2D], + animated: Bool = true, + duration: TimeInterval = 1.0, + animations: (() -> Void)? = nil, + completion: (() -> Void)? = nil) { + if coordinates.isEmpty { + preconditionFailure("Waypoints array should not be empty.") + } + + let destinationOptions = DestinationOptions(coordinates: coordinates) + let destinationPreviewViewController = DestinationPreviewViewController(destinationOptions) + destinationPreviewViewController.delegate = self + previewViewController.present(destinationPreviewViewController, + animated: animated, + duration: duration, + animations: animations, + completion: { + completion?() + }) + + presentBannerDismissalViewControllerIfNeeded(animated, + duration: duration) + + // TODO: Implement the ability to add final destination annotations. + } + + func preview(_ navigationRoutes: NavigationRoutes, + animated: Bool = true, + duration: TimeInterval = 1.0, + animations: (() -> Void)? = nil) { + let routePreviewOptions = RoutePreviewOptions(navigationRoutes: navigationRoutes, routeId: navigationRoutes.mainRoute.routeId) + let routePreviewViewController = RoutePreviewViewController(routePreviewOptions) + routePreviewViewController.delegate = self + previewViewController.present(routePreviewViewController, + animated: animated, + duration: duration, + animations: animations) + + presentBannerDismissalViewControllerIfNeeded(animated, + duration: duration) + + showcase(navigationRoutes: navigationRoutes, + animated: animated, + duration: duration) + } + + func showcase(navigationRoutes: NavigationRoutes, + animated: Bool = true, + duration: TimeInterval = 1.0) { + previewViewController.navigationView.configureViewportPadding() + previewViewController.navigationMapView.showcase( + navigationRoutes, + routesPresentationStyle: .all(shouldFit: true), + routeAnnotationKinds: [.relativeDurationsOnAlternative], + animated: animated, + duration: duration + ) + } +} diff --git a/Examples/UIKitExample/Transitions/DismissalAnimator.swift b/Examples/UIKitExample/Transitions/DismissalAnimator.swift new file mode 100644 index 00000000000..6edaf08649e --- /dev/null +++ b/Examples/UIKitExample/Transitions/DismissalAnimator.swift @@ -0,0 +1,25 @@ +import UIKit +import MapboxNavigationUIKit + +class DismissalAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return 0.0 + } + + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + guard let fromViewController = transitionContext.viewController(forKey: .from) as? NavigationViewController, + let navigationMapView = fromViewController.navigationMapView, + let toViewController = transitionContext.viewController(forKey: .to) as? PreviewViewController else { + transitionContext.completeTransition(false) + return + } + + // Transfer `NavigationMapView` that was used in `NavigationViewController` back to + // `PreviewViewController`. + toViewController.navigationMapView = navigationMapView + + transitionContext.containerView.addSubview(toViewController.view) + transitionContext.completeTransition(true) + } +} diff --git a/Examples/UIKitExample/Transitions/PresentationAnimator.swift b/Examples/UIKitExample/Transitions/PresentationAnimator.swift new file mode 100644 index 00000000000..3844953c66d --- /dev/null +++ b/Examples/UIKitExample/Transitions/PresentationAnimator.swift @@ -0,0 +1,24 @@ +import UIKit +import MapboxNavigationUIKit + +class PresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return 0.0 + } + + func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + guard let fromViewController = transitionContext.viewController(forKey: .from) as? PreviewViewController, + let toViewController = transitionContext.viewController(forKey: .to) as? NavigationViewController else { + transitionContext.completeTransition(false) + return + } + + // Replace default `NavigationMapView` in `NavigationViewController` with `NavigationMapView` + // that was used in `PreviewViewController`. + toViewController.navigationMapView = fromViewController.navigationMapView + + transitionContext.containerView.addSubview(toViewController.view) + transitionContext.completeTransition(true) + } +} diff --git a/Examples/UIKitExample/Transitions/SceneDelegate+UIViewControllerTransitioningDelegate.swift b/Examples/UIKitExample/Transitions/SceneDelegate+UIViewControllerTransitioningDelegate.swift new file mode 100644 index 00000000000..9b71dd6e6b9 --- /dev/null +++ b/Examples/UIKitExample/Transitions/SceneDelegate+UIViewControllerTransitioningDelegate.swift @@ -0,0 +1,14 @@ +import UIKit + +extension SceneDelegate: UIViewControllerTransitioningDelegate { + + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return DismissalAnimator() + } + + public func animationController(forPresented presented: UIViewController, + presenting: UIViewController, + source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return PresentationAnimator() + } +} diff --git a/Package.swift b/Package.swift index c597b109268..e9e73afd9e0 100644 --- a/Package.swift +++ b/Package.swift @@ -3,17 +3,16 @@ import PackageDescription -let version = "3.0.0-rc.1" +let version = "3.0.0" let binaries = [ - "MapboxCommon": "a8874af6acfafac0f5cf2c9a051967e4381bb7ed3707a44b9c6e6bef9d488456", - "MapboxCoreMaps": "e03cbb9f9c60dcaaa6f58b83d57d7796e95d5cd9ae4e47cc194b7c917c930e31", - "MapboxDirections": "974559a90d6aba462bb0527001456dc16ffd3ae506791cfd3d61fc986fe02d0e", - "MapboxMaps": "97485654d30264683df34e9cf0be5e4d09262759b3b1550ea21910172413e8fe", - "MapboxNavigationNative": "743b54c3cbb92f77458cf3c29278b863e0b30b745f737606a29fc980a839fb20", - "Turf": "2f5fffc7075f8582aca328f13b49e14cfb13d3ed1ee0789e53d657d827860b6f", - "MapboxNavigationCore": "17f52c9aa1d941638489a3f2d55e8184ce17012c8eee0156e86cdcfbdb4bf189", - "_MapboxNavigationUXPrivate": "1ee894eee848474826d5ab21761067d966e7343e0f436b985d21489fe6b2c3e2", + "MapboxCoreMaps": "2f514f7127673d21e6074b949f5ca224d3c847a82513ed247a4bb3d4e0c0c271", + "MapboxDirections": "fc246f668f167879d08f0de519d6884b1e9c01a77c641fd07fdce79fd316fe38", + "MapboxMaps": "3c8fee306569216b0cade7d27bb66e7138cca01eed34d738ebeb6f204e820be1", + "Turf": "595897f7f4117394c1b25f31c497feb539fc91b711099313c5cfc321b4bbfca8", + "MapboxNavigationCore": "d6b3dbdf80e2894b45a84898b4905b2ae6ec95b4cfb0812fa23f059fa3feaedb", + "_MapboxNavigationUXPrivate": "6dbb7a32a50464a2e4f5f0ab851ad03fbebf6c0fb8bcb9d660322529489f4806", + "MapboxNavigationUIKit": "06c550195001293b09e96a36fd4c42288cb97bd9f10ec1dfa9ad45eadff0b580", ] let package = Package( @@ -23,12 +22,29 @@ let package = Package( name: "MapboxNavigationCore", targets: ["MapboxNavigationCoreWrapper"] ), + .library( + name: "MapboxNavigationUIKit", + targets: ["MapboxNavigationUIKitWrapper"] + ), + ], + dependencies: [ + .package(url: "https://github.com/mapbox/mapbox-common-ios.git", exact: "24.3.1"), + .package(url: "https://github.com/mapbox/mapbox-navigation-native-ios.git", exact: "305.0.0"), ], targets: [ .target( name: "MapboxNavigationCoreWrapper", - dependencies: binaries.keys.map { .byName(name: $0) } - ) + dependencies: binaries.keys.map { .byName(name: $0) } + [ + .product(name: "MapboxCommon", package: "mapbox-common-ios"), + .product(name: "MapboxNavigationNative", package: "mapbox-navigation-native-ios"), + ] + ), + .target( + name: "MapboxNavigationUIKitWrapper", + dependencies: [ + "MapboxNavigationCoreWrapper" + ] + ), ] + binaryTargets() ) diff --git a/README.md b/README.md new file mode 100644 index 00000000000..3ad597c4390 --- /dev/null +++ b/README.md @@ -0,0 +1,152 @@ +# [Mapbox Navigation SDK for iOS](https://docs.mapbox.com/ios/navigation/) + +[![SPM compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://swift.org/package-manager/) + +Mapbox Navigation SDK + +Mapbox Navigation gives you all the tools you need to add turn-by-turn navigation to your iOS application. + +Get up and running in a few minutes with our drop-in turn-by-turn navigation `NavigationViewController`, or build a completely custom turn-by-turn navigation app with our core components for routing and navigation. + +## Features + +* A full-fledged turn-by-turn navigation UI for iPhone, iPad, and CarPlay that’s ready to drop into your application +* [Professionally designed map styles](https://www.mapbox.com/maps/) for daytime and nighttime driving +* Worldwide driving, cycling, and walking directions powered by [open data](https://www.mapbox.com/about/maps/) and user feedback +* Traffic avoidance and proactive rerouting based on current conditions in [over 55 countries](https://docs.mapbox.com/help/how-mapbox-works/directions/#traffic-data) +* Natural-sounding turn instructions +* [Support for over two dozen languages](https://docs.mapbox.com/ios/navigation/overview/localization-and-internationalization/) + +## [Documentation](https://docs.mapbox.com/ios/api/navigation/) + +## Requirements + +The Mapbox Navigation SDK and Core Navigation are compatible with applications written in Swift 5.9 in Xcode 15.0 and above. The Mapbox Navigation and Mapbox Core Navigation frameworks run on iOS 12.0 and above. + +The Mapbox Navigation SDK is also available [for Android](https://github.com/mapbox/mapbox-navigation-android/). + +## Installation + +### Using Swift Package Manager + +To install the MapboxNavigation framework in an application using [Swift Package Manager](https://swift.org/package-manager/): + +1. Go to your [Mapbox account dashboard](https://account.mapbox.com/) and create an access token that has the `DOWNLOADS:READ` scope. **PLEASE NOTE: This is not the same as your production Mapbox API token. Make sure to keep it private and do not insert it into any Info.plist file.** Create a file named `.netrc` in your home directory if it doesn’t already exist, then add the following lines to the end of the file: + ``` + machine api.mapbox.com + login mapbox + password PRIVATE_MAPBOX_API_TOKEN + ``` + where _PRIVATE_MAPBOX_API_TOKEN_ is your Mapbox API token with the `DOWNLOADS:READ` scope. + +1. In Xcode, go to File ‣ Swift Packages ‣ Add Package Dependency. + +1. Enter `https://github.com/mapbox/mapbox-navigation-ios.git` as the package repository and click Next. + +1. Set Rules to Version, Up to Next Major, and enter `3.0.0` as the minimum version requirement. Click Next. + +To install the MapboxNavigation framework in another package rather than an application, run `swift package init` to create a Package.swift, then add the following dependency: + +```swift +// Latest stable release +.package(name: "MapboxNavigation", url: "https://github.com/mapbox/mapbox-navigation-ios.git", from: "3.0.0") +// Latest prerelease +.package(name: "MapboxNavigation", url: "https://github.com/mapbox/mapbox-navigation-ios.git", .exact("2.18.0-rc.3")) +``` + +## Configuration + +1. Mapbox APIs and vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom iOS Target Properties” section, set `MBXAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://account.mapbox.com/access-tokens/). + +1. In order for the SDK to track the user’s location as they move along the route, set `NSLocationWhenInUseUsageDescription` to: + > Shows your location on the map and helps improve the map. + +1. Users expect the SDK to continue to track the user’s location and deliver audible instructions even while a different application is visible or the device is locked. Go to the Signing & Capabilities tab. Under the Background Modes section, enable “Audio, AirPlay, and Picture in Picture” and “Location updates”. (Alternatively, add the `audio` and `location` values to the `UIBackgroundModes` array in the Info tab.) + +Now import the relevant modules and present a new `NavigationViewController`. You can also [push to a navigation view controller from within a storyboard](https://docs.mapbox.com/ios/navigation/overview/storyboards/) if your application’s UI is laid out in Interface Builder. + +```swift +import MapboxDirections +import MapboxNavigationCore +import MapboxNavigationUIKit +``` + +```swift +// Define the Mapbox Navigation entry point. +let mapboxNavigationProvider = MapboxNavigationProvider(coreConfig: .init()) +lazy var mapboxNavigation = mapboxNavigationProvider.mapboxNavigation +``` + +```swift +// Define two waypoints to travel between +let origin = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox") +let destination = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House") + +// Set options +let routeOptions = NavigationRouteOptions(waypoints: [origin, destination]) + +// Request a route using RoutingProvider +let request = mapboxNavigation.routingProvider().calculateRoutes(options: options) +Task { + switch await request.result { + case .failure(let error): + print(error.localizedDescription) + case .success(let navigationRoutes): + // Pass the generated navigation routes to the the NavigationViewController + let navigationOptions = NavigationOptions(mapboxNavigation: mapboxNavigation, + voiceController: mapboxNavigationProvider.routeVoiceController, + eventsManager: mapboxNavigationProvider.eventsManager()) + let navigationViewController = NavigationViewController(navigationRoutes: navigationRoutes, + navigationOptions: navigationOptions) + navigationViewController.modalPresentationStyle = .fullScreen + + present(navigationViewController, animated: true, completion: nil) + } +} +``` + +Consult the [API reference](https://docs.mapbox.com/ios/api/navigation/) for further details. + +## Examples + +The [API reference](https://docs.mapbox.com/ios/api/navigation/) includes example code for accomplishing common tasks. + +This repository also contains [a testbed application](https://github.com/mapbox/mapbox-navigation-ios/tree/main/Example) that exercises a variety of navigation SDK features. See the [contributing guide](CONTRIBUTING.md#using-carthage) for instructions on installing and running this application. + +## Customization + +### Styling + +You can customize the appearance in order to blend in with the rest of your app. + +```swift +class CustomStandardDayStyle: StandardDayStyle { + required init() { + super.init() + mapStyleURL = URL(string: "mapbox://styles/mapbox/satellite-streets-v9")! + styleType = .nightStyle + } + + override func apply() { + super.apply() + BottomBannerView.appearance(for: UITraitCollection(userInterfaceIdiom: .phone)).backgroundColor = .orange + BottomBannerView.appearance(for: UITraitCollection(userInterfaceIdiom: .pad)).backgroundColor = .orange + } +} +``` + +then initialize `NavigationViewController` with your style or styles: + +```swift +let navigationOptions = NavigationOptions( + mapboxNavigation: navigationProvider.mapboxNavigation, + voiceController: navigationProvider.routeVoiceController, + eventsManager: navigationProvider.eventsManager(), + styles: [CustomStandardDayStyle()] + ) +NavigationViewController(navigationRoutes: navigationRoutes, navigationOptions: navigationOptions) +``` + +## License + +The Mapbox Navigation SDK for iOS is released under the Mapbox Terms of Service. See [LICENSE.md](./LICENSE.md) for details. diff --git a/Sources/MapboxNavigationUIKitWrapper/dummy.swift b/Sources/MapboxNavigationUIKitWrapper/dummy.swift new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/Sources/MapboxNavigationUIKitWrapper/dummy.swift @@ -0,0 +1 @@ +