init
This commit is contained in:
154
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationCallbackManager.swift
generated
vendored
Normal file
154
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationCallbackManager.swift
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
import Capacitor
|
||||
import IONGeolocationLib
|
||||
|
||||
private enum GeolocationCallbackType {
|
||||
case requestPermissions
|
||||
case location
|
||||
case watch
|
||||
|
||||
var shouldKeepCallback: Bool {
|
||||
self == .watch
|
||||
}
|
||||
|
||||
var shouldClearAfterSending: Bool {
|
||||
self == .location || self == .requestPermissions
|
||||
}
|
||||
}
|
||||
|
||||
private struct GeolocationCallbackGroup {
|
||||
let ids: [CAPPluginCall]
|
||||
let type: GeolocationCallbackType
|
||||
}
|
||||
|
||||
final class GeolocationCallbackManager {
|
||||
private(set) var requestPermissionsCallbacks: [CAPPluginCall]
|
||||
private(set) var locationCallbacks: [CAPPluginCall]
|
||||
private(set) var watchCallbacks: [String: CAPPluginCall]
|
||||
private let capacitorBridge: CAPBridgeProtocol?
|
||||
|
||||
private var allCallbackGroups: [GeolocationCallbackGroup] {
|
||||
[
|
||||
.init(ids: requestPermissionsCallbacks, type: .requestPermissions),
|
||||
.init(ids: locationCallbacks, type: .location),
|
||||
.init(ids: Array(watchCallbacks.values), type: .watch)
|
||||
]
|
||||
}
|
||||
private var requestPermissionsCallbackGroup: GeolocationCallbackGroup? {
|
||||
allCallbackGroups.first { $0.type == .requestPermissions }
|
||||
}
|
||||
|
||||
init(capacitorBridge: CAPBridgeProtocol?) {
|
||||
self.capacitorBridge = capacitorBridge
|
||||
self.requestPermissionsCallbacks = []
|
||||
self.locationCallbacks = []
|
||||
self.watchCallbacks = [:]
|
||||
}
|
||||
|
||||
func addRequestPermissionsCallback(capacitorCall call: CAPPluginCall) {
|
||||
capacitorBridge?.saveCall(call)
|
||||
requestPermissionsCallbacks.append(call)
|
||||
}
|
||||
|
||||
func addLocationCallback(capacitorCall call: CAPPluginCall) {
|
||||
capacitorBridge?.saveCall(call)
|
||||
locationCallbacks.append(call)
|
||||
}
|
||||
|
||||
func addWatchCallback(_ watchId: String, capacitorCall call: CAPPluginCall) {
|
||||
capacitorBridge?.saveCall(call)
|
||||
watchCallbacks[watchId] = call
|
||||
}
|
||||
|
||||
func clearRequestPermissionsCallbacks() {
|
||||
requestPermissionsCallbacks.forEach {
|
||||
capacitorBridge?.releaseCall($0)
|
||||
}
|
||||
requestPermissionsCallbacks.removeAll()
|
||||
}
|
||||
|
||||
func clearWatchCallbackIfExists(_ watchId: String) {
|
||||
if let callbackToRemove = watchCallbacks[watchId] {
|
||||
capacitorBridge?.releaseCall(callbackToRemove)
|
||||
watchCallbacks.removeValue(forKey: watchId)
|
||||
}
|
||||
}
|
||||
|
||||
func clearLocationCallbacks() {
|
||||
locationCallbacks.forEach {
|
||||
capacitorBridge?.releaseCall($0)
|
||||
}
|
||||
locationCallbacks.removeAll()
|
||||
}
|
||||
|
||||
func sendSuccess(_ call: CAPPluginCall) {
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
func sendSuccess(_ call: CAPPluginCall, with data: PluginCallResultData) {
|
||||
call.resolve(data)
|
||||
}
|
||||
|
||||
func sendRequestPermissionsSuccess(_ permissionsResult: String) {
|
||||
if let group = requestPermissionsCallbackGroup {
|
||||
let data = [
|
||||
Constants.AuthorisationStatus.ResultKey.location: permissionsResult,
|
||||
Constants.AuthorisationStatus.ResultKey.coarseLocation: permissionsResult
|
||||
]
|
||||
send(.success(data), to: group)
|
||||
}
|
||||
}
|
||||
|
||||
func sendSuccess(with position: IONGLOCPositionModel) {
|
||||
createPluginResult(status: .success(position.toJSObject()))
|
||||
}
|
||||
|
||||
func sendError(_ call: CAPPluginCall, error: GeolocationError) {
|
||||
let errorModel = error.toCodeMessagePair()
|
||||
call.reject(errorModel.1, errorModel.0)
|
||||
}
|
||||
|
||||
func sendError(_ error: GeolocationError) {
|
||||
createPluginResult(status: .error(error.toCodeMessagePair()))
|
||||
}
|
||||
}
|
||||
|
||||
private enum CallResultStatus {
|
||||
typealias SuccessModel = JSObject
|
||||
typealias ErrorModel = (code: String, message: String)
|
||||
|
||||
case success(_ data: SuccessModel)
|
||||
case error(_ codeAndMessage: ErrorModel)
|
||||
}
|
||||
|
||||
private extension GeolocationCallbackManager {
|
||||
|
||||
func createPluginResult(status: CallResultStatus) {
|
||||
allCallbackGroups.forEach {
|
||||
send(status, to: $0)
|
||||
}
|
||||
}
|
||||
|
||||
func send(_ callResultStatus: CallResultStatus, to group: GeolocationCallbackGroup) {
|
||||
group.ids.forEach { call in
|
||||
call.keepAlive = group.type.shouldKeepCallback
|
||||
switch callResultStatus {
|
||||
case .success(let data):
|
||||
call.resolve(data)
|
||||
case .error(let error):
|
||||
call.reject(error.message, error.code)
|
||||
}
|
||||
}
|
||||
|
||||
if group.type.shouldClearAfterSending {
|
||||
clearCallbacks(for: group.type)
|
||||
}
|
||||
}
|
||||
|
||||
func clearCallbacks(for type: GeolocationCallbackType) {
|
||||
if case .location = type {
|
||||
clearLocationCallbacks()
|
||||
} else if case .requestPermissions = type {
|
||||
clearRequestPermissionsCallbacks()
|
||||
}
|
||||
}
|
||||
}
|
||||
36
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationConstants.swift
generated
vendored
Normal file
36
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationConstants.swift
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
enum Constants {
|
||||
enum Arguments {
|
||||
static let enableHighAccuracy = "enableHighAccuracy"
|
||||
static let id = "id"
|
||||
}
|
||||
|
||||
enum AuthorisationStatus {
|
||||
enum ResultKey {
|
||||
static let location = "location"
|
||||
static let coarseLocation = "coarseLocation"
|
||||
}
|
||||
|
||||
enum Status {
|
||||
static let denied: String = "denied"
|
||||
static let granted: String = "granted"
|
||||
static let prompt: String = "prompt"
|
||||
}
|
||||
}
|
||||
|
||||
enum LocationUsageDescription {
|
||||
static let always: String = "NSLocationAlwaysAndWhenInUseUsageDescription"
|
||||
static let whenInUse: String = "NSLocationWhenInUseUsageDescription"
|
||||
}
|
||||
|
||||
enum Position {
|
||||
static let altitude: String = "altitude"
|
||||
static let coords: String = "coords"
|
||||
static let heading: String = "heading"
|
||||
static let accuracy: String = "accuracy"
|
||||
static let latitude: String = "latitude"
|
||||
static let longitude: String = "longitude"
|
||||
static let speed: String = "speed"
|
||||
static let timestamp: String = "timestamp"
|
||||
static let altitudeAccuracy: String = "altitudeAccuracy"
|
||||
}
|
||||
}
|
||||
44
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationError.swift
generated
vendored
Normal file
44
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationError.swift
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
enum GeolocationMethod: String {
|
||||
case getCurrentPosition
|
||||
case watchPosition
|
||||
case clearWatch
|
||||
}
|
||||
|
||||
enum GeolocationError: Error {
|
||||
case locationServicesDisabled
|
||||
case permissionDenied
|
||||
case permissionRestricted
|
||||
case positionUnavailable
|
||||
case inputArgumentsIssue(target: GeolocationMethod)
|
||||
|
||||
func toCodeMessagePair() -> (String, String) {
|
||||
("OS-PLUG-GLOC-\(String(format: "%04d", code))", description)
|
||||
}
|
||||
}
|
||||
|
||||
private extension GeolocationError {
|
||||
var code: Int {
|
||||
switch self {
|
||||
case .positionUnavailable: 2
|
||||
case .permissionDenied: 3
|
||||
case .locationServicesDisabled: 7
|
||||
case .permissionRestricted: 8
|
||||
case .inputArgumentsIssue(let target):
|
||||
switch target {
|
||||
case .getCurrentPosition: 4
|
||||
case .watchPosition: 5
|
||||
case .clearWatch: 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .positionUnavailable: "There was en error trying to obtain the location."
|
||||
case .permissionDenied: "Location permission request was denied."
|
||||
case .locationServicesDisabled: "Location services are not enabled."
|
||||
case .permissionRestricted: "Application's use of location services was restricted."
|
||||
case .inputArgumentsIssue(let target): "The '\(target.rawValue)' input parameters aren't valid."
|
||||
}
|
||||
}
|
||||
}
|
||||
228
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationPlugin.swift
generated
vendored
Normal file
228
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/GeolocationPlugin.swift
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
import Capacitor
|
||||
import IONGeolocationLib
|
||||
import UIKit
|
||||
|
||||
import Combine
|
||||
|
||||
@objc(GeolocationPlugin)
|
||||
public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "GeolocationPlugin"
|
||||
public let jsName = "Geolocation"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
.init(name: "getCurrentPosition", returnType: CAPPluginReturnPromise),
|
||||
.init(name: "watchPosition", returnType: CAPPluginReturnCallback),
|
||||
.init(name: "clearWatch", returnType: CAPPluginReturnPromise),
|
||||
.init(name: "checkPermissions", returnType: CAPPluginReturnPromise),
|
||||
.init(name: "requestPermissions", returnType: CAPPluginReturnPromise)
|
||||
]
|
||||
|
||||
private var locationService: (any IONGLOCService)?
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
private var locationCancellable: AnyCancellable?
|
||||
private var callbackManager: GeolocationCallbackManager?
|
||||
private var statusInitialized = false
|
||||
private var locationInitialized: Bool = false
|
||||
|
||||
override public func load() {
|
||||
self.locationService = IONGLOCManagerWrapper()
|
||||
self.callbackManager = .init(capacitorBridge: bridge)
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(appDidBecomeActive),
|
||||
name: UIApplication.didBecomeActiveNotification,
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func appDidBecomeActive() {
|
||||
if let watchCallbacksEmpty = callbackManager?.watchCallbacks.isEmpty, !watchCallbacksEmpty {
|
||||
print("App became active. Restarting location monitoring for watch callbacks.")
|
||||
locationCancellable?.cancel()
|
||||
locationCancellable = nil
|
||||
locationInitialized = false
|
||||
|
||||
locationService?.stopMonitoringLocation()
|
||||
locationService?.startMonitoringLocation()
|
||||
bindLocationPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@objc func getCurrentPosition(_ call: CAPPluginCall) {
|
||||
shouldSetupBindings()
|
||||
let enableHighAccuracy = call.getBool(Constants.Arguments.enableHighAccuracy, false)
|
||||
handleLocationRequest(enableHighAccuracy, call: call)
|
||||
}
|
||||
|
||||
@objc func watchPosition(_ call: CAPPluginCall) {
|
||||
shouldSetupBindings()
|
||||
let enableHighAccuracy = call.getBool(Constants.Arguments.enableHighAccuracy, false)
|
||||
let watchUUID = call.callbackId
|
||||
handleLocationRequest(enableHighAccuracy, watchUUID: watchUUID, call: call)
|
||||
}
|
||||
|
||||
@objc func clearWatch(_ call: CAPPluginCall) {
|
||||
shouldSetupBindings()
|
||||
guard let callbackId = call.getString(Constants.Arguments.id) else {
|
||||
callbackManager?.sendError(.inputArgumentsIssue(target: .clearWatch))
|
||||
return
|
||||
}
|
||||
callbackManager?.clearWatchCallbackIfExists(callbackId)
|
||||
|
||||
if (callbackManager?.watchCallbacks.isEmpty) ?? false {
|
||||
locationService?.stopMonitoringLocation()
|
||||
locationCancellable?.cancel()
|
||||
locationCancellable = nil
|
||||
locationInitialized = false
|
||||
}
|
||||
|
||||
callbackManager?.sendSuccess(call)
|
||||
}
|
||||
|
||||
@objc override public func checkPermissions(_ call: CAPPluginCall) {
|
||||
guard checkIfLocationServicesAreEnabled(call) else { return }
|
||||
|
||||
let status = switch locationService?.authorisationStatus {
|
||||
case .restricted, .denied: Constants.AuthorisationStatus.Status.denied
|
||||
case .authorisedAlways, .authorisedWhenInUse: Constants.AuthorisationStatus.Status.granted
|
||||
default: Constants.AuthorisationStatus.Status.prompt
|
||||
}
|
||||
|
||||
let callResultData = [
|
||||
Constants.AuthorisationStatus.ResultKey.location: status,
|
||||
Constants.AuthorisationStatus.ResultKey.coarseLocation: status
|
||||
]
|
||||
callbackManager?.sendSuccess(call, with: callResultData)
|
||||
}
|
||||
|
||||
@objc override public func requestPermissions(_ call: CAPPluginCall) {
|
||||
guard checkIfLocationServicesAreEnabled(call) else { return }
|
||||
|
||||
if locationService?.authorisationStatus == .notDetermined {
|
||||
shouldSetupBindings()
|
||||
callbackManager?.addRequestPermissionsCallback(capacitorCall: call)
|
||||
} else {
|
||||
checkPermissions(call)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension GeolocationPlugin {
|
||||
func shouldSetupBindings() {
|
||||
bindAuthorisationStatusPublisher()
|
||||
bindLocationPublisher()
|
||||
}
|
||||
|
||||
func bindAuthorisationStatusPublisher() {
|
||||
guard !statusInitialized else { return }
|
||||
statusInitialized = true
|
||||
locationService?.authorisationStatusPublisher
|
||||
.sink(receiveValue: { [weak self] status in
|
||||
guard let self else { return }
|
||||
|
||||
switch status {
|
||||
case .denied:
|
||||
self.onLocationPermissionNotGranted(error: .permissionDenied)
|
||||
case .notDetermined:
|
||||
self.requestLocationAuthorisation(type: .whenInUse)
|
||||
case .restricted:
|
||||
self.onLocationPermissionNotGranted(error: .permissionRestricted)
|
||||
case .authorisedAlways, .authorisedWhenInUse:
|
||||
self.onLocationPermissionGranted()
|
||||
@unknown default: break
|
||||
}
|
||||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func bindLocationPublisher() {
|
||||
guard !locationInitialized else { return }
|
||||
locationInitialized = true
|
||||
locationCancellable = locationService?.currentLocationPublisher
|
||||
.catch { [weak self] error -> AnyPublisher<IONGLOCPositionModel, Never> in
|
||||
print("An error was found while retrieving the location: \(error)")
|
||||
|
||||
if case IONGLOCLocationError.locationUnavailable = error {
|
||||
print("Location unavailable (likely due to backgrounding). Keeping watch callbacks alive.")
|
||||
self?.callbackManager?.sendError(.positionUnavailable)
|
||||
return Empty<IONGLOCPositionModel, Never>()
|
||||
.eraseToAnyPublisher()
|
||||
} else {
|
||||
self?.callbackManager?.sendError(.positionUnavailable)
|
||||
return Empty<IONGLOCPositionModel, Never>()
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
.sink(receiveValue: { [weak self] position in
|
||||
self?.callbackManager?.sendSuccess(with: position)
|
||||
})
|
||||
}
|
||||
|
||||
func requestLocationAuthorisation(type requestType: IONGLOCAuthorisationRequestType) {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
guard self.checkIfLocationServicesAreEnabled() else { return }
|
||||
self.locationService?.requestAuthorisation(withType: requestType)
|
||||
}
|
||||
}
|
||||
|
||||
func checkIfLocationServicesAreEnabled(_ call: CAPPluginCall? = nil) -> Bool {
|
||||
guard locationService?.areLocationServicesEnabled() == true else {
|
||||
call.map { callbackManager?.sendError($0, error: .locationServicesDisabled) }
|
||||
?? callbackManager?.sendError(.locationServicesDisabled)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func onLocationPermissionNotGranted(error: GeolocationError) {
|
||||
let shouldNotifyRequestPermissionsResult = callbackManager?.requestPermissionsCallbacks.isEmpty == false
|
||||
let shouldNotifyPermissionError = callbackManager?.locationCallbacks.isEmpty == false || callbackManager?.watchCallbacks.isEmpty == false
|
||||
|
||||
if shouldNotifyRequestPermissionsResult {
|
||||
self.callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.denied)
|
||||
}
|
||||
if shouldNotifyPermissionError {
|
||||
self.callbackManager?.sendError(error)
|
||||
}
|
||||
}
|
||||
|
||||
func onLocationPermissionGranted() {
|
||||
let shouldNotifyPermissionGranted = callbackManager?.requestPermissionsCallbacks.isEmpty == false
|
||||
// should request location if callbacks below exist and are not empty
|
||||
let shouldRequestCurrentPosition = callbackManager?.locationCallbacks.isEmpty == false
|
||||
let shouldRequestLocationMonitoring = callbackManager?.watchCallbacks.isEmpty == false
|
||||
|
||||
if shouldNotifyPermissionGranted {
|
||||
callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.granted)
|
||||
}
|
||||
if shouldRequestCurrentPosition {
|
||||
locationService?.requestSingleLocation()
|
||||
}
|
||||
if shouldRequestLocationMonitoring {
|
||||
locationService?.startMonitoringLocation()
|
||||
}
|
||||
}
|
||||
|
||||
func handleLocationRequest(_ enableHighAccuracy: Bool, watchUUID: String? = nil, call: CAPPluginCall) {
|
||||
bindLocationPublisher()
|
||||
let configurationModel = IONGLOCConfigurationModel(enableHighAccuracy: enableHighAccuracy)
|
||||
locationService?.updateConfiguration(configurationModel)
|
||||
|
||||
if let watchUUID {
|
||||
callbackManager?.addWatchCallback(watchUUID, capacitorCall: call)
|
||||
} else {
|
||||
callbackManager?.addLocationCallback(capacitorCall: call)
|
||||
}
|
||||
|
||||
switch locationService?.authorisationStatus {
|
||||
case .authorisedAlways, .authorisedWhenInUse: onLocationPermissionGranted()
|
||||
case .denied: callbackManager?.sendError(.permissionDenied)
|
||||
case .restricted: callbackManager?.sendError(.permissionRestricted)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
23
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift
generated
vendored
Normal file
23
node_modules/@capacitor/geolocation/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import Capacitor
|
||||
import IONGeolocationLib
|
||||
|
||||
extension IONGLOCPositionModel {
|
||||
func toJSObject() -> JSObject {
|
||||
[
|
||||
Constants.Position.timestamp: timestamp,
|
||||
Constants.Position.coords: coordsJSObject
|
||||
]
|
||||
}
|
||||
|
||||
private var coordsJSObject: JSObject {
|
||||
[
|
||||
Constants.Position.altitude: altitude,
|
||||
Constants.Position.heading: course,
|
||||
Constants.Position.accuracy: horizontalAccuracy,
|
||||
Constants.Position.latitude: latitude,
|
||||
Constants.Position.longitude: longitude,
|
||||
Constants.Position.speed: speed,
|
||||
Constants.Position.altitudeAccuracy: verticalAccuracy
|
||||
]
|
||||
}
|
||||
}
|
||||
15
node_modules/@capacitor/geolocation/ios/Tests/GeolocationTests/GeolocationTests.swift
generated
vendored
Normal file
15
node_modules/@capacitor/geolocation/ios/Tests/GeolocationTests/GeolocationTests.swift
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import XCTest
|
||||
@testable import GeolocationCapacitorPlugin
|
||||
|
||||
class GeolocationPluginCapacitorTests: XCTestCase {
|
||||
func testEcho() {
|
||||
// This is an example of a functional test case for a plugin.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
|
||||
let implementation = GeolocationPluginCapacitor()
|
||||
let value = "Hello, World!"
|
||||
let result = implementation.echo(value)
|
||||
|
||||
XCTAssertEqual(value, result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user