AppNavigator.openMap() now works on iOS

Also implemented currently unused AppNavigator.openWalkingDirections()
This commit is contained in:
Olof Hedman
2025-10-22 14:04:41 +02:00
parent c8a630e87f
commit 4112204a5f

View File

@@ -1,7 +1,49 @@
@file:OptIn(ExperimentalForeignApi::class)
package app.klottr.platform
import platform.Foundation.NSURL
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.useContents
import platform.Foundation.NSURL
import platform.UIKit.UIApplication
import platform.Foundation.NSURLComponents
import platform.Foundation.NSURLQueryItem
import platform.darwin.dispatch_async
import platform.darwin.dispatch_get_main_queue
import platform.Foundation.*
private fun urlEncode(query: String): String {
// Percent-encode for use in URL query
val encoded = (query as NSString)
.stringByAddingPercentEncodingWithAllowedCharacters(
NSCharacterSet.URLQueryAllowedCharacterSet()
)
return encoded ?: query
}
private fun isAtLeast(major: Int, minor: Int = 0, patch: Int = 0): Boolean {
val current = NSProcessInfo.processInfo.operatingSystemVersion
return current.useContents {
when {
this.majorVersion > major -> true
this.majorVersion < major -> false
this.minorVersion > minor -> true
this.minorVersion < minor -> false
else -> this.patchVersion >= patch
}
}
}
private fun openUrlOnMain(url: NSURL) {
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication.openURL(
url,
options = emptyMap<Any?, Any?>(),
completionHandler = null
)
}
}
actual object AppNavigator {
actual fun openUrl(url: String) {
@@ -10,13 +52,35 @@ actual object AppNavigator {
}
actual fun openMap(lat: Double, lon: Double, label: String?) {
// Use Apple Maps URL scheme
val encoded = label?.let { it } ?: "Place"
val url = "http://maps.apple.com/?ll=$lat,$lon&q=$encoded"
openUrl(url)
// This always opens apple maps, regardless of what navigation app you've set in system settings.
// There seems to be no way around that without implementing your own chooser.
val comps = NSURLComponents(string = "maps://")
comps.path = "/"
comps.queryItems = listOf(
NSURLQueryItem(name = "ll", value = "$lat,$lon"),
NSURLQueryItem(name = "q", value = label ?: "Place")
)
val nsUrl = comps.URL ?: return
openUrlOnMain(nsUrl)
}
actual fun openWalkingDirections(lat: Double?, lon: Double?, title: String?) {
//TODO: Implement
// On iOS 18.4+ there is a "default navigation app" setting in EU countries.
// This implementation makes sure to use it if available
// Build a destination string. You can replace this with a full address if you have one.
val destination = "$lat,$lon"
val encoded = urlEncode(destination)
val urlString = if (isAtLeast(18, 4, 0)) {
// iOS routes this to the user's chosen default navigation app
"geo-navigation:///directions?destination=$encoded"
} else {
// Apple Maps fallback: driving directions to destination
"maps://?daddr=$encoded&dirflg=d"
}
openUrlOnMain((NSURL(string = urlString)))
}
}