dumon-geolocation/ios/Sources/DumonGeolocationPlugin/DumonGeolocationPlugin.swift
2026-01-08 09:20:20 +08:00

224 lines
8.1 KiB
Swift

import Foundation
import Capacitor
import CoreLocation
import UIKit
@objc(DumonGeolocationPlugin)
public class DumonGeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "DumonGeolocationPlugin"
public let jsName = "DumonGeolocation"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "startPositioning", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "stopPositioning", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "getLatestPosition", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "checkAndRequestPermissions", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setOptions", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "getGnssStatus", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "getLocationServicesStatus", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "startBackgroundTracking", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "stopBackgroundTracking", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "isBackgroundTrackingActive", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "getBackgroundLatestPosition", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "openBackgroundPermissionSettings", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "openNotificationPermissionSettings", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setAuthTokens", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "clearAuthTokens", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "getAuthState", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setBackgroundPostUrl", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "getBackgroundPostUrl", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "configureEdgeToEdge", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "setGpsMode", returnType: CAPPluginReturnPromise)
]
private let implementation = DumonGeolocation()
private var pendingPermissionCall: CAPPluginCall?
private var pendingBackgroundCall: CAPPluginCall?
public override func load() {
implementation.onPositionUpdate = { [weak self] data in
self?.notifyListeners("onPositionUpdate", data: data)
}
implementation.onGnssStatus = { [weak self] data in
self?.notifyListeners("onGnssStatus", data: data)
}
implementation.onAuthorizationChange = { [weak self] status in
self?.handleAuthorizationChange(status)
}
}
@objc func startPositioning(_ call: CAPPluginCall) {
let status = implementation.authorizationStatus()
if !isLocationAuthorized(status) {
call.reject("Location permission not granted")
return
}
implementation.startPositioning()
call.resolve()
}
@objc func stopPositioning(_ call: CAPPluginCall) {
implementation.stopPositioning()
call.resolve()
}
@objc func getLatestPosition(_ call: CAPPluginCall) {
call.resolve(implementation.getLatestPosition())
}
@objc func checkAndRequestPermissions(_ call: CAPPluginCall) {
let status = implementation.authorizationStatus()
if status == .notDetermined {
pendingPermissionCall = call
implementation.requestWhenInUsePermission()
return
}
call.resolve(permissionStatusDict(status))
}
@objc func setOptions(_ call: CAPPluginCall) {
var options: [String: Any] = [:]
for (key, value) in call.options {
if let key = key as? String {
options[key] = value
}
}
implementation.setOptions(options)
call.resolve()
}
@objc func getGnssStatus(_ call: CAPPluginCall) {
if let data = implementation.getGnssStatus() {
call.resolve(data)
} else {
call.resolve([:])
}
}
@objc func getLocationServicesStatus(_ call: CAPPluginCall) {
call.resolve(implementation.getLocationServicesStatus())
}
@objc func startBackgroundTracking(_ call: CAPPluginCall) {
if let postUrl = call.getString("postUrl") {
implementation.setBackgroundPostUrl(postUrl)
}
let status = implementation.authorizationStatus()
if status == .authorizedAlways {
implementation.startBackgroundTracking()
call.resolve()
return
}
pendingBackgroundCall = call
implementation.requestAlwaysPermission()
}
@objc func stopBackgroundTracking(_ call: CAPPluginCall) {
implementation.stopBackgroundTracking()
call.resolve()
}
@objc func isBackgroundTrackingActive(_ call: CAPPluginCall) {
call.resolve(["active": implementation.isBackgroundTrackingActive()])
}
@objc func getBackgroundLatestPosition(_ call: CAPPluginCall) {
if let data = implementation.getBackgroundLatestPosition() {
call.resolve(data)
} else {
call.resolve([:])
}
}
@objc func openBackgroundPermissionSettings(_ call: CAPPluginCall) {
openAppSettings(call)
}
@objc func openNotificationPermissionSettings(_ call: CAPPluginCall) {
openAppSettings(call)
}
@objc func setAuthTokens(_ call: CAPPluginCall) {
guard let access = call.getString("accessToken"), !access.isEmpty else {
call.reject("accessToken is required")
return
}
guard let refresh = call.getString("refreshToken"), !refresh.isEmpty else {
call.reject("refreshToken is required")
return
}
implementation.setAuthTokens(accessToken: access, refreshToken: refresh)
call.resolve()
}
@objc func clearAuthTokens(_ call: CAPPluginCall) {
implementation.clearAuthTokens()
call.resolve()
}
@objc func getAuthState(_ call: CAPPluginCall) {
call.resolve(["present": implementation.getAuthState()])
}
@objc func setBackgroundPostUrl(_ call: CAPPluginCall) {
let url = call.getString("url")
implementation.setBackgroundPostUrl(url)
call.resolve()
}
@objc func getBackgroundPostUrl(_ call: CAPPluginCall) {
let url = implementation.getBackgroundPostUrl()
call.resolve(["url": url ?? NSNull()])
}
@objc func configureEdgeToEdge(_ call: CAPPluginCall) {
// No-op on iOS; UI handled by app.
call.resolve()
}
@objc func setGpsMode(_ call: CAPPluginCall) {
let mode = call.getString("mode") ?? "normal"
implementation.setGpsMode(mode)
call.resolve()
}
private func handleAuthorizationChange(_ status: CLAuthorizationStatus) {
if let call = pendingPermissionCall {
pendingPermissionCall = nil
call.resolve(permissionStatusDict(status))
}
if let call = pendingBackgroundCall {
pendingBackgroundCall = nil
if status == .authorizedAlways {
implementation.startBackgroundTracking()
call.resolve()
} else {
call.reject("Background location permission not granted")
}
}
}
private func permissionStatusDict(_ status: CLAuthorizationStatus) -> [String: String] {
let granted = isLocationAuthorized(status)
return [
"location": granted ? "granted" : "denied",
"wifi": "granted"
]
}
private func isLocationAuthorized(_ status: CLAuthorizationStatus) -> Bool {
return status == .authorizedAlways || status == .authorizedWhenInUse
}
private func openAppSettings(_ call: CAPPluginCall) {
guard let url = URL(string: UIApplication.openSettingsURLString) else {
call.reject("Unable to open settings")
return
}
DispatchQueue.main.async {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
call.resolve()
}
}
}