Skip to content
Merged
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
61 changes: 61 additions & 0 deletions packages/geolocator_watchos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,64 @@
## 0.2.0

**Breaking**

* `GeolocatorWatchosBackend`, the public seam tests fake, changed shape:
`requestLocation` takes the accuracy index; `stopLocationRequest`,
`positionCount`, `accuracyAuthorization`, `requestTemporaryFullAccuracy`
and `accuracyRequestsDone` are new; `startUpdates` takes `activityType` and
`allowBackground`. The native callback now carries a
`GeolocatorWatchosSignal` kind.
* `getPositionStream` called while a stream runs returns that stream, with
the settings it started with, as geolocator_apple does. A second stream
with other settings used to replace the first one's.

**Added**

* `getLocationAccuracy` reports `accuracyAuthorization`: precise or reduced.
* `requestTemporaryFullAccuracy` asks for full accuracy with a purpose key and
waits for the answer. Without `NSLocationTemporaryUsageDescriptionDictionary`
in the `Info.plist` it throws `PermissionDefinitionsNotFoundException`, as
geolocator does on iOS.
* `getServiceStatusStream` starts with the current status, then reports each
change CoreLocation signals. It reads the services switch only when
CoreLocation reports an authorization change, not on every fix.
* `AppleSettings` passed to `getPositionStream` now reach CoreLocation, read
through `toJson()`: `activityType` (for example `ActivityType.fitness` for
a run) and `allowBackgroundLocationUpdates`, which `AppleSettings` turns on
by default. Background updates turn on only when the `Info.plist`'s
`UIBackgroundModes` has `location`, because CoreLocation asserts otherwise;
`location` under `WKBackgroundModes` does not count (checked on the
watchOS 27.0 Simulator). A stream without `AppleSettings` gets
`CLActivityTypeOther`, not the previous stream's type.
`ActivityType.maritime` is `CLActivityTypeMaritime` when built with the
watchOS 27 SDK and run on watchOS 27, and `CLActivityTypeOtherNavigation`
otherwise, as in geolocator_apple; the package still builds with Xcode 26.
* Five FFI exports: `geolocator_watchos_accuracy_authorization`,
`_request_temporary_full_accuracy`, `_accuracy_requests_done`,
`_stop_location_request` and `_position_count`.
`geolocator_watchos_start_updates` takes the activity type and the
background flag, and `geolocator_watchos_request_location` the accuracy.

**Fixed**

* `getCurrentPosition` has a `CLLocationManager` of its own, as in
geolocator_apple, so it no longer waits on a running stream's distance
filter, which timed it out when the wearer stood still, nor stops or
reconfigures the stream. It skips cached fixes more than 5 seconds old,
which CoreLocation hands over first; a running stream's next fix answers
it too.
* A position stream emits every fix CoreLocation delivers, with no age
filter, as geolocator_apple's does: a reduced-accuracy fix can
legitimately be old.

**Docs**

* README and PORTING_REPORT: the three members move out of "Not supported on
watchOS"; a section on workouts and background updates, with App Review
guideline 2.5.4, and what is not yet checked on a physical watch.
* Comments no longer say that Dart polls the cached fix: the delegate wakes
Dart.

## 0.1.1

* README: the install snippet names `geolocator: ^14.1.1` and this version.
Expand Down
12 changes: 7 additions & 5 deletions packages/geolocator_watchos/PORTING_REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
| Aspect | Result |
|---|---|
| Implementation | ✅ Working (CoreLocation FFI) |
| watchOS capability | Full — query, permission, and position stream |
| watchOS capability | Full — query, permission, accuracy, service status, and position stream. Accuracy, service status and the `AppleSettings` fields are checked by host tests; the temporary full-accuracy prompt and background updates are not yet checked on a physical watch |
| Host unit tests (`flutter-watchos test`) | ✅ pass |
| Upstream integration test | ○ none upstream (Baseflow manual demo) — verified by building + running the example on-sim |
| Internal unified demo | ✅ included |
Expand Down Expand Up @@ -70,11 +70,13 @@ watchOS" table lists the ✗ rows.
| `checkPermission` / `requestPermission` | ✅ when-in-use authorization |
| `isLocationServiceEnabled` | ✅ |
| `getLastKnownPosition` | ✅ the last cached fix |
| `getCurrentPosition` / `getPositionStream` | ✅ pushed by the `CLLocationManager` delegate |
| `getCurrentPosition` | ✅ a `CLLocationManager` of its own, as in geolocator_apple; skips cached fixes more than 5 seconds old |
| `getPositionStream` | ✅ pushed by the `CLLocationManager` delegate, every fix; a second call while one runs gets that stream, as from geolocator_apple |
| `distanceBetween` / `bearingBetween` | ✅ the interface's own Dart code |
| `getServiceStatusStream` | ✗ throws `UnimplementedError` when called: not implemented yet |
| `getLocationAccuracy` | ✗ fails with `UnimplementedError`: not implemented yet |
| `requestTemporaryFullAccuracy` | ✗ fails with `UnimplementedError`: not implemented |
| `getServiceStatusStream` | ✅ starts with the current status, then each change CoreLocation reports |
| `getLocationAccuracy` | ✅ `accuracyAuthorization`: precise or reduced |
| `requestTemporaryFullAccuracy` | ◐ `requestTemporaryFullAccuracyAuthorizationWithPurposeKey`; throws `PermissionDefinitionsNotFoundException` without `NSLocationTemporaryUsageDescriptionDictionary`, as on iOS |
| `AppleSettings` (via `toJson()`) | ◐ `activityType` (maritime from the watchOS 27 SDK and watchOS 27 on, `otherNavigation` before, as in geolocator_apple) and `allowBackgroundLocationUpdates` (only with `location` in `UIBackgroundModes`); `pauseLocationUpdatesAutomatically` and `showBackgroundLocationIndicator` do not exist on watchOS |
| `openAppSettings` / `openLocationSettings` | ✗ fail with `UnimplementedError`: watchOS has no settings page an app can open |

