SkillAgentSearch skills...

Position

🛰 Lightweight location positioning in Swift

Install / Use

/learn @piemonte/Position

README

Position

Position is a Swift 6-ready, actor-based location positioning library for iOS and macOS with modern async/await APIs and AsyncSequence support.

Swift Platforms Swift Package Manager License

Features

| Feature | Description | |:-------:|:------------| | 🚀 | Swift 6 - Full concurrency support with actor isolation | | ⚡ | Modern async/await - One-shot location requests with async/await | | 🔄 | AsyncSequence - Reactive updates for location, heading, and authorization | | 🎭 | Actor-based - Thread-safe by design with Swift concurrency | | 📍 | Customizable location accuracy and filtering | | 🌍 | Distance and time-based location filtering | | 📡 | Continuous location tracking with configurable accuracy | | 🧭 | Device heading and compass support (iOS only) | | 🔐 | Permission management with async authorization requests | | 📐 | Geospatial utilities for distance and bearing calculations | | 🔋 | Battery-aware location accuracy adjustments | | 📍 | Visit monitoring for significant location changes | | 🏢 | Floor level detection in supported venues | | 🏢 | Place data formatting and geocoding utilities | | 📍 | vCard location sharing support |

Requirements

  • iOS 16.0+ / macOS 13.0+
  • Swift 6.0+ (also supports Swift 5 mode)
  • Xcode 16.0+

Installation

Swift Package Manager (Recommended)

Add Position to your project using Swift Package Manager:

  1. In Xcode, select File > Add Package Dependencies...
  2. Enter the repository URL: https://github.com/piemonte/Position
  3. Select version 1.0.0 or later

Or add it to your Package.swift:

dependencies: [
    .package(url: "https://github.com/piemonte/Position", from: "1.0.0")
]

Quick Start

1. Configure Info.plist

Add the appropriate location usage descriptions to your app's Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>Your app needs location access to provide location-based features.</string>

<!-- Optional: For always authorization -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Your app needs location access even in the background.</string>

2. Basic Usage - Swift 6 Style

import Position

class LocationManager {
    let position = Position()
    
    func setup() async {
        // Check and request permissions
        let status = await position.locationServicesStatus
        
        switch status {
        case .notDetermined:
            let newStatus = await position.requestWhenInUseLocationAuthorization()
            print("Authorization result: \(newStatus)")
            
        case .allowedWhenInUse, .allowedAlways:
            await requestLocation()
            
        case .denied, .notAvailable:
            print("Location services unavailable")
        }
    }
    
    func requestLocation() async {
        do {
            // One-shot location request with async/await
            let location = try await position.currentLocation()
            print("📍 Location: \(location.coordinate)")
            
            // Or with custom accuracy
            let preciseLocation = try await position.currentLocation(
                desiredAccuracy: kCLLocationAccuracyBest
            )
            print("📍 Precise location: \(preciseLocation.coordinate)")
        } catch {
            print("❌ Location error: \(error)")
        }
    }
}

3. Continuous Updates with AsyncSequence

import Position

class LocationTracker {
    let position = Position()
    
    func startTracking() async {
        // Configure tracking parameters
        await position.setDistanceFilter(10) // meters
        position.trackingDesiredAccuracyWhenActive = kCLLocationAccuracyBest
        
        // Start location updates
        await position.startUpdating()
        
        // Consume location updates
        Task {
            for await location in position.locationUpdates {
                print("📍 New location: \(location.coordinate)")
                updateUI(with: location)
            }
        }
        
        // Monitor authorization changes
        Task {
            for await status in position.authorizationUpdates {
                print("🔐 Authorization changed: \(status)")
                handleAuthorizationChange(status)
            }
        }
        
        // Track heading updates (iOS only)
        Task {
            for await heading in position.headingUpdates {
                print("🧭 Heading: \(heading.trueHeading)°")
            }
        }
    }
    
    func stopTracking() async {
        await position.stopUpdating()
    }
}

4. SwiftUI Integration

import SwiftUI
import Position

@MainActor
class LocationViewModel: ObservableObject {
    @Published var currentLocation: CLLocation?
    @Published var authorizationStatus: Position.LocationAuthorizationStatus = .notDetermined
    
    private let position = Position()
    private var locationTask: Task<Void, Never>?
    
