diff --git a/README.md b/README.md
index dd195c1..d37d800 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ at the time; the last full run on the Simulator is under
| [`sensors_plus_watchos`](packages/sensors_plus_watchos) [](https://pub.dev/packages/sensors_plus_watchos) | [`sensors_plus`](https://pub.dev/packages/sensors_plus) | CoreMotion (`CMMotionManager`) |
| [`local_auth_watchos`](packages/local_auth_watchos) [](https://pub.dev/packages/local_auth_watchos) | [`local_auth`](https://pub.dev/packages/local_auth) | LocalAuthentication (passcode) |
| [`geolocator_watchos`](packages/geolocator_watchos) [](https://pub.dev/packages/geolocator_watchos) | [`geolocator`](https://pub.dev/packages/geolocator) | CoreLocation (`CLLocationManager`) |
+| [`permission_handler_watchos`](packages/permission_handler_watchos) | [`permission_handler`](https://pub.dev/packages/permission_handler) | UserNotifications, and CoreLocation, CoreMotion, AVFAudio, Contacts, EventKit, CoreBluetooth and Intents loaded at runtime |
| [`sqflite_watchos`](packages/sqflite_watchos) | [`sqflite`](https://pub.dev/packages/sqflite) | The system SQLite (`libsqlite3`), its C API called from Dart |
| [`video_player_watchos`](packages/video_player_watchos) [](https://pub.dev/packages/video_player_watchos) | [`video_player`](https://pub.dev/packages/video_player) | AVFoundation + AVKit platform view |
| [`audioplayers_watchos`](packages/audioplayers_watchos) [](https://pub.dev/packages/audioplayers_watchos) | [`audioplayers`](https://pub.dev/packages/audioplayers) | AVFoundation (`AVPlayer`) |
diff --git a/packages/permission_handler_watchos/.gitignore b/packages/permission_handler_watchos/.gitignore
new file mode 100644
index 0000000..7b8ac9e
--- /dev/null
+++ b/packages/permission_handler_watchos/.gitignore
@@ -0,0 +1,23 @@
+# Dart / Flutter
+.dart_tool/
+build/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub/
+
+# Xcode / SwiftPM (per-user, generated when watchos/Package.swift is opened)
+**/.swiftpm/
+**/.build/
+**/xcuserdata/
+
+# flutter-watchos app wiring (generated in an app's watchos/, never a plugin's)
+watchos/Flutter/
+
+# IDE
+.idea/
+.vscode/
+*.iml
+
+# macOS
+.DS_Store
diff --git a/packages/permission_handler_watchos/CHANGELOG.md b/packages/permission_handler_watchos/CHANGELOG.md
new file mode 100644
index 0000000..b9425b2
--- /dev/null
+++ b/packages/permission_handler_watchos/CHANGELOG.md
@@ -0,0 +1,29 @@
+## 0.0.1
+
+First version, staged: checked on the watchOS 27.0 Simulator, not yet on a
+physical watch.
+
+* `PermissionHandlerWatchos` answers `permission_handler` on watchOS over
+ dart:ffi: status, service status and requests for location (when in use
+ and always), notifications, critical alerts, sensors, the microphone,
+ contacts, the calendar (full access and write only), reminders, Bluetooth
+ and Siri (`assistant`, for an app that sets `PermissionHandlerWatchosSiri`
+ in its Info.plist), with the iOS implementation's statuses and error
+ codes. `storage` is granted, as on iOS.
+* Each framework but UserNotifications is loaded at runtime instead of
+ linked. Every group's class names and selectors are still in the binary,
+ unlike the iOS implementation, whose build macros leave a group out;
+ whether App Store Connect's usage-description check reads them is not yet
+ known (see the README).
+* The location strategy keeps one flag in `NSUserDefaults`, so apps declare
+ `NSPrivacyAccessedAPICategoryUserDefaults` (`CA92.1`) in their privacy
+ manifest.
+* A request whose usage description is missing fails with
+ `MISSING_USAGE_DESCRIPTION` instead of the app being terminated. A request
+ while another waits fails with `ERROR_ALREADY_REQUESTING_PERMISSIONS`, as
+ on iOS. A location prompt closed without an answer answers denied, as on
+ iOS; watchOS sends no delegate call then, so the app becoming active
+ again is the answer.
+* The example's `lib/` is permission_handler_apple's own example,
+ unchanged, with `url_launcher_watchos` for its template's links; a
+ watchOS integration test checks the answers that need no prompt.
diff --git a/packages/permission_handler_watchos/LICENSE b/packages/permission_handler_watchos/LICENSE
new file mode 100644
index 0000000..bd6192f
--- /dev/null
+++ b/packages/permission_handler_watchos/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Baseflow
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/permission_handler_watchos/PORTING_REPORT.md b/packages/permission_handler_watchos/PORTING_REPORT.md
new file mode 100644
index 0000000..4b546fc
--- /dev/null
+++ b/packages/permission_handler_watchos/PORTING_REPORT.md
@@ -0,0 +1,157 @@
+# permission_handler_watchos — porting report
+
+## Verification status
+
+| Aspect | Result |
+|---|---|
+| Implementation | ✅ Working (FFI; one strategy per permission group, as in the iOS implementation) |
+| watchOS capability | ◐ The permissions watchOS has: location (when in use and always), notifications, critical alerts, sensors, microphone, contacts, calendar (full access and write only), reminders, Bluetooth, Siri; storage is granted as on iOS. The others answer as iOS answers for a permission it does not know |
+| Host unit tests (`flutter test`) | ✅ 8 pass |
+| Upstream integration test | ○ none upstream (Baseflow's example is a manual demo) |
+| watchOS integration test (`example/integration_test/permission_handler_test.dart`) | ✅ 5 pass on the watchOS 27.0 Simulator |
+| System prompts | ✅ asked for on the Simulator, each answered as on iOS: notification granted; location when in use granted; location always kept at "while using" → permanentlyDenied; sensors granted; microphone granted; contacts refused → permanentlyDenied; reminders granted; calendar write only granted. Bluetooth reads granted on the Simulator, which has no Bluetooth. After the review fixes, location when in use again: the prompt closed with the crown → answered, and a second request prompted again; allowed → granted; "always" asked for right after → its prompt stayed up until answered, kept at "while using" → permanentlyDenied. In upstream's example: calendar (full access) allowed → granted |
+| Critical alerts and Siri prompts | not yet asked for: each needs an entitlement the example does not have |
+| App Store Connect upload | not yet done: whether ITMS-90683 reads the class names of groups an app does not use is unchecked (see "Design") |
+| Example deviations | `example/pubspec.yaml` adds `url_launcher_watchos`, for the links of `baseflow_plugin_template`, which go through `url_launcher`. `example/lib/main.dart` is otherwise upstream's, formatted as this repo's CI checks |
+| Physical watch | not yet checked |
+
+Marking: ✅ full / passes · ◐ partial — reason given · ○ not applicable (no upstream test) · ✗ unsupported on watchOS.
+
+> This scaffold has been **finished by hand** into a working FFI package; see
+> the status above. The generated notes below are kept for provenance.
+
+## Design
+
+The iOS implementation compiles each permission group in or out with a
+preprocessor macro (`PERMISSION_CONTACTS=1` and so on, all off by default), so
+that an app does not reference an API it never asks for: App Store Connect
+warns about a missing usage description (ITMS-90683) for the privacy APIs a
+binary references. A watch app has no Podfile to set those macros, and the
+flutter-watchos CLI compiles plugin sources with fixed flags, so every group
+is compiled into every app. Each framework is loaded with `dlopen` and its
+classes looked up by name the first time a permission of its group is asked
+about, and only messaged; of the frameworks, only UserNotifications, which
+needs no usage description, is linked. `nm -u` on the compiled objects shows
+no class symbol of CoreLocation, CoreMotion, AVFAudio, Contacts, EventKit,
+CoreBluetooth or Intents. That is not the iOS result: the class names,
+selectors and delegate protocol metadata are still in the binary, and Apple
+does not document whether its check reads those. Until an App Store Connect
+upload of an app that uses only notifications shows no ITMS-90683, the README
+tells apps to expect to need every group's usage description. Leaving groups
+out at compile time needs a CLI feature.
+
+The location strategy keeps one flag in `NSUserDefaults` (whether "always"
+was asked for), a required-reason API; the iOS implementation ships a
+privacy manifest for the same reason. The README shows the entry an app's
+manifest needs.
+
+watchOS terminates an app that asks for a permission without its usage
+description. Before each prompt this package checks the Info.plist key the
+prompt needs and fails the request with a `PlatformException` whose code is
+`MISSING_USAGE_DESCRIPTION`, the code the iOS implementation uses for
+location, instead.
+
+Each call returns a request id at once; the strategy answers on its own
+queue, native keeps the answer as JSON, and wakes Dart through one
+`NativeCallable.listener` that carries a kind, never a payload. Dart asks for
+the permissions of `requestPermissions` one at a time, as the watch shows one
+prompt at a time.
+
+A location prompt closed without an answer, with the crown, sends no
+delegate call on watchOS, not even the second "not determined" report the
+iOS implementation takes as that (seen on the watchOS 27.0 Simulator). The
+app becoming active again answers then, if it resigned active since the
+request (the prompt taking the screen does that): with the status at that
+moment, or, if it is still "not determined" a second later, denied. An
+answer from the delegate in that second stands the re-read down, so a
+request made right after, such as "always" after "when in use", is not
+answered by it.
+
+An "always" location request kept at "while using" changes nothing, so
+CoreLocation sends no delegate call. As in the iOS implementation, the app
+becoming active again after the prompt (`WKApplicationDidBecomeActiveNotification`)
+is the answer then, and a second request answers without a prompt that
+watchOS would not show again.
+
+## Permission coverage
+
+| Permission | watchOS |
+|---|---|
+| `notification` | ✅ UNUserNotificationCenter: alert, sound and badge, as on iOS; provisional is reported. The iOS implementation also registers for remote notifications after a grant; this package does not, which is firebase_messaging_watchos's job on the watch |
+| `location`, `locationWhenInUse`, `locationAlways` | ✅ CLLocationManager; service status is `locationServicesEnabled` |
+| `sensors` | ✅ CMMotionActivityManager, asked for with an activity query as on iOS; service status is `isActivityAvailable` |
+| `microphone` | ✅ AVAudioApplication's record permission (watchOS 10 and later) |
+| `contacts` | ✅ CNContactStore; the watchOS SDK has no limited access |
+| `calendarFullAccess`, `calendarWriteOnly`, `calendar`, `reminders` | ✅ EKEventStore, with the full-access and write-only requests |
+| `bluetooth` | ✅ CBCentralManager: creating it asks, its first state update answers; service status is whether it is powered on |
+| `criticalAlerts` | ✅ UNUserNotificationCenter's critical alert setting and request; needs the Critical Alerts entitlement |
+| `assistant` | ◐ INPreferences (watchOS 6+), Siri, for an app that opts in; needs the Siri capability. INPreferences throws in an app without it (seen on the Simulator), so the Info.plist key `PermissionHandlerWatchosSiri` (`YES`) is the opt-in, in place of the iOS implementation's `PERMISSION_ASSISTANT` macro; `NSSiriUsageDescription`, which apps add with every other group's, does not switch it on. Without the opt-in the status is `denied` and so is a request; with it and no `NSSiriUsageDescription`, a request fails with `MISSING_USAGE_DESCRIPTION`. A per-app compile-time opt-in is #19 |
+| `storage` | ✅ granted, service not applicable, as on iOS |
+| `camera`, `photos`, `photosAddOnly`, `mediaLibrary`, `speech`, `appTrackingTransparency`, `backgroundRefresh`, `phone` | ✗ not on watchOS: `denied`, a request `permanentlyDenied`, service `disabled`, as iOS answers for an unknown permission |
+| The Android-only permissions | answered as an unknown permission, as on iOS |
+
+## Interface coverage
+
+| Member | watchOS |
+|---|---|
+| `checkPermissionStatus` | ✅ |
+| `checkServiceStatus` | ✅ |
+| `requestPermissions` | ✅ one at a time; another call while one waits fails with `ERROR_ALREADY_REQUESTING_PERMISSIONS`, as on iOS |
+| `shouldShowRequestPermissionRationale` | ✅ false, as on iOS |
+| `openAppSettings` | ✗ false: watchOS has no settings page an app can open |
+
+## Example
+
+`example/lib/main.dart` is permission_handler_apple 9.6.3's own example,
+unchanged but for the formatting this repo's CI checks: a phone app on `baseflow_plugin_template` that lists every
+permission, shows its status and asks for it on a tap. It runs on the watch,
+cramped but usable (on the watchOS 27.0 Simulator a calendar request from it
+prompted and answered granted). The example's pubspec adds what it imports,
+`baseflow_plugin_template` and `permission_handler_platform_interface`, and
+`url_launcher_watchos` for the template's links, which call url_launcher only
+when tapped; `res/images/` is upstream's. On the Simulator the template's
+info page opened, but its link buttons sit below a scroll area too small to
+reach there, so the links were not tapped. The Info.plist has the usage
+description of each permission. Upstream has no integration test, so
+`integration_test/permission_handler_test.dart` is this package's own; it
+imports only `permission_handler`.
+
+Generated by `flutter-watchos plugin port` on 2026-10-21.
+
+Source: `permission_handler_apple` 9.6.2 (path: `/Users/iamoguzhanarslantas/.pub-cache/hosted/pub.dev/permission_handler_apple-9.6.2`)
+Base platform: ios (Objective-C)
+Output: `./permission_handler_watchos`
+
+## APIs the source plugin used
+
+### Not available on watchOS
+
+These iOS/macOS APIs have **no watchOS equivalent** — the capability must be omitted or redesigned (often via the paired iPhone):
+
+| API | Used at | Why / watchOS note |
+|---|---|---|
+| AVCaptureCamera | `ios/permission_handler_apple/Sources/permission_handler_apple/strategies/AudioVideoPermissionStrategy.m:58` (+1 more) | AVFoundation exists on watchOS but the capture stack does not — there is no camera. Camera features must be omitted; the rest of the plugin's AVFoundation use (players, audio) can stay. |
+| CoreTelephony | `ios/permission_handler_apple/Sources/permission_handler_apple/strategies/PhonePermissionStrategy.m:8` (+6 more) | CoreTelephony is not available on watchOS — even cellular watch models do not expose carrier/cellular-plan APIs to apps. There is no watchOS replacement; the feature must be omitted. |
+| Photos | `ios/permission_handler_apple/Sources/permission_handler_apple/strategies/PhotoPermissionStrategy.h:11` (+4 more) | The Photos library framework is not available on watchOS. |
+| SpeechRecognition | `ios/permission_handler_apple/Sources/permission_handler_apple/strategies/SpeechPermissionStrategy.m:27` (+2 more) | The Speech framework is not available on watchOS. System dictation is reachable only through WatchKit text input (`presentTextInputController`), which the Flutter watchOS engine already drives for text fields — a custom speech pipeline has no watchOS port. |
+| UIApplication | `ios/permission_handler_apple/Sources/permission_handler_apple/strategies/BackgroundRefreshStrategy.m:25` (+4 more) | UIApplication does not exist on watchOS — the app object is WKApplication (watchOS 7+) / WKExtension. For opening URLs, use `openSystemURL(_:)`. It reliably handles tel: and sms:, and — despite the documentation listing only those — it also accepts http/https, presenting the system web sheet. Verified on a physical watch (watchOS 26.5): for a third-party app that sheet declines to render and shows "URL failed to load — this url can be viewed on your iPhone", even for a trivial page. Pair it with an NSUserActivity (NSUserActivityTypeBrowsingWeb) so the phone can actually pick the link up — see url_launcher_watchos. |
+
+### Available, but review
+
+These work on watchOS (often differently than iOS) — implement them, checking the note:
+
+| API | Used at | watchOS note |
+|---|---|---|
+| CoreLocation | `ios/permission_handler_apple/Sources/permission_handler_apple/strategies/LocationPermissionStrategy.m:17` (+9 more) | CoreLocation IS available on watchOS: requestLocation, continuous updates, and heading (watchOS 6+) work, with GPS on cellular/GPS models and phone-assisted fixes otherwise. Differences to review: authorization is shared with the paired iPhone app when one exists, region monitoring is limited, and background location needs a workout or background-refresh context. |
+
+## Checklist
+
+- [x] Declare your C functions in `watchos/Classes/permission_handler_watchos_ffi.h` and implement them in the `.m`, one per platform-interface method you support.
+- [x] List every exported symbol under `ffiSymbols` in `pubspec.yaml`, and the frameworks you link in `Package.swift`.
+- [x] Add a `lookupFunction` binding per symbol in the Dart `Bindings` class and override the platform-interface methods.
+- [x] Add the package to a watchOS app (`flutter-watchos create` one if needed), build for `watchsimulator`, then `nm` the binary to confirm your `ffiSymbols` are present (type `T`).
+- [x] Bump the version and update `CHANGELOG.md` before publishing.
+
+---
+
+See the finished plugins in the `flutterwatch/plugins` repo (e.g. `path_provider_watchos`, `battery_plus_watchos`) for worked examples of this exact shape.
diff --git a/packages/permission_handler_watchos/README.md b/packages/permission_handler_watchos/README.md
new file mode 100644
index 0000000..e6edce5
--- /dev/null
+++ b/packages/permission_handler_watchos/README.md
@@ -0,0 +1,116 @@
+# permission_handler_watchos
+
+The watchOS implementation of [`permission_handler`](https://pub.dev/packages/permission_handler).
+
+Scaffolded with [`flutter-watchos plugin port`](https://github.com/flutterwatch/flutter-watchos)
+from `permission_handler_apple` and finished by hand as an **FFI**
+implementation — see `PORTING_REPORT.md`.
+
+## Usage
+
+`permission_handler` does not include a watchOS implementation, so add this
+package alongside it:
+
+```yaml
+dependencies:
+ permission_handler: ^13.0.2
+ permission_handler_watchos: ^0.0.1
+```
+
+Use permission_handler as usual:
+
+```dart
+final PermissionStatus status = await Permission.locationWhenInUse.request();
+if (status.isGranted) {
+ // ...
+}
+```
+
+Add the usage description of each permission you ask for to the watch app's
+`watchos/Runner/Info.plist`, as on iOS: `NSLocationWhenInUseUsageDescription`,
+`NSLocationAlwaysAndWhenInUseUsageDescription`, `NSMotionUsageDescription`,
+`NSMicrophoneUsageDescription`, `NSContactsUsageDescription`,
+`NSCalendarsFullAccessUsageDescription`,
+`NSCalendarsWriteOnlyAccessUsageDescription`,
+`NSRemindersFullAccessUsageDescription`, `NSBluetoothAlwaysUsageDescription`,
+`NSSiriUsageDescription`. A request whose key is missing fails with a
+`PlatformException` whose code is `MISSING_USAGE_DESCRIPTION`, where watchOS
+would terminate the app. Siri also needs its own opt-in, only with the Siri
+capability (see `assistant` below), because asking about Siri without the
+capability ends the app.
+
+### App Review
+
+Every permission group's code is in every app that uses this package. The
+iOS implementation leaves a group out at compile time unless its build macro
+is set, so App Store Connect sees no privacy API an app does not use. A watch
+app has no Podfile to set such macros, and the flutter-watchos CLI compiles
+plugin sources with fixed flags. Here the frameworks other than
+UserNotifications are not linked and are loaded only when a permission of
+their group is asked about, but each group's class names, selectors and
+delegate metadata are still in the binary. Whether App Store Connect's check
+for missing usage descriptions (ITMS-90683) reads those is not documented,
+and no upload has checked it yet: until one has, expect an app to need the
+usage description of every group, the ones it never asks for included.
+
+The location strategy keeps one flag in `NSUserDefaults`, whether "always"
+was asked for, since watchOS shows that prompt once. `NSUserDefaults` is a
+required-reason API and this code is in every app that uses the package, so
+the app's privacy manifest (`PrivacyInfo.xcprivacy`) declares
+`NSPrivacyAccessedAPICategoryUserDefaults` with reason `CA92.1`:
+
+```xml
+NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+```
+
+## Behaviour on watchOS
+
+| Permission | watchOS |
+|---|---|
+| `notification` | supported, provisional included |
+| `location`, `locationWhenInUse`, `locationAlways` | supported, with the service status; "always" needs "when in use" first, as on iOS |
+| `sensors` | supported (Motion & Fitness), with the service status |
+| `microphone` | supported |
+| `contacts` | supported; watchOS has no limited access |
+| `calendarFullAccess`, `calendarWriteOnly`, `reminders` | supported, with the full-access and write-only prompts |
+| `bluetooth` | supported, with the service status |
+| `criticalAlerts` | supported; needs the Critical Alerts entitlement (`com.apple.developer.usernotifications.critical-alerts`), which Apple grants on request |
+| `assistant` | Siri, supported for an app that opts in: watchOS ends an app without the Siri capability (`com.apple.developer.siri`) that asks about Siri, so the iOS implementation's build macro is an Info.plist key here, `PermissionHandlerWatchosSiri` set to `YES`, which only an app with the capability sets, with `NSSiriUsageDescription`. Without it the status is `denied`, a request too, and Siri is never asked |
+| `storage` | granted, as on iOS: the app's own container needs no permission |
+
+`shouldShowRequestPermissionRationale` is false, as on iOS. The statuses and
+the error codes are the iOS implementation's.
+
+## Not supported on watchOS
+
+| Member | On watchOS | Why |
+|---|---|---|
+| `camera`, `photos`, `photosAddOnly`, `mediaLibrary`, `speech`, `appTrackingTransparency`, `backgroundRefresh`, `phone` | `denied`; a request `permanentlyDenied`; service `disabled` | watchOS has none of these; iOS answers the same for a permission it does not know |
+| `openAppSettings` | returns false | watchOS has no settings page an app can open; the wearer changes a permission in the watch's Settings or in the Watch app on the iPhone |
+
+## Example deviations
+
+The example is `permission_handler_apple`'s own example app, unchanged
+except for this watchOS deviation (and the formatting this repository's CI
+checks):
+
+| Where | Change | Why |
+|---|---|---|
+| `example/pubspec.yaml` | adds `url_launcher_watchos` | the example's `baseflow_plugin_template` opens its links with `url_launcher`, which has no watchOS implementation without it |
+
+`example/integration_test/permission_handler_test.dart` is this package's
+own: upstream has no integration test.
+
+## License
+
+MIT, as upstream `permission_handler` is. See `LICENSE` for the full text.
diff --git a/packages/permission_handler_watchos/analysis_options.yaml b/packages/permission_handler_watchos/analysis_options.yaml
new file mode 100644
index 0000000..d0114d8
--- /dev/null
+++ b/packages/permission_handler_watchos/analysis_options.yaml
@@ -0,0 +1,9 @@
+include: package:flutter_lints/flutter.yaml
+
+analyzer:
+ exclude:
+ - build/**
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
diff --git a/packages/permission_handler_watchos/example/.gitignore b/packages/permission_handler_watchos/example/.gitignore
new file mode 100644
index 0000000..3b47c00
--- /dev/null
+++ b/packages/permission_handler_watchos/example/.gitignore
@@ -0,0 +1,14 @@
+.dart_tool/
+.packages
+build/
+.flutter-plugins
+.flutter-plugins-dependencies
+*.iml
+.idea/
+.DS_Store
+
+# watchOS / CocoaPods
+watchos/Pods/
+watchos/Podfile.lock
+watchos/.symlinks/
+watchos/Flutter/Flutter.framework
diff --git a/packages/permission_handler_watchos/example/README.md b/packages/permission_handler_watchos/example/README.md
new file mode 100644
index 0000000..ac2fe02
--- /dev/null
+++ b/packages/permission_handler_watchos/example/README.md
@@ -0,0 +1,9 @@
+# permission_handler_example
+
+A watch demo of `permission_handler_watchos`: every permission watchOS has,
+with its status. Tapping one asks for it.
+
+```sh
+flutter-watchos run -d
+flutter-watchos test integration_test/permission_handler_test.dart -d
+```
diff --git a/packages/permission_handler_watchos/example/analysis_options.yaml b/packages/permission_handler_watchos/example/analysis_options.yaml
new file mode 100644
index 0000000..801d885
--- /dev/null
+++ b/packages/permission_handler_watchos/example/analysis_options.yaml
@@ -0,0 +1,4 @@
+analyzer:
+ exclude:
+ - build/**
+include: package:flutter_lints/flutter.yaml
diff --git a/packages/permission_handler_watchos/example/integration_test/permission_handler_test.dart b/packages/permission_handler_watchos/example/integration_test/permission_handler_test.dart
new file mode 100644
index 0000000..4e7cd4d
--- /dev/null
+++ b/packages/permission_handler_watchos/example/integration_test/permission_handler_test.dart
@@ -0,0 +1,63 @@
+// Copyright 2026 The FlutterWatch Authors. All rights reserved.
+// Use of this source code is governed by the MIT license that can be found
+// in the LICENSE file.
+//
+// Against the real watch, through permission_handler's own API: every
+// symbol resolves, every permission answers, and the answers that need no
+// prompt are the ones the iOS implementation gives. Run it on a Simulator
+// with the app installed afresh (flutter-watchos test does that):
+// flutter-watchos test integration_test/permission_handler_test.dart \
+// -d
+
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:permission_handler/permission_handler.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ testWidgets('every permission answers with a status', (WidgetTester _) async {
+ for (final Permission permission in Permission.values) {
+ expect(await permission.status, isA(),
+ reason: '$permission');
+ }
+ });
+
+ testWidgets('a permission watchOS lacks answers as on iOS',
+ (WidgetTester _) async {
+ expect(await Permission.camera.status, PermissionStatus.denied);
+ expect(
+ await Permission.camera.request(), PermissionStatus.permanentlyDenied);
+ expect(await Permission.phone.serviceStatus, ServiceStatus.disabled);
+ });
+
+ testWidgets('storage, critical alerts and Siri answer as on iOS',
+ (WidgetTester _) async {
+ expect(await Permission.storage.status, PermissionStatus.granted);
+ expect(await Permission.storage.request(), PermissionStatus.granted);
+ // The example has neither the Critical Alerts entitlement nor Siri, so
+ // neither has been asked for. Its Info.plist has no
+ // NSSiriUsageDescription, so Siri is not even asked about: INPreferences
+ // ends an app without the Siri entitlement.
+ expect(await Permission.criticalAlerts.status, PermissionStatus.denied);
+ expect(await Permission.assistant.status, PermissionStatus.denied);
+ });
+
+ testWidgets('location services answer', (WidgetTester _) async {
+ expect(await Permission.location.serviceStatus, isA());
+ });
+
+ testWidgets('"always" before "when in use" fails as on iOS',
+ (WidgetTester _) async {
+ // Only meaningful on a fresh install, where location is not determined.
+ if (await Permission.locationWhenInUse.status != PermissionStatus.denied) {
+ return;
+ }
+ await expectLater(
+ Permission.locationAlways.request(),
+ throwsA(isA().having((PlatformException e) => e.code,
+ 'code', 'MISSING_WHENINUSE_PERMISSION')),
+ );
+ });
+}
diff --git a/packages/permission_handler_watchos/example/lib/main.dart b/packages/permission_handler_watchos/example/lib/main.dart
new file mode 100644
index 0000000..cbcf835
--- /dev/null
+++ b/packages/permission_handler_watchos/example/lib/main.dart
@@ -0,0 +1,164 @@
+import 'package:baseflow_plugin_template/baseflow_plugin_template.dart';
+import 'package:flutter/material.dart';
+import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';
+
+void main() {
+ runApp(
+ BaseflowPluginExample(
+ pluginName: 'Permission Handler',
+ githubURL: 'https://github.com/Baseflow/flutter-permission-handler',
+ pubDevURL: 'https://pub.dev/packages/permission_handler',
+ pages: [PermissionHandlerWidget.createPage()],
+ ),
+ );
+}
+
+///Defines the main theme color
+final MaterialColor themeMaterialColor =
+ BaseflowPluginExample.createMaterialColor(
+ const Color.fromRGBO(48, 49, 60, 1),
+);
+
+/// A Flutter application demonstrating the functionality of this plugin
+class PermissionHandlerWidget extends StatefulWidget {
+ const PermissionHandlerWidget._();
+
+ /// Create a page containing the functionality of this plugin
+ static ExamplePage createPage() {
+ return ExamplePage(
+ Icons.location_on,
+ (context) => const PermissionHandlerWidget._(),
+ );
+ }
+
+ @override
+ PermissionHandlerWidgetState createState() => PermissionHandlerWidgetState();
+}
+
+/// The state of the [PermissionHandlerWidget] that listens for permission status changes.
+class PermissionHandlerWidgetState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Center(
+ child: ListView(
+ children: Permission.values
+ .where((permission) {
+ return permission != Permission.unknown &&
+ permission != Permission.phone &&
+ permission != Permission.sms &&
+ permission != Permission.ignoreBatteryOptimizations &&
+ permission != Permission.accessMediaLocation &&
+ permission != Permission.activityRecognition &&
+ permission != Permission.manageExternalStorage &&
+ permission != Permission.systemAlertWindow &&
+ permission != Permission.requestInstallPackages &&
+ permission != Permission.accessNotificationPolicy &&
+ permission != Permission.bluetoothScan &&
+ permission != Permission.bluetoothAdvertise &&
+ permission != Permission.bluetoothConnect &&
+ permission != Permission.nearbyWifiDevices &&
+ permission != Permission.videos &&
+ permission != Permission.audio &&
+ permission != Permission.scheduleExactAlarm &&
+ permission != Permission.sensorsAlways;
+ })
+ .map((permission) => PermissionWidget(permission))
+ .toList(),
+ ),
+ );
+ }
+}
+
+/// Permission widget containing information about the passed [Permission]
+class PermissionWidget extends StatefulWidget {
+ /// Constructs a [PermissionWidget] for the supplied [Permission]
+ const PermissionWidget(this.permission, {super.key});
+
+ /// The [Permission] that this widget is rendered for.
+ final Permission permission;
+
+ @override
+ State createState() => _PermissionState();
+}
+
+class _PermissionState extends State {
+ final PermissionHandlerPlatform _permissionHandler =
+ PermissionHandlerPlatform.instance;
+ PermissionStatus _permissionStatus = PermissionStatus.denied;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _listenForPermissionStatus();
+ }
+
+ void _listenForPermissionStatus() async {
+ final status = await _permissionHandler.checkPermissionStatus(
+ widget.permission,
+ );
+ setState(() => _permissionStatus = status);
+ }
+
+ Color getPermissionColor() {
+ switch (_permissionStatus) {
+ case PermissionStatus.denied:
+ return Colors.red;
+ case PermissionStatus.granted:
+ return Colors.green;
+ case PermissionStatus.limited:
+ return Colors.orange;
+ default:
+ return Colors.grey;
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ title: Text(
+ widget.permission.toString(),
+ style: Theme.of(context).textTheme.bodyLarge,
+ ),
+ subtitle: Text(
+ _permissionStatus.toString(),
+ style: TextStyle(color: getPermissionColor()),
+ ),
+ trailing: (widget.permission is PermissionWithService)
+ ? IconButton(
+ icon: const Icon(Icons.info, color: Colors.white),
+ onPressed: () {
+ checkServiceStatus(
+ context,
+ widget.permission as PermissionWithService,
+ );
+ },
+ )
+ : null,
+ onTap: () {
+ requestPermission(widget.permission);
+ },
+ );
+ }
+
+ void checkServiceStatus(
+ BuildContext context,
+ PermissionWithService permission,
+ ) async {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text(
+ (await _permissionHandler.checkServiceStatus(permission)).toString(),
+ ),
+ ),
+ );
+ }
+
+ Future requestPermission(Permission permission) async {
+ final status = await _permissionHandler.requestPermissions([permission]);
+
+ setState(() {
+ _permissionStatus = status[permission] ?? PermissionStatus.denied;
+ });
+ }
+}
diff --git a/packages/permission_handler_watchos/example/pubspec.yaml b/packages/permission_handler_watchos/example/pubspec.yaml
new file mode 100644
index 0000000..8d5edf8
--- /dev/null
+++ b/packages/permission_handler_watchos/example/pubspec.yaml
@@ -0,0 +1,36 @@
+name: permission_handler_example
+description: "watchOS example for permission_handler_watchos."
+publish_to: 'none'
+version: 1.0.0+1
+
+environment:
+ sdk: ">=3.1.0 <4.0.0"
+
+dependencies:
+ # lib/ is permission_handler_apple's own example, which imports these two.
+ baseflow_plugin_template: ^2.2.1
+ flutter:
+ sdk: flutter
+ permission_handler: ^13.0.2
+ permission_handler_platform_interface: ^4.4.1
+ permission_handler_watchos:
+ path: ../
+ # The template's links go through url_launcher, which this package
+ # answers on the watch.
+ url_launcher_watchos:
+ path: ../../url_launcher_watchos
+
+dev_dependencies:
+ flutter_lints: ^4.0.0
+ flutter_test:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+
+flutter:
+ uses-material-design: true
+
+ # The template's logos, as upstream's example lists them.
+ assets:
+ - res/images/baseflow_logo_def_light-02.png
+ - res/images/poweredByBaseflowLogoLight@3x.png
diff --git a/packages/permission_handler_watchos/example/res/images/baseflow_logo_def_light-02.png b/packages/permission_handler_watchos/example/res/images/baseflow_logo_def_light-02.png
new file mode 100644
index 0000000..85f071f
Binary files /dev/null and b/packages/permission_handler_watchos/example/res/images/baseflow_logo_def_light-02.png differ
diff --git a/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight.png b/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight.png
new file mode 100644
index 0000000..6b9f1aa
Binary files /dev/null and b/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight.png differ
diff --git a/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight@2x.png b/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight@2x.png
new file mode 100644
index 0000000..66901d9
Binary files /dev/null and b/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight@2x.png differ
diff --git a/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight@3x.png b/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight@3x.png
new file mode 100644
index 0000000..36fbdff
Binary files /dev/null and b/packages/permission_handler_watchos/example/res/images/poweredByBaseflowLogoLight@3x.png differ
diff --git a/packages/permission_handler_watchos/example/test_driver/integration_test.dart b/packages/permission_handler_watchos/example/test_driver/integration_test.dart
new file mode 100644
index 0000000..2acb97e
--- /dev/null
+++ b/packages/permission_handler_watchos/example/test_driver/integration_test.dart
@@ -0,0 +1,4 @@
+// Generated by `flutter-watchos plugin port --include-example`.
+import 'package:integration_test/integration_test_driver.dart';
+
+Future main() => integrationDriver();
diff --git a/packages/permission_handler_watchos/example/watchos/Flutter/.gitignore b/packages/permission_handler_watchos/example/watchos/Flutter/.gitignore
new file mode 100644
index 0000000..196f947
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Flutter/.gitignore
@@ -0,0 +1,3 @@
+# Build artifacts placed here by `flutter-watchos build` — never commit.
+*
+!.gitignore
diff --git a/packages/permission_handler_watchos/example/watchos/HostApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/permission_handler_watchos/example/watchos/HostApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..13613e3
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/HostApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,13 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/packages/permission_handler_watchos/example/watchos/HostApp/Assets.xcassets/Contents.json b/packages/permission_handler_watchos/example/watchos/HostApp/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/HostApp/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/packages/permission_handler_watchos/example/watchos/HostApp/Info.plist b/packages/permission_handler_watchos/example/watchos/HostApp/Info.plist
new file mode 100644
index 0000000..9312f07
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/HostApp/Info.plist
@@ -0,0 +1,48 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Permission Handler Example
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ ITSWatchOnlyContainer
+
+ LSApplicationLaunchProhibited
+
+ LSRequiresIPhoneOS
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+
+ UILaunchScreen
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/project.pbxproj b/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..917f1d8
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,438 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ AB0000000000000000000001 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000001 /* App.swift */; };
+ AB0000000000000000000003 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000003 /* Flutter.framework */; };
+ AB0000000000000000000004 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000003 /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ AB0000000000000000000005 /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000004 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ AB0000000000000000000006 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000005 /* flutter_assets */; };
+ AB0000000000000000000007 /* icudtl.dat in Resources */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000006 /* icudtl.dat */; };
+ AB0000000000000000000008 /* vm_isolate_snapshot.bin in Resources */ = {isa = PBXBuildFile; fileRef = AF000000000000000000000A /* vm_isolate_snapshot.bin */; };
+ AB0000000000000000000009 /* isolate_snapshot.bin in Resources */ = {isa = PBXBuildFile; fileRef = AF000000000000000000000B /* isolate_snapshot.bin */; };
+ AB0000000000000000000010 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AF000000000000000000000C /* Assets.xcassets */; };
+ CB0000000000000000000002 /* Runner.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = AF0000000000000000000007 /* Runner.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ CB0000000000000000000003 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CF0000000000000000000004 /* Assets.xcassets */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ CA0000000000000000000004 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = AA0000000000000000000002 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = AA0000000000000000000001;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ AC0000000000000000000001 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ AB0000000000000000000004 /* Flutter.framework in Embed Frameworks */,
+ AB0000000000000000000005 /* App.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CD0000000000000000000011 /* Embed Watch Content */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
+ dstSubfolderSpec = 16;
+ files = (
+ CB0000000000000000000002 /* Runner.app in Embed Watch Content */,
+ );
+ name = "Embed Watch Content";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 0B66C03D2FE326E4002C6E54 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AF0000000000000000000001 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; };
+ AF0000000000000000000003 /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Flutter.framework; sourceTree = ""; };
+ AF0000000000000000000004 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = App.framework; sourceTree = ""; };
+ AF0000000000000000000005 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = flutter_assets; sourceTree = ""; };
+ AF0000000000000000000006 /* icudtl.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = icudtl.dat; sourceTree = ""; };
+ AF0000000000000000000007 /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ AF000000000000000000000A /* vm_isolate_snapshot.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = vm_isolate_snapshot.bin; sourceTree = ""; };
+ AF000000000000000000000B /* isolate_snapshot.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = isolate_snapshot.bin; sourceTree = ""; };
+ AF000000000000000000000C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ AF000000000000000000000D /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; };
+ AF000000000000000000000E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; };
+ CF0000000000000000000001 /* permission_handler_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = permission_handler_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ CF0000000000000000000003 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ CF0000000000000000000004 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ AD0000000000000000000001 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AB0000000000000000000003 /* Flutter.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ AE0000000000000000000001 = {
+ isa = PBXGroup;
+ children = (
+ AE0000000000000000000002 /* Runner */,
+ CE0000000000000000000001 /* HostApp */,
+ AE0000000000000000000004 /* Flutter */,
+ AE0000000000000000000003 /* Products */,
+ );
+ sourceTree = "";
+ };
+ AE0000000000000000000002 /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ AF0000000000000000000001 /* App.swift */,
+ AF000000000000000000000C /* Assets.xcassets */,
+ 0B66C03D2FE326E4002C6E54 /* Info.plist */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+ AE0000000000000000000003 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ AF0000000000000000000007 /* Runner.app */,
+ CF0000000000000000000001 /* permission_handler_example.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ AE0000000000000000000004 /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ AF0000000000000000000003 /* Flutter.framework */,
+ AF0000000000000000000004 /* App.framework */,
+ AF0000000000000000000005 /* flutter_assets */,
+ AF0000000000000000000006 /* icudtl.dat */,
+ AF000000000000000000000A /* vm_isolate_snapshot.bin */,
+ AF000000000000000000000B /* isolate_snapshot.bin */,
+ AF000000000000000000000D /* Debug.xcconfig */,
+ AF000000000000000000000E /* Release.xcconfig */,
+ );
+ path = Flutter;
+ sourceTree = "";
+ };
+ CE0000000000000000000001 /* HostApp */ = {
+ isa = PBXGroup;
+ children = (
+ CF0000000000000000000004 /* Assets.xcassets */,
+ CF0000000000000000000003 /* Info.plist */,
+ );
+ path = HostApp;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ AA0000000000000000000001 /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA0000000000000000000002 /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ AD0000000000000000000002 /* Sources */,
+ AD0000000000000000000001 /* Frameworks */,
+ AD0000000000000000000003 /* Resources */,
+ AC0000000000000000000001 /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = AF0000000000000000000007 /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+ CA0000000000000000000001 /* HostApp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = CA0000000000000000000003 /* Build configuration list for PBXNativeTarget "HostApp" */;
+ buildPhases = (
+ CD0000000000000000000012 /* Resources */,
+ CD0000000000000000000011 /* Embed Watch Content */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ CA0000000000000000000002 /* PBXTargetDependency */,
+ );
+ name = HostApp;
+ productName = permission_handler_example;
+ productReference = CF0000000000000000000001 /* permission_handler_example.app */;
+ productType = "com.apple.product-type.application.watchapp2-container";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ AA0000000000000000000002 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastUpgradeCheck = 2700;
+ TargetAttributes = {
+ AA0000000000000000000001 = {
+ CreatedOnToolsVersion = 15.0;
+ };
+ CA0000000000000000000001 = {
+ CreatedOnToolsVersion = 15.0;
+ };
+ };
+ };
+ buildConfigurationList = BA0000000000000000000001 /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = AE0000000000000000000001;
+ productRefGroup = AE0000000000000000000003 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ AA0000000000000000000001 /* Runner */,
+ CA0000000000000000000001 /* HostApp */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ AD0000000000000000000003 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AB0000000000000000000006 /* flutter_assets in Resources */,
+ AB0000000000000000000007 /* icudtl.dat in Resources */,
+ AB0000000000000000000008 /* vm_isolate_snapshot.bin in Resources */,
+ AB0000000000000000000009 /* isolate_snapshot.bin in Resources */,
+ AB0000000000000000000010 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CD0000000000000000000012 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CB0000000000000000000003 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ AD0000000000000000000002 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AB0000000000000000000001 /* App.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ CA0000000000000000000002 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = AA0000000000000000000001 /* Runner */;
+ targetProxy = CA0000000000000000000004 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ BB0000000000000000000001 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ENABLE_MODULES = YES;
+ ENABLE_BITCODE = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ BB0000000000000000000002 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AF000000000000000000000D /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
+ GENERATE_INFOPLIST_FILE = NO;
+ HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
+ INFOPLIST_FILE = Runner/Info.plist;
+ INSTALL_PATH = "$(LOCAL_APPS_DIR)";
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
+ MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.example.permissionHandlerExample.watchkitapp";
+ PRODUCT_NAME = Runner;
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ WATCHOS_DEPLOYMENT_TARGET = 26.0;
+ };
+ name = Debug;
+ };
+ BB0000000000000000000003 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ENABLE_MODULES = YES;
+ ENABLE_BITCODE = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = s;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ };
+ name = Release;
+ };
+ BB0000000000000000000004 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AF000000000000000000000E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
+ GENERATE_INFOPLIST_FILE = NO;
+ HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
+ INFOPLIST_FILE = Runner/Info.plist;
+ INSTALL_PATH = "$(LOCAL_APPS_DIR)";
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
+ MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.example.permissionHandlerExample.watchkitapp";
+ PRODUCT_NAME = Runner;
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ WATCHOS_DEPLOYMENT_TARGET = 26.0;
+ };
+ name = Release;
+ };
+ CC0000000000000000000001 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AF000000000000000000000D /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ ENABLE_BITCODE = NO;
+ GENERATE_INFOPLIST_FILE = NO;
+ INFOPLIST_FILE = HostApp/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 26.0;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.example.permissionHandlerExample";
+ PRODUCT_NAME = permission_handler_example;
+ SDKROOT = iphoneos;
+ SKIP_INSTALL = NO;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ CC0000000000000000000002 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AF000000000000000000000E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = "";
+ ENABLE_BITCODE = NO;
+ GENERATE_INFOPLIST_FILE = NO;
+ INFOPLIST_FILE = HostApp/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 26.0;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.example.permissionHandlerExample";
+ PRODUCT_NAME = permission_handler_example;
+ SDKROOT = iphoneos;
+ SKIP_INSTALL = NO;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ BA0000000000000000000001 /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BB0000000000000000000001 /* Debug */,
+ BB0000000000000000000003 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA0000000000000000000002 /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BB0000000000000000000002 /* Debug */,
+ BB0000000000000000000004 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ CA0000000000000000000003 /* Build configuration list for PBXNativeTarget "HostApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CC0000000000000000000001 /* Debug */,
+ CC0000000000000000000002 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = AA0000000000000000000002 /* Project object */;
+}
diff --git a/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..1bc84b8
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/xcshareddata/xcschemes/permission_handler_example.xcscheme b/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/xcshareddata/xcschemes/permission_handler_example.xcscheme
new file mode 100644
index 0000000..222dae3
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Runner.xcodeproj/xcshareddata/xcschemes/permission_handler_example.xcscheme
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/App.swift b/packages/permission_handler_watchos/example/watchos/Runner/App.swift
new file mode 100644
index 0000000..f2b52dd
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Runner/App.swift
@@ -0,0 +1,57 @@
+import SwiftUI
+
+#if !arch(arm64_32)
+// The Flutter host (frame display, input, native overlays) — compiled by
+// flutter-watchos into watchos/Flutter/, like Flutter.framework itself.
+import FlutterWatchOS
+#endif
+
+@main
+struct PermissionHandlerExampleApp: App {
+ #if !arch(arm64_32)
+ // Remote-notification plumbing (APNs device token, notification payloads)
+ // for plugins that need it, e.g. firebase_messaging. Safe to keep even if
+ // no plugin uses notifications.
+ @WKApplicationDelegateAdaptor(FlutterWatchOSAppDelegate.self)
+ private var flutterAppDelegate
+
+ init() {
+ // Native platform views: register a SwiftUI factory for every
+ // `viewType` your Dart code embeds with WatchPlatformView
+ // (package:flutter_watchos). Example:
+ //
+ // WatchPlatformViewRegistry.register("my-gauge") { params in
+ // AnyView(MyGaugeView(params: params))
+ // }
+ }
+ #endif
+
+ var body: some Scene {
+ WindowGroup {
+ #if arch(arm64_32)
+ // 32-bit watches (Series 4–8 / SE) are not supported.
+ UnsupportedDeviceView()
+ #else
+ // Holds a black launch placeholder over the screen until Flutter's
+ // first frame is ready, then fades it out. Supply your own to
+ // replace it: `FlutterHostView { MyLaunchScreen() }`.
+ FlutterHostView()
+ #endif
+ }
+ }
+}
+
+// Shown on 32-bit watches (Series 4–8 / SE), which this app does not support.
+struct UnsupportedDeviceView: View {
+ var body: some View {
+ VStack(spacing: 8) {
+ Text("Permission Handler Example")
+ .font(.headline)
+ Text("Requires Apple Watch Series 9 or later.")
+ .font(.footnote)
+ .multilineTextAlignment(.center)
+ .foregroundStyle(.secondary)
+ }
+ .padding()
+ }
+}
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..287d73c
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,140 @@
+{
+ "images" : [
+ {
+ "filename" : "icon_24x24_2x_38mm.png",
+ "idiom" : "watch",
+ "role" : "notificationCenter",
+ "scale" : "2x",
+ "size" : "24x24",
+ "subtype" : "38mm"
+ },
+ {
+ "filename" : "icon_27.5x27.5_2x_42mm.png",
+ "idiom" : "watch",
+ "role" : "notificationCenter",
+ "scale" : "2x",
+ "size" : "27.5x27.5",
+ "subtype" : "42mm"
+ },
+ {
+ "filename" : "icon_29x29_2x_companion.png",
+ "idiom" : "watch",
+ "role" : "companionSettings",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "icon_29x29_3x_companion.png",
+ "idiom" : "watch",
+ "role" : "companionSettings",
+ "scale" : "3x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "icon_33x33_2x_45mm.png",
+ "idiom" : "watch",
+ "role" : "notificationCenter",
+ "scale" : "2x",
+ "size" : "33x33",
+ "subtype" : "45mm"
+ },
+ {
+ "filename" : "icon_40x40_2x_38mm.png",
+ "idiom" : "watch",
+ "role" : "appLauncher",
+ "scale" : "2x",
+ "size" : "40x40",
+ "subtype" : "38mm"
+ },
+ {
+ "filename" : "icon_44x44_2x_40mm.png",
+ "idiom" : "watch",
+ "role" : "appLauncher",
+ "scale" : "2x",
+ "size" : "44x44",
+ "subtype" : "40mm"
+ },
+ {
+ "filename" : "icon_46x46_2x_41mm.png",
+ "idiom" : "watch",
+ "role" : "appLauncher",
+ "scale" : "2x",
+ "size" : "46x46",
+ "subtype" : "41mm"
+ },
+ {
+ "filename" : "icon_50x50_2x_44mm.png",
+ "idiom" : "watch",
+ "role" : "appLauncher",
+ "scale" : "2x",
+ "size" : "50x50",
+ "subtype" : "44mm"
+ },
+ {
+ "filename" : "icon_51x51_2x_45mm.png",
+ "idiom" : "watch",
+ "role" : "appLauncher",
+ "scale" : "2x",
+ "size" : "51x51",
+ "subtype" : "45mm"
+ },
+ {
+ "filename" : "icon_54x54_2x_49mm.png",
+ "idiom" : "watch",
+ "role" : "appLauncher",
+ "scale" : "2x",
+ "size" : "54x54",
+ "subtype" : "49mm"
+ },
+ {
+ "filename" : "icon_86x86_2x.png",
+ "idiom" : "watch",
+ "role" : "quickLook",
+ "scale" : "2x",
+ "size" : "86x86",
+ "subtype" : "38mm"
+ },
+ {
+ "filename" : "icon_98x98_2x.png",
+ "idiom" : "watch",
+ "role" : "quickLook",
+ "scale" : "2x",
+ "size" : "98x98",
+ "subtype" : "42mm"
+ },
+ {
+ "filename" : "icon_108x108_2x_44mm.png",
+ "idiom" : "watch",
+ "role" : "quickLook",
+ "scale" : "2x",
+ "size" : "108x108",
+ "subtype" : "44mm"
+ },
+ {
+ "filename" : "icon_117x117_2x_45mm.png",
+ "idiom" : "watch",
+ "role" : "quickLook",
+ "scale" : "2x",
+ "size" : "117x117",
+ "subtype" : "45mm"
+ },
+ {
+ "filename" : "icon_129x129_2x_49mm.png",
+ "idiom" : "watch",
+ "role" : "quickLook",
+ "scale" : "2x",
+ "size" : "129x129",
+ "subtype" : "49mm"
+ },
+ {
+ "filename" : "icon_1024.png",
+ "idiom" : "watch-marketing",
+ "scale" : "1x",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_1024.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_1024.png
new file mode 100644
index 0000000..819d623
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_1024.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_108x108_2x_44mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_108x108_2x_44mm.png
new file mode 100644
index 0000000..7b3140c
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_108x108_2x_44mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_117x117_2x_45mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_117x117_2x_45mm.png
new file mode 100644
index 0000000..66f8d8c
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_117x117_2x_45mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_129x129_2x_49mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_129x129_2x_49mm.png
new file mode 100644
index 0000000..0382bad
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_129x129_2x_49mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_24x24_2x_38mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_24x24_2x_38mm.png
new file mode 100644
index 0000000..14682e5
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_24x24_2x_38mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_27.5x27.5_2x_42mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_27.5x27.5_2x_42mm.png
new file mode 100644
index 0000000..e29fe11
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_27.5x27.5_2x_42mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_29x29_2x_companion.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_29x29_2x_companion.png
new file mode 100644
index 0000000..796aa3f
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_29x29_2x_companion.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_29x29_3x_companion.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_29x29_3x_companion.png
new file mode 100644
index 0000000..afbe411
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_29x29_3x_companion.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_33x33_2x_45mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_33x33_2x_45mm.png
new file mode 100644
index 0000000..c24aca9
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_33x33_2x_45mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_40x40_2x_38mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_40x40_2x_38mm.png
new file mode 100644
index 0000000..011934e
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_40x40_2x_38mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_44x44_2x_40mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_44x44_2x_40mm.png
new file mode 100644
index 0000000..ec54e61
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_44x44_2x_40mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_46x46_2x_41mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_46x46_2x_41mm.png
new file mode 100644
index 0000000..d574b52
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_46x46_2x_41mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_50x50_2x_44mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_50x50_2x_44mm.png
new file mode 100644
index 0000000..fafa3ef
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_50x50_2x_44mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_51x51_2x_45mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_51x51_2x_45mm.png
new file mode 100644
index 0000000..883c37b
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_51x51_2x_45mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_54x54_2x_49mm.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_54x54_2x_49mm.png
new file mode 100644
index 0000000..457d76a
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_54x54_2x_49mm.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_86x86_2x.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_86x86_2x.png
new file mode 100644
index 0000000..28feaed
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_86x86_2x.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_98x98_2x.png b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_98x98_2x.png
new file mode 100644
index 0000000..3b901e5
Binary files /dev/null and b/packages/permission_handler_watchos/example/watchos/Runner/Assets.xcassets/AppIcon.appiconset/icon_98x98_2x.png differ
diff --git a/packages/permission_handler_watchos/example/watchos/Runner/Info.plist b/packages/permission_handler_watchos/example/watchos/Runner/Info.plist
new file mode 100644
index 0000000..e4c2592
--- /dev/null
+++ b/packages/permission_handler_watchos/example/watchos/Runner/Info.plist
@@ -0,0 +1,46 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Permission Handler Example
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ permission_handler_example
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ WKApplication
+
+ NSLocationWhenInUseUsageDescription
+ The example shows the location permission's status and asks for it.
+ NSLocationAlwaysAndWhenInUseUsageDescription
+ The example shows the always-location permission's status and asks for it.
+ NSMotionUsageDescription
+ The example shows the Motion & Fitness permission's status and asks for it.
+ NSMicrophoneUsageDescription
+ The example shows the microphone permission's status and asks for it.
+ NSContactsUsageDescription
+ The example shows the contacts permission's status and asks for it.
+ NSCalendarsFullAccessUsageDescription
+ The example shows the calendar permission's status and asks for it.
+ NSCalendarsWriteOnlyAccessUsageDescription
+ The example shows the write-only calendar permission's status and asks for it.
+ NSRemindersFullAccessUsageDescription
+ The example shows the reminders permission's status and asks for it.
+ NSBluetoothAlwaysUsageDescription
+ The example shows the Bluetooth permission's status and asks for it.
+ WKWatchOnly
+
+
+
diff --git a/packages/permission_handler_watchos/lib/permission_handler_watchos.dart b/packages/permission_handler_watchos/lib/permission_handler_watchos.dart
new file mode 100644
index 0000000..0cb907c
--- /dev/null
+++ b/packages/permission_handler_watchos/lib/permission_handler_watchos.dart
@@ -0,0 +1,177 @@
+// Copyright 2026 The FlutterWatch Authors. All rights reserved.
+// Use of this source code is governed by the MIT license that can be found
+// in the LICENSE file.
+//
+// watchOS implementation of `permission_handler`, over dart:ffi.
+//
+// Method-channel plugins are not supported on watchOS, so the answers come
+// from `watchos/Classes/` over dart:ffi: each call returns a request id,
+// native wakes Dart through one `NativeCallable.listener` when an answer is
+// ready, and Dart takes it as JSON. The permissions, statuses and error
+// codes are the iOS implementation's.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:flutter/services.dart';
+import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';
+
+import 'src/backend.dart';
+import 'src/ffi_backend.dart';
+
+export 'src/backend.dart' show PermissionHandlerWatchosBackend;
+
+/// What woke Dart up. Mirrored in
+/// `watchos/Classes/permission_handler_watchos_ffi.h`.
+abstract final class PermissionHandlerWatchosSignal {
+ /// An answer is ready.
+ static const int result = 1;
+}
+
+/// watchOS implementation of [PermissionHandlerPlatform].
+///
+/// Answers for location (when in use and always), notifications, critical
+/// alerts, sensors (Motion & Fitness), the microphone, contacts, the calendar
+/// (full access and write only), reminders, Bluetooth, Siri
+/// ([Permission.assistant]) and storage, which is granted as on iOS. The
+/// permissions watchOS does not have answer as the iOS implementation
+/// answers for one it does not know: [PermissionStatus.denied], a request
+/// [PermissionStatus.permanentlyDenied], their service
+/// [ServiceStatus.disabled].
+class PermissionHandlerWatchos extends PermissionHandlerPlatform {
+ /// Test hook: set before first use to replace the native backend.
+ static PermissionHandlerWatchosBackend? backendOverride;
+
+ static PermissionHandlerWatchosBackend? _backend;
+
+ PermissionHandlerWatchosBackend get _b =>
+ backendOverride ?? (_backend ??= FfiPermissionHandlerWatchosBackend());
+
+ /// Registers this class as the `permission_handler` implementation on
+ /// watchOS.
+ static void registerWith() {
+ PermissionHandlerPlatform.instance = PermissionHandlerWatchos();
+ }
+
+ final Map>> _pending =
+ >>{};
+ bool _registered = false;
+ bool _requesting = false;
+
+ @override
+ Future checkPermissionStatus(Permission permission) async =>
+ PermissionStatusValue.statusByValue(
+ _number(await _await(_b.check(permission.value)), 'status'),
+ );
+
+ /// Whether the service behind [permission] is on: location services for
+ /// the location permissions, motion activity for [Permission.sensors],
+ /// Bluetooth for [Permission.bluetooth]; [ServiceStatus.notApplicable] for
+ /// the others watchOS has.
+ @override
+ Future checkServiceStatus(Permission permission) async =>
+ ServiceStatusValue.statusByValue(
+ _number(await _await(_b.service(permission.value)), 'service'),
+ );
+
+ /// Asks for each of [permissions] in turn, as the watch shows one prompt
+ /// at a time, and answers with each one's status afterwards.
+ ///
+ /// Fails with a [PlatformException] whose code is
+ /// `MISSING_USAGE_DESCRIPTION` when the app's Info.plist lacks the key a
+ /// prompt needs, where watchOS would terminate the app,
+ /// `MISSING_WHENINUSE_PERMISSION` for [Permission.locationAlways] asked
+ /// for before "when in use" was granted, and, as on iOS,
+ /// `ERROR_ALREADY_REQUESTING_PERMISSIONS` while an earlier request is
+ /// still waiting for its answers.
+ @override
+ Future