---
Expand Down
56 changes: 50 additions & 6 deletions packages/geolocator_watchos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ The watchOS implementation of [`geolocator`](https://pub.dev/packages/geolocator
Location comes from **CoreLocation** (`CLLocationManager`) over dart:ffi: the
delegate caches the latest fix and **pushes** a signal into Dart. The position
stream, `getCurrentPosition` and `requestPermission` all wait on it — nothing
polls.
polls. As in geolocator_apple, the position stream and `getCurrentPosition`
each have a location manager of their own.

> Scaffolded by [`flutter-watchos plugin port`](https://github.com/flutterwatch/flutter-watchos)
> from `geolocator_apple`, then implemented and verified by hand.
Expand All @@ -18,7 +19,7 @@ This is a federated plugin implementation. Apps that already depend on
```yaml
dependencies:
geolocator: ^14.1.1
geolocator_watchos: ^0.1.1
geolocator_watchos: ^0.2.0
```

The plugin registers automatically via Flutter's federated registry — no
Expand All @@ -37,12 +38,58 @@ Add a location usage description to the watch app's `Info.plist`:
|---|---|
| `checkPermission` / `requestPermission` | supported (when-in-use) |
| `isLocationServiceEnabled` | supported |
| `getCurrentPosition` / `getPositionStream` | supported |
| `getCurrentPosition` | supported; skips cached fixes more than 5 seconds old, and does not wait on a running stream |
| `getPositionStream` | supported; while a stream runs, a second call gets it, with its settings, as from geolocator_apple |
| `getLastKnownPosition` | supported (last cached fix) |
| `getLocationAccuracy` | supported (precise or reduced) |
| `requestTemporaryFullAccuracy` | supported; needs `NSLocationTemporaryUsageDescriptionDictionary` |
| `getServiceStatusStream` | supported; starts with the current status |

The watch has no *Always* background-location entitlement flow that iOS has;
authorization is when-in-use.

### Workouts and background updates

`AppleSettings` from `geolocator`, passed to `getPositionStream`, reaches
CoreLocation here too: `activityType` sets `CLLocationManager.activityType`,
and `allowBackgroundLocationUpdates`, which `AppleSettings` turns on by
default, sets `allowsBackgroundLocationUpdates`. A running or cycling app
passes `ActivityType.fitness`:

```dart
Geolocator.getPositionStream(
locationSettings: AppleSettings(
accuracy: LocationAccuracy.bestForNavigation,
activityType: ActivityType.fitness,
allowBackgroundLocationUpdates: true,
),
);
```

Background updates turn on only when the `Info.plist`'s `UIBackgroundModes`
has `location`; without it the setting is ignored, because CoreLocation
asserts and the app ends otherwise. It has to be `UIBackgroundModes`, also on
the watch: `location` under `WKBackgroundModes` does not count and still
trips the assertion.

```xml
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
```
App Review accepts background location only for a feature that needs it
(App Review Guideline 2.5.4); say what it is for in the usage description.

`pauseLocationUpdatesAutomatically` and `showBackgroundLocationIndicator` do
not exist on watchOS and are ignored. `ActivityType.maritime` needs the
watchOS 27 SDK and watchOS 27; otherwise it is `otherNavigation`, as in
geolocator_apple. An app recording a workout keeps running with the wrist
down through its `HKWorkoutSession`, not through this setting.

Not yet checked on a physical watch: the temporary full-accuracy prompt, and
updates with the wrist down.

## Status

| Platform | Implemented |
Expand All @@ -62,9 +109,6 @@ These members of `geolocator_platform_interface` 4.4.0 throw or fail on watchOS.

| Member | On watchOS | Why |
|---|---|---|
| `getServiceStatusStream` | throws `UnimplementedError` when called | not implemented yet |
| `getLocationAccuracy` | fails with `UnimplementedError` | not implemented yet |
| `requestTemporaryFullAccuracy` | fails with `UnimplementedError` | not implemented |
| `openAppSettings` / `openLocationSettings` | fail with `UnimplementedError` | watchOS has no settings page an app can open |

## License
Expand Down
Loading
Loading