    func startLocationUpdates() {
        locationTask = Task {
            await position.startUpdating()
            
            for await location in position.locationUpdates {
                currentLocation = location
            }
        }
    }
    
    func stopLocationUpdates() async {
        locationTask?.cancel()
        await position.stopUpdating()
    }
}

struct LocationView: View {
    @StateObject private var viewModel = LocationViewModel()
    
    var body: some View {
        VStack {
            if let location = viewModel.currentLocation {
                Text("📍 \(location.coordinate.latitude), \(location.coordinate.longitude)")
            } else {
                Text("No location available")
            }
        }
        .task {
            viewModel.startLocationUpdates()
        }
    }
}

Advanced Features

All Available AsyncSequences

let position = Position()

// Location updates
for await location in position.locationUpdates {
    print("Location: \(location)")
}

// Heading updates (iOS only)
for await heading in position.headingUpdates {
    print("Heading: \(heading)")
}

// Authorization status changes
for await status in position.authorizationUpdates {
    print("Auth status: \(status)")
}

// Floor changes (when available)
for await floor in position.floorUpdates {
    print("Floor: \(floor.level)")
}

// Visit monitoring
for await visit in position.visitUpdates {
    print("Visit at: \(visit.coordinate)")
}

// Error handling
for await error in position.errorUpdates {
    print("Location error: \(error)")
}

Geospatial Calculations

import Position
import CoreLocation

let location1 = CLLocation(latitude: 37.7749, longitude: -122.4194) // San Francisco
let location2 = CLLocation(latitude: 34.0522, longitude: -118.2437) // Los Angeles

// Calculate distance
let distance = location1.distance(from: location2)
print("Distance: \(distance / 1000) km")

// Or use Measurement API for type-safe conversions
let measurement = Measurement(value: distance, unit: UnitLength.meters)
let km = measurement.converted(to: .kilometers).value
print("Distance: \(km) km")

// Calculate bearing
let bearing = location1.bearing(toLocation: location2)
print("Bearing: \(bearing)°")

// Calculate coordinate at bearing and distance
let coordinate = location1.locationCoordinate(withBearing: 45, distanceMeters: 1000)
print("New coordinate: \(coordinate)")

// Pretty distance description (localized)
let description = location1.prettyDistanceDescription(fromLocation: location2)
print("Distance: \(description)")

Battery-Aware Tracking

let position = Position()

// Enable automatic battery management
await position.setAdjustLocationUseFromBatteryLevel(true)

// Manual accuracy adjustment based on app state
await position.setAdjustLocationUseWhenBackgrounded(true)

// Configure accuracy levels
position.trackingDesiredAccuracyWhenActive = kCLLocationAccuracyBest
position.trackingDesiredAccuracyWhenInBackground = kCLLocationAccuracyKilometer

// The library will automatically adjust accuracy when:
// - Battery level drops below 20% (switches to reduced accuracy)
// - App enters background (uses trackingDesiredAccuracyWhenInBackground)
// - App becomes active again (restores trackingDesiredAccuracyWhenActive)

vCard Location Sharing

import Position
import CoreLocation

let location = CLLocation(latitude: 37.7749, longitude: -122.4194)

// Create vCard for sharing location (async version)
do {
    let vCardURL = try await location.vCard(name: "Golden Gate Bridge")
    // Share the vCard file URL
    print("vCard created at: \(vCardURL)")
} catch {
    print("Failed to create vCard: \(error)")
}

Placemark Utilities

import Position
import CoreLocation

// Format address components
let address = CLPlacemark.shortStringFromAddressElements(
    address: "1 Infinite Loop",
    locality: "Cupertino",
    administrativeArea: "CA"
)
print("Formatted address: \(address ?? "")")

// Pretty descriptions from placemarks
if let placemark = somePlacemark {
    // Simple pretty description
    let description = placemark.prettyDescription()
    print("Location: \(description)")
    
    // Zoom-level aware description
    let zoomDescription = placemark.prettyDescription(withZoomLevel: 14)
    print("Location at zoom 14: \(zoomDescription)")
    
    // Full address string
    let fullAddress = placemark.stringFromPlacemark()
    print(
View on GitHub
GitHub Stars97
CategoryDevelopment
Updated2mo ago
Forks10

Languages

Swift

Security Score

100/100

Audited on Jan 26, 2026

No findings