Widget links maps:// directly so CarPlay can route to Apple Maps

- The widget now uses the native maps://?daddr= scheme for taps in both
  sizes. In CarPlay there is no containing app to relay through, but since
  Apple Maps IS a CarPlay app, the system may route the tap straight to
  Maps on the car display (WWDC25: widgets can launch apps in CarPlay).
- iOS keeps working via onOpenURL: the app now forwards maps:// URLs (if
  the Home Screen delivers them to the app), plus legacy fuelboard:// and
  http://maps.apple.com links from older cached timelines.
- No public API exists for a widget to detect CarPlay context, so the
  single maps:// link serves both; the app-side forward is the iOS safety
  net. 35 tests pass.
This commit is contained in:
FuelBoard Contributor
2026-08-12 13:07:44 +01:00
parent 1ff14607c5
commit 3e226ece57
3 changed files with 44 additions and 20 deletions
+27 -10
View File
@@ -9,18 +9,35 @@ struct FuelBoardApp: App {
}
}
/// WidgetKit widgets can only open their containing app, so a widget tap
/// delivers a `fuelboard://directions?lat=..&lng=..` URL here instead of
/// opening Apple Maps itself. Forward it to the native Maps directions
/// URL (`maps://?daddr=`), which is what the app's own rows use.
/// Handles deep links that end up in the app. Widget taps arrive here in
/// two cases:
/// - legacy/cached widget timelines using the `fuelboard://` relay, or
/// - the Home Screen delivering a `maps://` URL to the containing app
/// instead of opening Maps directly (the system's choice on iOS).
/// Either way we forward to the native Apple Maps directions URL. The
/// `http://maps.apple.com` form is also handled, from very old timelines.
/// In CarPlay the widget uses the same `maps://` URL, which routes to
/// Apple Maps without ever launching this app.
private func handleOpenURL(_ url: URL) {
guard url.scheme == "fuelboard",
url.host == "directions",
let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let lat = components.queryItems?.first(where: { $0.name == "lat" })?.value.flatMap(Double.init),
let lng = components.queryItems?.first(where: { $0.name == "lng" })?.value.flatMap(Double.init),
let mapsURL = URL(string: "maps://?daddr=\(lat),\(lng)&t=d")
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let items = components.queryItems
else { return }
// Preferred: maps://?daddr=lat,lng&t=d (also covers http://maps.apple.com).
if let daddr = items.first(where: { $0.name == "daddr" })?.value {
openMaps(daddr: daddr)
return
}
// Legacy relay: fuelboard://directions?lat=..&lng=..
if let lat = items.first(where: { $0.name == "lat" })?.value.flatMap(Double.init),
let lng = items.first(where: { $0.name == "lng" })?.value.flatMap(Double.init) {
openMaps(daddr: "\(lat),\(lng)")
}
}
private func openMaps(daddr: String) {
guard let mapsURL = URL(string: "maps://?daddr=\(daddr)&t=d") else { return }
UIApplication.shared.open(mapsURL)
}
}