Version: 1.1 | Stand: Mai 2026 | Plattform: iOS Swift / SwiftUI MapKit REST API
SAMO Infra Tracker ist eine native iOS-Anwendung zur GPS-basierten Erfassung, Verwaltung und Dokumentation von Infrastrukturelementen – insbesondere Gasleitungen. Die App dient als mobiler Client für das SAMO Infrastruktur-System (Asseco-BERIT) und richtet sich an professionelle Nutzer wie Netzbetreiber, Versorgungsunternehmen, Bauunternehmen, Wartungs- und Inspektionsdienste sowie Kommunen.
| Komponente | Technologie | Details |
|---|---|---|
| Sprache | Swift | Moderne, typsichere Programmiersprache von Apple |
| UI-Framework | SwiftUI | Deklaratives UI-Framework mit reaktiver Datenbindung |
| Karten | MapKit (UIKit) | Über UIViewRepresentable in SwiftUI eingebettet |
| GPS / Location | CoreLocation | CLLocationManager mit Hintergrund-Tracking |
| Netzwerk | URLSession | Native HTTP-Kommunikation mit async/await & Completion Handlers |
| Logging | OSLog | Apple-natives System für strukturiertes App-Logging |
| Persistenz | JSON-Datei | config.json im Documents-Verzeichnis |
| Lokalisierung | Localizable.xcstrings | Unterstützung für Deutsch, Englisch, Französisch, Italienisch, Tschechisch und Japanisch |
| Architektur | MVVM | Model-View-ViewModel mit @ObservableObject |
| Min. iOS-Version | iOS 14.0+ | Unterstützt iPhone und iPad |
| Backend | SAMO REST API | GIS-Server von Asseco-BERIT |
append-Parameter bei loadFeatures() ermöglicht inkrementelles Laden von Features statt vollständigem Ersetzen.content-Strukturen.
Die App folgt dem MVVM-Muster (Model-View-ViewModel) mit einem zentralen ViewModel
als ObservableObject. Das ViewModel orchestriert die gesamte App-Logik, hält den State
und koordiniert die Netzwerk-Schicht über den GisFeatureController.
@Published-Properties bereit.@ObservedObject / @Binding an das ViewModel und reagieren reaktiv auf Änderungen.SAMO_Infra_TrackerApp.swift
Einstiegspunkt der App, markiert mit @main. Erstellt ein WindowGroup mit
CustomContentView als Root-View. Das ViewModel wird innerhalb von
CustomContentView instanziiert.
@main
struct SAMO_Infra_TrackerApp: App {
var body: some Scene {
WindowGroup {
CustomContentView(myPolylinesSelected: [])
}
}
}
GisFeatureController.swiftZentrale Klasse für die HTTP-Kommunikation mit dem SAMO REST API. Verwaltet Authentifizierung (Cookie-basiert mit Basic-Auth-Fallback), Feature-Downloads, Track-Uploads und Schadensmeldungen.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
cooke | String | Session-Cookie für authentifizierte Anfragen |
bs64LoginToken | String | Base64-codierter Login-Token (Basic Auth) |
features | [GisFeature] | Heruntergeladene GIS-Features |
baseUrl | String | REST-Basis-URL |
maxRetries | Int | Max. Wiederholungsversuche (10) |
retryDelay | TimeInterval | Wartezeit zwischen Retries (2 Sek.) |
| Methode | Beschreibung |
|---|---|
connect() | Einstiegspunkt: Feature-Anzahl abfragen, dann Features laden |
getFeatureCount(type:useCookie:) | GET /{type}/count → Gesamtzahl der Features |
loadFeatures(type:url:...boundingBox:append:) | GET /{type}?srs=epsg:4326&size=…&bbox=… → Features im Kartenausschnitt (append: Features hinzufügen oder ersetzen) |
uploadTrack(idLeitung:trackFeature:) | PUT → GPS-Track erstellen und mit Leitung verknüpfen |
uploadTrackOhneLeitung(trackFeature:) | PUT → GPS-Track ohne Leitungsverknüpfung erstellen (neu in v1.1) |
updateCurrentTrackFeature(trackFeature:) | POST → Laufenden Track aktualisieren |
uploadSchaden(schadenFeature:) | PUT → Schadensmeldung mit optionalen Foto-Attachments erstellen und mit Track verknüpfen |
retryRequest(request:) | Generischer Retry-Wrapper (bis 10 Versuche, 2s Delay bei 401) |
extractAndSetCookie(from:) | Session-Cookie aus Response-Headers extrahieren |
ViewModel.swift
Zentrales ObservableObject, das den gesamten App-State verwaltet. Erbt von NSObject
und implementiert CLLocationManagerDelegate für GPS-Updates. Orchestriert den
GisFeatureController und stellt @Published-Properties für die Views bereit.
| Property | Typ | Zweck |
|---|---|---|
myGpsPath | GpsPath | Aktuell aufgezeichneter GPS-Track |
allSchaden | [Schaden] | Alle erfassten Schadensmeldungen |
leitungen | [Leitungen] | Alle heruntergeladenen Leitungen |
selectedLeitungIndex | Int | Index der ausgewählten Leitung (-1 = keine) |
userLocation | CLLocationCoordinate2D? | Aktuelle GPS-Position |
followGPS | Bool | Karte folgt automatisch der Position |
trackVerfolgenUndAufzeichnen | Bool | GPS-Aufzeichnung aktiv |
infobox | String | Statusmeldungen in der UI |
uriString, username, password | String | Server-Verbindungsdaten |
lineFeatureType | String | SAMO-Feature-Typ für Leitungen |
pointFeatureType | String | SAMO-Feature-Typ für Schäden |
gpsTrackFeatureType | String | SAMO-Feature-Typ für GPS-Tracks |
| Methode | Beschreibung |
|---|---|
init() | Lädt Konfiguration aus JSON, initialisiert GisFeatureController, startet Verbindung |
startUpdatingLocation() | GPS-Tracking starten: 2s-Timer, Track hochladen, Features im Sichtbereich laden |
stopUpdatingLocation() | GPS-Tracking beenden |
downloadAllFeaturesInBoundingBox() | Features für den aktuellen Kartenausschnitt neu laden |
createAllGasLeitungen() | Konvertiert [GisFeature] → [Leitungen], filtert Niederdruck |
selectGasleitung(_:) | Leitung auswählen / abwählen |
neuenSchadenErstellen(Text:) | Schaden an aktueller Position erstellen und hochladen |
neuerTrack() | Aktuellen Track archivieren, neuen starten |
gpsPathVerknuepfen() | GPS-Track mit ausgewählter Leitung verknüpfen |
wgs84ToLV95(lat:lon:) | WGS84 → Swiss LV95 Koordinatenumrechnung |
checkServerConnection() | Verbindungstest: GET /rest/security/getCurrentUser |
saveConfigToFile() / loadConfigFromFile() | Konfiguration als JSON speichern / laden |
Alle Datenmodelle befinden sich im Ordner structs/. Details zu den einzelnen Structs finden Sie in Abschnitt 6. Datenmodelle.
Details zur Benutzeroberfläche finden Sie in Abschnitt 8. Benutzeroberfläche.
GisFeature.swift)Decodable-Modell für die JSON-Antworten des SAMO REST API. Repräsentiert ein geographisches Feature (Leitung).
| Struct | Beschreibung |
|---|---|
GisFeature | Hauptmodell: id, sid, Geometrien, Attribute. Implementiert Identifiable und Decodable. |
geometry | Geometrie-Typ (LineString) mit coordinates: [[Double]] |
geometriesEpsg4326 | Wrapper für Geometrie im EPSG:4326 Koordinatensystem |
at_30001_02 | Attribut-Struct mit ca_GA_DRUCK_02 (Druckzone, z.B. "Niederdruck") |
getFirstCoordinate() → CLLocationCoordinate2D – Erste Koordinate des FeaturesgetCoordinates() → [CLLocationCoordinate2D] – Alle Koordinaten als ArrayLeitungen.swift)Repräsentiert eine Leitung (z.B. Gasleitung) für die Kartenanzeige. Konvertiert aus GisFeature.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
title | String | Anzeigename der Leitung |
id | String | Eindeutige SAMO-ID |
coordinates | [CLLocationCoordinate2D] | Koordinaten des Leitungsverlaufs |
druckzone | String? | Druckzone (Niederdruck wird gefiltert) |
myPolyLine | MKPolyline? | Vorberechnete Polyline für MapKit |
Extension: isNear(coordinate:) – Hit-Test, ob eine Koordinate innerhalb von 15m liegt (für Tap-Erkennung).
GpsTrack.swift)Repräsentiert einen aufgezeichneten GPS-Track (Pfad aus Koordinaten).
| Eigenschaft / Methode | Beschreibung |
|---|---|
coordinates | Array aller aufgezeichneten GPS-Punkte |
id | Server-ID nach Upload (initial nil) |
addCoordinate(_:_:) | Neuen GPS-Punkt hinzufügen |
getDistance() | Gesamtlänge des Tracks in Metern |
getPolyLine() | MKPolyline für Kartenrendering |
myEncode(viewModel:) | JSON-Encoding mit LV95-konvertierten Koordinaten |
myEncode(viewModel:beschreibung:) | Vollständiges JSON-Encoding mit Beschreibung und Attributen |
viewModel.wgs84ToLV95()).
Schaden.swift)Repräsentiert eine Schadensmeldung an einer Punktposition.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
beschreibung | String | Beschreibungstext des Schadens |
coordinates | [Double] | Swiss LV95 Koordinaten [E, N] |
wgs84Coordinates | CLLocationCoordinate2D | WGS84-Koordinaten für Kartenanzeige |
connectToId | String | ID des zugehörigen GPS-Tracks |
myEncode() erzeugt das JSON für die SAMO API mit Attributen wie at_alg_report_description und Punkt-Geometrie.
ConfigData.swift)Codable-Struct für die Persistierung aller Einstellungen.
| Felder | Beschreibung |
|---|---|
uriString, username, password | Server-Verbindungsdaten |
lineFeatureType, pointFeatureType, gpsTrackFeatureType | SAMO Feature-Typen |
| Relationen & Rollen | Konfigurierbare Beziehungstypen |
cookie | Gespeicherter Session-Cookie |
polylineName, pointName | Anzeigenamen (z.B. "Gasleitung", "Schaden") |
ConfigManager (Singleton): save(_:) und load() lesen/schreiben config.json im Documents-Verzeichnis.
Die App verwendet eine zweistufige Authentifizierungsstrategie:
username:password-Token als Authorization: Basic …-Header gesendet.Bei 401 Unauthorized-Antworten wechselt die App automatisch zurück zu Basic Auth und versucht einen neuen Cookie zu erhalten.
| Endpunkt | Methode | Zweck |
|---|---|---|
{base}/rest/features/{type}/count |
GET | Anzahl der Features eines Typs abfragen |
{base}/rest/features/{type}?srs=epsg:4326&size=…&bbox=… |
GET | Features innerhalb einer Bounding Box laden |
{base}/rest/features/{lineType}/{id}/relations/{trackType}/{relation}/{role}/create |
PUT | GPS-Track erstellen und mit Leitung verknüpfen |
{base}/rest/features/{trackType} |
PUT | GPS-Track ohne Leitungsverknüpfung erstellen (neu in v1.1) |
{base}/rest/features/{trackType}/{trackId} |
POST | Bestehenden GPS-Track aktualisieren (Geometrie erweitern) |
{base}/rest/features/{trackType}/{trackId}/relations/{pointType}/{relation}/{role}/create |
PUT | Schadensmeldung mit optionalen Foto-Attachments erstellen und mit Track verknüpfen |
{base}/rest/security/getCurrentUser |
GET | Verbindung prüfen / aktuellen Benutzer abrufen |
{base}/api/rest/management/user/logout |
GET | Session beenden / Logout |
https://samo.example.com/EZL – Die REST-Pfade werden automatisch angehängt.
Alle Netzwerkanfragen nutzen eine generische Retry-Logik (retryRequest()):
CustomContentView.swiftRoot-View der App mit folgendem Aufbau (von oben nach unten):
trackVerfolgenUndAufzeichnen, startet/stoppt Location-Updates.viewModel.selectGasleitung().viewModel.neuenSchadenErstellen() auf.customMapView.swift
UIViewRepresentable-Wrapper um MKMapView für volle MapKit-Kontrolle.
Ein Coordinator dient als MKMapViewDelegate.
| Farbe | Element | Stil |
|---|---|---|
| Orange | Aktueller GPS-Track | Gestrichelt, 3pt |
| Grau | Archivierte Tracks | Gestrichelt |
| Blau | Ausgewählte Leitung | Solide, 4pt |
| Grün | Zusätzlich selektierte Leitungen | Gestrichelt |
| Rot | Standard-Leitungen | Solide, 2pt |
| Rot (Kreuz) | Crosshair-Overlay (Schadenspositionen) | Fadenkreuz |
| Blau (Kreis) | GPS-Position des Benutzers | Kreisförmig |
configPage.swift
Einstellungs-View mit @Binding-Properties zum ViewModel. Zwei Formularbereiche:
Drei Aktionsbuttons: Konfiguration speichern, Verbindung prüfen, Verbindung trennen.
Die App arbeitet mit zwei Koordinatensystemen und konvertiert automatisch zwischen diesen:
| System | EPSG-Code | Verwendung |
|---|---|---|
| WGS84 | EPSG:4326 | GPS-Empfang (CoreLocation), Kartenanzeige (MapKit), Feature-Download |
| Swiss LV95 | EPSG:2056 | Upload zu SAMO API, Bounding-Box-Berechnung, Schweizer Koordinatenanzeige |
Die Methode wgs84ToLV95(lat:lon:) im ViewModel implementiert die offiziellen
swisstopo-Formeln zur Umrechnung von WGS84-Breitengrad/Längengrad in Schweizer LV95-Koordinaten
(Easting/Northing).
boundingBoxLV95FromGPS(lat:lon:edgeLengthMeters:) berechnet eine quadratische Bounding Box in
LV95-Koordinaten um eine GPS-Position. Diese wird für den Feature-Download verwendet, um nur Features im
aktuellen Kartenausschnitt zu laden.
Alle Einstellungen werden als JSON-Datei im Documents-Verzeichnis der App gespeichert:
Documents/config.json
scenePhase == .background)| Methode | Beschreibung |
|---|---|
save(_:) | Encodiert ConfigData nach JSON und schreibt in die Datei |
load() | Liest und decodiert ConfigData aus der Datei |
| Anforderung | Wert |
|---|---|
| IDE | Xcode (aktuell) |
| Sprache | Swift |
| Projekttyp | Xcode Project (.xcodeproj) |
| Abhängigkeiten | Keine externen Pakete – nur Apple Frameworks |
| Framework | Zweck |
|---|---|
SwiftUI | Deklaratives UI |
MapKit | Kartenanzeige, Overlays, Annotations |
CoreLocation | GPS-Tracking, Standortbestimmung |
Foundation | URLSession, JSON-Encoding/-Decoding, FileManager |
| Eigenschaft | Wert |
|---|---|
| Plattform | iOS (iPhone + iPad) |
| Min. iOS-Version | 14.0 |
| Benötigte Berechtigungen | Standort ("Immer"), Netzwerk |
| Background Modes | location (in Info.plist konfiguriert) |
| Speicherbedarf | ca. 50 MB |
SAMO Infra Tracker.xcodeproj)| Begriff | Beschreibung |
|---|---|
| SAMO | GIS-Infrastruktur-System von Asseco-BERIT für die Verwaltung von leitungsgebundener Infrastruktur |
| GIS | Geographisches Informationssystem – System zur Erfassung, Verwaltung und Analyse räumlicher Daten |
| Feature | Ein geographisches Objekt im GIS (z.B. eine Leitung, ein Schaden, ein GPS-Track) |
| Feature-Typ | Klassifizierung eines Features (z.B. ft_30015 für Gasleitungen) |
| Relation | Verknüpfung zwischen zwei Features (z.B. Track ↔ Leitung) |
| Role | Rolle eines Features in einer Relation (z.B. rt_tracking) |
| WGS84 | World Geodetic System 1984 – globales Koordinatensystem (GPS-Standard), EPSG:4326 |
| Swiss LV95 | Schweizer Landesvermessung 1995 – nationales Koordinatensystem der Schweiz, EPSG:2056 |
| Bounding Box | Rechteckiger Kartenausschnitt (min/max Koordinaten) für den Feature-Download |
| EPSG | European Petroleum Survey Group – Registrierung von Koordinatenreferenzsystemen |
| Polyline | Linienzug aus Koordinaten – Darstellung von Leitungen und Tracks auf der Karte |
| Annotation | Kartenmarkierung (Pin) an einer Punktposition (z.B. für Schäden) |
| Overlay | Grafische Ebene über der Karte (Polylines, Crosshairs, Kreise) |
| MVVM | Model-View-ViewModel – Architekturmuster zur Trennung von Daten, Logik und UI |
| Druckzone | Kategorie einer Gasleitung nach Druck (z.B. Niederdruck, Mitteldruck, Hochdruck) |
| Crosshair | Fadenkreuz-Overlay zur Markierung exakter Positionen auf der Karte |
| Track | Aufgezeichneter GPS-Pfad (Folge von Koordinaten) |
| Track ohne Leitung | GPS-Track, der unabhängig von einer Infrastrukturleitung erstellt wird (neu in v1.1) |
| Foto-Attachment | Fotografische Dokumentation, die einer Schadensmeldung beigefügt wird (neu in v1.1) |
| OSLog | Apple-natives Logging-Framework für strukturiertes, effizienten App-Logging (neu in v1.1) |
Projektdokumentation SAMO Infra Tracker | Stand: Mai 2026
← Zurück zur Startseite |
Zur Benutzeranleitung