Skip to content

Commit 0e08058

Browse files
committed
Add LocationProvider.monitor()
1 parent c4f607c commit 0e08058

8 files changed

Lines changed: 183 additions & 113 deletions

README.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ On Android, the `app/src/main/AndroidManifest.xml` file will need to be edited t
2424

2525
## Location
2626

27-
You can request the current device location with:
27+
You can request a single current device location with:
2828

2929
```swift
3030
let provider = LocationProvider()
@@ -37,10 +37,12 @@ logger.log("latitude: \(location.latitude) longitude: \(location.longitude) alti
3737
In order to access the device's location, you will need to
3838
declare the permissions in the app's metadata.
3939

40-
On Android, the `app/src/main/AndroidManifest.xml` file will need to be edited to include:
40+
On Android, the `app/src/main/AndroidManifest.xml` file will need to be edited to include one of the
41+
following permissions:
4142

4243
```
43-
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
44+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
45+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
4446
```
4547

4648
On iOS, you will need to add the `NSLocationWhenInUseUsageDescription` key to your `Darwin/AppName.xcconfig` file:
@@ -100,6 +102,9 @@ The `GyroscopeProvider` type provides an `AsyncStream<GyroscopeEvent>` of device
100102
It can be used in a View like this:
101103

102104
```swift
105+
import SwiftUI
106+
import SkipDevice
107+
103108
struct GyroscopeView : View {
104109
@State var event: GyroscopeEvent?
105110

@@ -131,15 +136,18 @@ The `MagnetometerProvider` type provides an `AsyncStream<MagnetometerEvent>` of
131136
It can be used in a View like this:
132137

133138
```swift
139+
import SwiftUI
140+
import SkipDevice
141+
134142
struct MagnetometerView : View {
135143
@State var event: MagnetometerEvent?
136144

137145
var body: some View {
138146
VStack {
139147
if let event = event {
140-
Text("x: \(event.x)")
141-
Text("y: \(event.y)")
142-
Text("z: \(event.z)")
148+
Text("x: \(event.x)") // X-axis magnetic field in microteslas
149+
Text("y: \(event.y)") // Y-axis magnetic field in microteslas
150+
Text("z: \(event.z)") // Z-axis magnetic field in microteslas
143151
}
144152
}
145153
.font(Font.body.monospaced())
@@ -163,6 +171,9 @@ The `BarometerProvider` type provides an `AsyncStream<BarometerEvent>` of device
163171
It can be used in a View like this:
164172

165173
```swift
174+
import SwiftUI
175+
import SkipDevice
176+
166177
struct BarometerView : View {
167178
@State var event: BarometerEvent?
168179

Sources/SkipDevice/AccelerometerProvider.swift

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,6 @@ public class AccelerometerProvider {
2626
#elseif os(iOS) || os(watchOS)
2727
private let motionManager = CMMotionManager()
2828
#endif
29-
30-
public init() {
31-
}
32-
33-
deinit {
34-
stop()
35-
}
36-
3729
/// Set the update interval for the accelerometer. Must be set before `monitor()` is invoked.
3830
public var updateInterval: TimeInterval? {
3931
didSet {
@@ -45,6 +37,14 @@ public class AccelerometerProvider {
4537
}
4638
}
4739

40+
41+
public init() {
42+
}
43+
44+
deinit {
45+
stop()
46+
}
47+
4848
/// Returns `true` if the accelerometer is available on this device
4949
public var isAvailable: Bool {
5050
#if SKIP
@@ -68,30 +68,21 @@ public class AccelerometerProvider {
6868
}
6969

7070
// SKIP @nobridge // 'AsyncStream<AccelerometerEvent>' is not a bridged type
71-
public func monitor() -> AsyncStream<AccelerometerEvent> {
71+
public func monitor() -> AsyncThrowingStream<AccelerometerEvent, Error> {
7272
logger.debug("starting accelerometer monitor")
73-
let (stream, continuation) = AsyncStream.makeStream(of: AccelerometerEvent.self)
73+
let (stream, continuation) = AsyncThrowingStream.makeStream(of: AccelerometerEvent.self)
7474

7575
#if SKIP
76-
if let sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) {
77-
listener = SensorEventHandler(onSensorChangedCallback: { event in
78-
continuation.yield(AccelerometerEvent(event: event))
79-
})
80-
81-
// The rate sensor events are delivered at. This is only a hint to the system. Events may be received faster or slower than the specified rate. Usually events are received faster. The value must be one of SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, or SENSOR_DELAY_FASTEST or, the desired delay between events in microseconds.
82-
var interval = SensorManager.SENSOR_DELAY_NORMAL
83-
if let updateInterval {
84-
interval = Int(updateInterval * 1_000_000) // microseconds
85-
}
86-
sensorManager.registerListener(listener, sensor, interval)
76+
listener = sensorManager.startSensorUpdates(type: Sensor.TYPE_ACCELEROMETER, interval: updateInterval) { event in
77+
continuation.yield(AccelerometerEvent(event: event))
8778
}
8879
#elseif os(iOS) || os(watchOS)
8980
motionManager.startAccelerometerUpdates(to: OperationQueue.main) { data, error in
9081
if let error = error {
9182
logger.debug("accelerometer update error: \(error)")
92-
//continuation.finish(throwing: error) // would need to be AsyncThrowingStream
83+
continuation.yield(with: .failure(error))
9384
} else if let data = data {
94-
continuation.yield(AccelerometerEvent(data: data))
85+
continuation.yield(with: .success(AccelerometerEvent(data: data)))
9586
}
9687
}
9788
#endif

Sources/SkipDevice/BarometerProvider.swift

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public class BarometerProvider {
2727
#elseif os(iOS) || os(watchOS)
2828
private let altimeter = CMAltimeter()
2929
#endif
30+
/// Set the update interval for the magnetometer. Must be set before `monitor()` is invoked.
31+
public var updateInterval: TimeInterval?
3032

3133
public init() {
3234
}
@@ -35,9 +37,6 @@ public class BarometerProvider {
3537
stop()
3638
}
3739

38-
/// Set the update interval for the magnetometer. Must be set before `monitor()` is invoked.
39-
public var updateInterval: TimeInterval?
40-
4140
/// Returns `true` if the barometer is available on this device
4241
public var isAvailable: Bool {
4342
#if SKIP
@@ -62,34 +61,25 @@ public class BarometerProvider {
6261
}
6362

6463
// SKIP @nobridge // 'AsyncStream<BarometerEvent>' is not a bridged type
65-
public func monitor() -> AsyncStream<BarometerEvent> {
64+
public func monitor() -> AsyncThrowingStream<BarometerEvent, Error> {
6665
logger.debug("starting barometer monitor")
67-
let (stream, continuation) = AsyncStream.makeStream(of: BarometerEvent.self)
66+
let (stream, continuation) = AsyncThrowingStream.makeStream(of: BarometerEvent.self)
6867

6968
#if SKIP
70-
if let sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) {
71-
listener = SensorEventHandler(onSensorChangedCallback: { event in
72-
if self.referencePressure == nil {
73-
// remember the initial reading so we can calculate relative altitiude
74-
self.referencePressure = event.values[0]
75-
}
76-
continuation.yield(BarometerEvent(event: event, referencePressure: referencePressure!))
77-
})
78-
79-
// The rate sensor events are delivered at. This is only a hint to the system. Events may be received faster or slower than the specified rate. Usually events are received faster. The value must be one of SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, or SENSOR_DELAY_FASTEST or, the desired delay between events in microseconds.
80-
var interval = SensorManager.SENSOR_DELAY_NORMAL
81-
if let updateInterval {
82-
interval = Int(updateInterval * 1_000_000) // microseconds
69+
listener = sensorManager.startSensorUpdates(type: Sensor.TYPE_PRESSURE, interval: updateInterval) { event in
70+
if self.referencePressure == nil {
71+
// remember the initial reading so we can calculate relative altitiude
72+
self.referencePressure = event.values[0]
8373
}
84-
sensorManager.registerListener(listener, sensor, interval)
74+
continuation.yield(BarometerEvent(event: event, referencePressure: referencePressure!))
8575
}
8676
#elseif os(iOS) || os(watchOS)
8777
altimeter.startRelativeAltitudeUpdates(to: OperationQueue.main) { data, error in
8878
if let error = error {
8979
logger.debug("barometer update error: \(error)")
90-
//continuation.finish(throwing: error) // would need to be AsyncThrowingStream
80+
continuation.yield(with: .failure(error))
9181
} else if let data = data {
92-
continuation.yield(BarometerEvent(data: data))
82+
continuation.yield(with: .success(BarometerEvent(data: data)))
9383
}
9484
}
9585
#endif

Sources/SkipDevice/GyroscopeProvider.swift

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,6 @@ public class GyroscopeProvider {
2626
#elseif os(iOS) || os(watchOS)
2727
private let motionManager = CMMotionManager()
2828
#endif
29-
30-
public init() {
31-
}
32-
33-
deinit {
34-
stop()
35-
}
36-
3729
/// Set the update interval for the gyroscope. Must be set before `monitor()` is invoked.
3830
public var updateInterval: TimeInterval? {
3931
didSet {
@@ -45,6 +37,14 @@ public class GyroscopeProvider {
4537
}
4638
}
4739

40+
41+
public init() {
42+
}
43+
44+
deinit {
45+
stop()
46+
}
47+
4848
/// Returns `true` if the gyroscope is available on this device
4949
public var isAvailable: Bool {
5050
#if SKIP
@@ -68,30 +68,21 @@ public class GyroscopeProvider {
6868
}
6969

7070
// SKIP @nobridge // 'AsyncStream<GyroscopeEvent>' is not a bridged type
71-
public func monitor() -> AsyncStream<GyroscopeEvent> {
71+
public func monitor() -> AsyncThrowingStream<GyroscopeEvent, Error> {
7272
logger.debug("starting gyroscope monitor")
73-
let (stream, continuation) = AsyncStream.makeStream(of: GyroscopeEvent.self)
73+
let (stream, continuation) = AsyncThrowingStream.makeStream(of: GyroscopeEvent.self)
7474

7575
#if SKIP
76-
if let sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) {
77-
listener = SensorEventHandler(onSensorChangedCallback: { event in
78-
continuation.yield(GyroscopeEvent(event: event))
79-
})
80-
81-
// The rate sensor events are delivered at. This is only a hint to the system. Events may be received faster or slower than the specified rate. Usually events are received faster. The value must be one of SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, or SENSOR_DELAY_FASTEST or, the desired delay between events in microseconds.
82-
var interval = SensorManager.SENSOR_DELAY_NORMAL
83-
if let updateInterval {
84-
interval = Int(updateInterval * 1_000_000) // microseconds
85-
}
86-
sensorManager.registerListener(listener, sensor, interval)
76+
listener = sensorManager.startSensorUpdates(type: Sensor.TYPE_GYROSCOPE, interval: updateInterval) { event in
77+
continuation.yield(GyroscopeEvent(event: event))
8778
}
8879
#elseif os(iOS) || os(watchOS)
8980
motionManager.startGyroUpdates(to: OperationQueue.main) { data, error in
9081
if let error = error {
9182
logger.debug("gyroscope update error: \(error)")
92-
//continuation.finish(throwing: error) // would need to be AsyncThrowingStream
83+
continuation.yield(with: .failure(error))
9384
} else if let data = data {
94-
continuation.yield(GyroscopeEvent(data: data))
85+
continuation.yield(with: .success(GyroscopeEvent(data: data)))
9586
}
9687
}
9788
#endif

0 commit comments

Comments
 (0)