Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tvOS #38

Merged
merged 5 commits into from
Jun 21, 2023
Merged

tvOS #38

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Swift Package Manager](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat)](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat)
[![Swift](https://img.shields.io/badge/Swift-5.5-orange?style=flat)](https://img.shields.io/badge/Swift-5.5-Orange?style=flat)
[![Platforms](https://img.shields.io/badge/platforms-iOS--13%20|%20macOS(beta)%20|%20watchOS--6(beta)-orange?style=flat)](https://img.shields.io/badge/platforms-iOS--13%20|%20macOS(beta)-orange?style=flat)
[![Platforms](https://img.shields.io/badge/platforms-iOS--13%20|%20macOS(beta)%20|%20watchOS--6(beta)%20|%20tvOS(beta)-orange?style=flat)](https://img.shields.io/badge/platforms-iOS--13%20|%20macOS(beta)%20|%20watchOS--6(beta)%20|%20tvOS(beta)-orange?style=flat)

Wrapper for Apple `CoreLocation` framework with new Concurency Model. No more `delegate` pattern or `completion blocks`.

Expand Down
25 changes: 19 additions & 6 deletions Sources/AsyncLocationKit/AsyncLocationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public typealias HeadingMonitorStream = AsyncStream<HeadingMonitorEvent>
public typealias AuthorizationStream = AsyncStream<AuthorizationEvent>
public typealias AccuracyAuthorizationStream = AsyncStream<AccuracyAuthorizationEvent>
@available(watchOS, unavailable)
@available(tvOS, unavailable)
public typealias BeaconsRangingStream = AsyncStream<BeaconRangeEvent>

public final class AsyncLocationManager {
Expand All @@ -51,7 +52,9 @@ public final class AsyncLocationManager {
locationDelegate = LocationDelegate(delegateProxy: proxyDelegate)
self.locationManager.delegate = locationDelegate
self.locationManager.desiredAccuracy = desiredAccuracy.convertingAccuracy
#if !os(tvOS)
self.locationManager.allowsBackgroundLocationUpdates = allowsBackgroundLocationUpdates
#endif
}


Expand All @@ -64,7 +67,7 @@ public final class AsyncLocationManager {

@available(watchOS 6.0, *)
public func getAuthorizationStatus() -> CLAuthorizationStatus {
if #available(iOS 14, watchOS 7, *) {
if #available(iOS 14, tvOS 14, watchOS 7, *) {
return locationManager.authorizationStatus
} else {
return CLLocationManager.authorizationStatus()
Expand Down Expand Up @@ -116,7 +119,7 @@ public final class AsyncLocationManager {
proxyDelegate.cancel(for: AccuracyAuthorizationMonitoringPerformer.self)
}

@available(iOS 14, watchOS 7, *)
@available(iOS 14, tvOS 14, watchOS 7, *)
public func getAccuracyAuthorization() -> CLAccuracyAuthorization {
locationManager.accuracyAuthorization
}
Expand All @@ -125,6 +128,7 @@ public final class AsyncLocationManager {
locationManager.desiredAccuracy = newAccuracy.convertingAccuracy
}

@available(tvOS, unavailable)
public func updateAllowsBackgroundLocationUpdates(with newAllows: Bool) {
locationManager.allowsBackgroundLocationUpdates = newAllows
}
Expand All @@ -149,7 +153,7 @@ public final class AsyncLocationManager {
})
}

#if !APPCLIP
#if !APPCLIP && !os(tvOS)
@available(*, deprecated, message: "Use new function requestPermission(with:)")
@available(watchOS 7.0, *)
@available(iOS 14, *)
Expand Down Expand Up @@ -195,11 +199,12 @@ public final class AsyncLocationManager {
}
}

@available(iOS 14, watchOS 7, *)
@available(iOS 14, tvOS 14, watchOS 7, *)
public func requestTemporaryFullAccuracyAuthorization(purposeKey: String) async throws -> CLAccuracyAuthorization? {
try await locationPermissionTemporaryFullAccuracy(purposeKey: purposeKey)
}

@available(tvOS, unavailable)
public func startUpdatingLocation() async -> LocationStream {
let monitoringPerformer = MonitoringUpdateLocationPerformer()
return LocationStream { streamContinuation in
Expand Down Expand Up @@ -231,6 +236,7 @@ public final class AsyncLocationManager {
}

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public func startMonitoring(for region: CLRegion) async -> RegionMonitoringStream {
let performer = RegionMonitoringPerformer(region: region)
return RegionMonitoringStream { streamContinuation in
Expand All @@ -244,6 +250,7 @@ public final class AsyncLocationManager {
}

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public func stopMonitoring(for region: CLRegion) {
proxyDelegate.cancel(for: RegionMonitoringPerformer.self) { regionMonitoring in
guard let regionPerformer = regionMonitoring as? RegionMonitoringPerformer else { return false }
Expand All @@ -253,6 +260,7 @@ public final class AsyncLocationManager {
}

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public func startMonitoringVisit() async -> VisitMonitoringStream {
let performer = VisitMonitoringPerformer()
return VisitMonitoringStream { stream in
Expand All @@ -266,6 +274,7 @@ public final class AsyncLocationManager {
}

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public func stopMonitoringVisit() {
proxyDelegate.cancel(for: VisitMonitoringPerformer.self)
locationManager.stopMonitoringVisits()
Expand All @@ -292,6 +301,7 @@ public final class AsyncLocationManager {
#endif

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public func startRangingBeacons(satisfying: CLBeaconIdentityConstraint) async -> BeaconsRangingStream {
let performer = BeaconsRangePerformer(satisfying: satisfying)
return BeaconsRangingStream { stream in
Expand All @@ -305,6 +315,7 @@ public final class AsyncLocationManager {
}

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public func stopRangingBeacons(satisfying: CLBeaconIdentityConstraint) {
proxyDelegate.cancel(for: BeaconsRangePerformer.self) { beaconsMonitoring in
guard let beaconsPerformer = beaconsMonitoring as? BeaconsRangePerformer else { return false }
Expand Down Expand Up @@ -346,12 +357,14 @@ extension AsyncLocationManager {
locationManager.requestAlwaysAuthorization()
}
#else
if #available(iOS 14, watchOS 7, *), locationManager.authorizationStatus != .notDetermined && locationManager.authorizationStatus != .authorizedWhenInUse {
if #available(iOS 14, tvOS 14, watchOS 7, *), locationManager.authorizationStatus != .notDetermined && locationManager.authorizationStatus != .authorizedWhenInUse {
continuation.resume(with: .success(locationManager.authorizationStatus))
} else {
#if !os(tvOS)
authorizationPerformer.linkContinuation(continuation)
proxyDelegate.addPerformer(authorizationPerformer)
locationManager.requestAlwaysAuthorization()
#endif
}
#endif
}
Expand All @@ -360,7 +373,7 @@ extension AsyncLocationManager {
})
}

@available(iOS 14, watchOS 7, *)
@available(iOS 14, tvOS 14, watchOS 7, *)
private func locationPermissionTemporaryFullAccuracy(purposeKey: String) async throws -> CLAccuracyAuthorization? {
let authorizationPerformer = RequestAccuracyAuthorizationPerformer()
return try await withTaskCancellationHandler(operation: {
Expand Down
5 changes: 5 additions & 0 deletions Sources/AsyncLocationKit/CoreLocationEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,19 @@ enum CoreLocationDelegateEvent {
case didChangeAccuracyAuthorization(authorization: CLAccuracyAuthorization)
// MARK: - Location events
case didUpdate(locations: [CLLocation])
@available(tvOS, unavailable)
case didUpdateHeading(heading: CLHeading)

@available(watchOS, unavailable)
@available(tvOS, unavailable)
case didDetermine(state: CLRegionState, forRegion: CLRegion)

// MARK: - Beacons events
@available(watchOS, unavailable)
@available(tvOS, unavailable)
case didRange(beacons: [CLBeacon], beaconConstraint: CLBeaconIdentityConstraint)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
case didFailRanginFor(beaconConstraint: CLBeaconIdentityConstraint, error: Error)
// MARK: - Region events
case didEnterRegion(region: CLRegion)
Expand All @@ -50,6 +54,7 @@ enum CoreLocationDelegateEvent {
case monitoringDidFailFor(region: CLRegion?, error: Error)
// MARK: - Visit event
@available(watchOS, unavailable)
@available(tvOS, unavailable)
case didVisit(visit: CLVisit)
// MARK: - Pause and resume events
case locationUpdatesPaused
Expand Down
6 changes: 3 additions & 3 deletions Sources/AsyncLocationKit/Helpers/NotificationNames.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// SOFTWARE.

import Foundation
#if os(iOS)
#if os(iOS) || os(tvOS)
import UIKit
#elseif os(macOS)
import AppKit
Expand All @@ -31,15 +31,15 @@ import WatchKit

@available(macOS 12, iOS 13, tvOS 13, watchOS 8, *)
struct NotificationNamesConstants {
#if os(iOS)
#if os(iOS) || os(tvOS)
static let willResignActiveName = UIApplication.willResignActiveNotification
#elseif os(macOS)
static let willResignActiveName = NSApplication.willResignActiveNotification
#elseif os(watchOS)
static let willResignActiveName = WKExtension.applicationWillResignActiveNotification
#endif

#if os(iOS)
#if os(iOS) || os(tvOS)
static let didBecomeActiveName = UIApplication.didBecomeActiveNotification
#elseif os(macOS)
static let didBecomeActiveName = NSApplication.didBecomeActiveNotification
Expand Down
8 changes: 5 additions & 3 deletions Sources/AsyncLocationKit/LocationDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal class LocationDelegate: NSObject, CLLocationManagerDelegate {

// MARK: - Authorize
@available(watchOS 7.0, *)
@available(iOS 14, *)
@available(iOS 14, tvOS 14, *)
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
proxy?.eventForMethodInvoked(.didChangeAuthorization(status: manager.authorizationStatus))
proxy?.eventForMethodInvoked(.didChangeAccuracyAuthorization(authorization: manager.accuracyAuthorization))
Expand All @@ -59,11 +59,13 @@ internal class LocationDelegate: NSObject, CLLocationManagerDelegate {
proxy?.eventForMethodInvoked(.didUpdate(locations: locations))
}

#if !os(tvOS)
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
proxy?.eventForMethodInvoked(.didUpdateHeading(heading: newHeading))
}
#endif

#if os(iOS) || os(tvOS)
#if os(iOS)
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
proxy?.eventForMethodInvoked(.didDetermine(state: state, forRegion: region))
}
Expand Down Expand Up @@ -96,7 +98,7 @@ internal class LocationDelegate: NSObject, CLLocationManagerDelegate {
proxy?.eventForMethodInvoked(.didFailWithError(error: error))
}

#if os(iOS) || os(tvOS)
#if os(iOS)
func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
proxy?.eventForMethodInvoked(.monitoringDidFailFor(region: region, error: error))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import Foundation
import CoreLocation

@available(watchOS, unavailable)
@available(tvOS, unavailable)
public enum BeaconRangeEvent {
case didRange(beacons: [CLBeacon], beaconConstraint: CLBeaconIdentityConstraint)
case didFailRanginFor(beaconConstraint: CLBeaconIdentityConstraint, error: Error)
Expand All @@ -42,17 +43,21 @@ class BeaconsRangePerformer: AnyLocationPerformer {
var eventssupported: [CoreLocationEventSupport] = [.didRangeBeacons, .didFailRanginForBeaconConstraint]

@available(watchOS, unavailable)
@available(tvOS, unavailable)
var satisfying: CLBeaconIdentityConstraint

@available(watchOS, unavailable)
@available(tvOS, unavailable)
var stream: BeaconsRangingStream.Continuation?

@available(watchOS, unavailable)
@available(tvOS, unavailable)
init(satisfying: CLBeaconIdentityConstraint) {
self.satisfying = satisfying
}

@available(watchOS, unavailable)
@available(tvOS, unavailable)
func linkContinuation(_ continuation: BeaconsRangingStream.Continuation) {
self.stream = continuation
}
Expand All @@ -63,10 +68,12 @@ class BeaconsRangePerformer: AnyLocationPerformer {

func invokedMethod(event: CoreLocationDelegateEvent) {
switch event {
#if !os(tvOS)
case .didRange(let beacons, let beaconConstraint):
stream?.yield(.didRange(beacons: beacons, beaconConstraint: beaconConstraint))
case .didFailRanginFor(let beaconConstraint, let error):
stream?.yield(.didFailRanginFor(beaconConstraint: beaconConstraint, error: error))
#endif
default:
fatalError("Method can't be execute by this performer: \(String(describing: self)) for event: \(type(of: event))")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import Foundation
import CoreLocation.CLHeading

public enum HeadingMonitorEvent {
@available(tvOS, unavailable)
case didUpdate(heading: CLHeading)
case didFailWith(error: Error)
}
Expand All @@ -49,8 +50,10 @@ class HeadingMonitorPerformer: AnyLocationPerformer {

func invokedMethod(event: CoreLocationDelegateEvent) {
switch event {
#if !os(tvOS)
case .didUpdateHeading(let heading):
stream?.yield(.didUpdate(heading: heading))
#endif
case .didFailWithError(let error):
stream?.yield(.didFailWith(error: error))
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import CoreLocation.CLVisit

public enum VisitMonitoringEvent {
@available(watchOS, unavailable)
@available(tvOS, unavailable)
case didVisit(visit: CLVisit)
case didFailWithError(error: Error)
}
Expand Down Expand Up @@ -53,7 +54,7 @@ class VisitMonitoringPerformer: AnyLocationPerformer {
case .didFailWithError(let error):
stream?.yield(.didFailWithError(error: error))
case .didVisit(let visit):
#if os(iOS) || os(tvOS)
#if os(iOS)
stream?.yield(.didVisit(visit: visit))
#endif
default:
Expand Down
2 changes: 2 additions & 0 deletions Tests/AsyncLocationKitTests/AsyncLocationKitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ final class AsyncLocationKitTests: XCTestCase {
}

func testAllowsBackgroundLocationUpdates() {
#if !os(tvOS)
let firstAllows = true
let locationManager = AsyncLocationManager(locationManager: AsyncLocationKitTests.mockLocationManager, allowsBackgroundLocationUpdates: firstAllows)
XCTAssertTrue(AsyncLocationKitTests.mockLocationManager.allowsBackgroundLocationUpdates == firstAllows)

let secondAllows = false
locationManager.updateAllowsBackgroundLocationUpdates(with: secondAllows)
XCTAssertTrue(AsyncLocationKitTests.mockLocationManager.allowsBackgroundLocationUpdates == secondAllows)
#endif
}

func testRequestLocation() async {
Expand Down
2 changes: 2 additions & 0 deletions Tests/AsyncLocationKitTests/LocationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import CoreLocation
class MockLocationManager: CLLocationManager {
private var mockAllowsBackgroundLocationUpdates: Bool = false

#if !os(tvOS)
override var allowsBackgroundLocationUpdates: Bool {
get {
return mockAllowsBackgroundLocationUpdates
Expand All @@ -19,6 +20,7 @@ class MockLocationManager: CLLocationManager {
mockAllowsBackgroundLocationUpdates = newValue
}
}
#endif

override var location: CLLocation? {
return CLLocation(latitude: 100, longitude: 200)
Expand Down