forked from fritob/Camper-Monitor
CarPlay-Demo: Nivellierung auf dem Fahrzeugdisplay
Eigene Build-Konfiguration "CarPlay" samt Schema, damit der Versuchsbau neben der TestFlight-App stehen kann: eigener Name, eigene Bundle-ID, persoenliches Team, manuelles Signing. Debug und Release bleiben unberuehrt. Wichtig dabei: Die Signing-Einstellungen stehen ausschliesslich in den Target-Konfigurationen. Steht CODE_SIGN_STYLE auf Projektebene, schreibt der naechste xcodebuild-Lauf alle uebrigen Konfigurationen auf Manual um und loescht ihr Team – der TestFlight-Build waere damit hin. Der CarPlay-Code haengt an `CARPLAY_DEMO` und existiert im regulaeren Build nicht. Die Szene zeichnet in das gelieferte CPWindow; das CPMapTemplate darueber bleibt leer, weil es auf dem Stellplatz nichts zu tippen gibt. Die Anzeige sperrt sich oberhalb von 5 km/h selbst – erzwungen, nicht zugesagt. Die Groessen sind auf die 400x240 Punkte ausgelegt, die CarPlay liefert, nicht auf die 800x480 Pixel. In Pixeln gedachte Schriftgroessen sind auf dem Fahrzeugdisplay doppelt zu gross und schneiden den Text ab. Bekannt: Unter iOS 26.5 stuerzt Apples CarPlayTemplateUIHost beim Aufbau der Navigationsleiste ab (`_updateShareButtonVisibility` fragt seinen destinationSharingDelegate nach `vehicleSupportsDestinationSharing`, den dieser nicht kennt). Beides ist privates API und von der App aus nicht erreichbar; unter iOS 18 laeuft es. Szene und Root-Template werden vorher in beiden Faellen akzeptiert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b1ffbe324a
commit
ae12d8ede4
@@ -0,0 +1,77 @@
|
||||
#if CARPLAY_DEMO
|
||||
import CoreLocation
|
||||
import Observation
|
||||
|
||||
/// Sperrt die Libelle, sobald das Fahrzeug schneller als Schrittgeschwindigkeit
|
||||
/// fährt.
|
||||
///
|
||||
/// Ausrichten passiert im Stand oder im Zentimeterbereich davor. Eine Anzeige,
|
||||
/// die während der Fahrt etwas zu lesen gäbe, wäre Ablenkung ohne Nutzen – also
|
||||
/// gibt es sie dort nicht. Die Grenze ist bewusst technisch erzwungen und nicht
|
||||
/// bloss eine Zusage im Text.
|
||||
@Observable
|
||||
final class CarPlaySpeedGate: NSObject, CLLocationManagerDelegate {
|
||||
static let shared = CarPlaySpeedGate()
|
||||
|
||||
/// Fünf km/h: schneller als Rangieren, langsamer als jede Verkehrssituation,
|
||||
/// in der jemand aufs Display sehen dürfte.
|
||||
static let limit: CLLocationSpeed = 5.0 / 3.6
|
||||
|
||||
private(set) var isStationary = true
|
||||
private(set) var speed: CLLocationSpeed?
|
||||
|
||||
@ObservationIgnored private let manager = CLLocationManager()
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
manager.delegate = self
|
||||
manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
|
||||
}
|
||||
|
||||
func start() {
|
||||
// Fuer Screenshots laesst sich die Geschwindigkeit vorgeben (in km/h);
|
||||
// eine simulierte GPS-Fahrt nur fuer ein Standbild waere unverhaeltnis-
|
||||
// maessig. Ohne die Variable zaehlt ausschliesslich der echte Sensor.
|
||||
if let forced = ProcessInfo.processInfo.environment["CARPLAY_DEMO_SPEED"].flatMap(Double.init) {
|
||||
speed = forced / 3.6
|
||||
isStationary = forced / 3.6 <= Self.limit
|
||||
return
|
||||
}
|
||||
manager.requestWhenInUseAuthorization()
|
||||
manager.startUpdatingLocation()
|
||||
}
|
||||
|
||||
/// Nur für die Demo-Sequenz: erzwingt den Fahrzustand, damit sich die
|
||||
/// Sperre zeigen lässt, ohne eine GPS-Fahrt zu simulieren.
|
||||
func setDemoDriving(_ driving: Bool) {
|
||||
speed = driving ? 30 / 3.6 : 0
|
||||
isStationary = !driving
|
||||
}
|
||||
|
||||
func stop() {
|
||||
manager.stopUpdatingLocation()
|
||||
}
|
||||
|
||||
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
|
||||
guard let location = locations.last else { return }
|
||||
|
||||
// CoreLocation meldet im Stand eine negative Geschwindigkeit: der Wert
|
||||
// ist dann schlicht unbekannt. Das als "fährt" zu werten, würde die
|
||||
// Funktion genau dort abschalten, wo sie gebraucht wird – auf dem
|
||||
// Stellplatz, oft unter Bäumen mit schlechtem Empfang.
|
||||
guard location.speed >= 0 else {
|
||||
speed = nil
|
||||
isStationary = true
|
||||
return
|
||||
}
|
||||
|
||||
speed = location.speed
|
||||
isStationary = location.speed <= Self.limit
|
||||
}
|
||||
|
||||
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
||||
speed = nil
|
||||
isStationary = true
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user