# permission_handler_apple 9.6.4

Permission plugin for Flutter. This plugin provides the iOS API to request and check permissions.




## Installing
```
export PUB_HOSTED_URL=https://pub.mirror.p-hatan.com
flutter pub add permission_handler_apple
```
Published: 2026-10-23T07:28:29.757117Z
Expected archive SHA-256: b69e6b8300f9584af5ab81b41cdaa544e1b45e6fca0a30b0f9a9a120d90fc8a5

Available in cache; verification: upstream_checksum
## Direct dependencies
- flutter: map[sdk:flutter]
- permission_handler_platform_interface: ^4.4.0
- yaml: ^3.1.0

## Package README (untrusted upstream documentation)
# permission_handler_apple

[![pub package](https://img.shields.io/pub/v/permission_handler_apple.svg)](https://pub.dartlang.org/packages/permission_handler_apple) ![Build status](https://github.com/Baseflow/flutter-permission-handler/workflows/permission_handler_apple/badge.svg?branch=master) [![style: flutter lints](https://img.shields.io/badge/style-flutter_lints-40c4ff.svg)](https://pub.dev/packages/flutter_lints)

The official iOS implementation of the [permission_handler](https://pub.dev/packages/permission_handler) plugin by [Baseflow](https://baseflow.com).

## Usage

Since version 9.1.0 of the [permission_handler](https://pub.dev/packages/permission_handler) plugin this is the endorsed iOS implementation. This means it will automatically be added to your dependencies when you depend on `permission_handler: ^9.1.0` in your applications pubspec.yaml.

More detailed instructions on using the API can be found in the [README.md](../permission_handler/README.md) of the [permission_handler](https://pub.dev/packages/permission_handler) package.

## Swift Package Manager

Only the permissions your app actually uses are compiled into the binary. Referencing an iOS
permission API you have no usage description for is grounds for App Store rejection
(`ITMS-90683`), so each permission is guarded by a `PERMISSION_*` macro.

Under CocoaPods you set those macros yourself, in the `GCC_PREPROCESSOR_DEFINITIONS` block of your
`Podfile`. Under Swift Package Manager the package manifest derives them instead: it locates your
app's `Info.plist` files and enables a permission when the matching `NS*UsageDescription` key is
present. `INFOPLIST_FILE` is read from your Xcode project and `.xcconfig` files, so
build-configuration and flavor specific plists (`Info-Debug.plist`, `Info-dev.plist`,
`Runner/Info-$(CONFIGURATION).plist`, …) are all picked up.

**Keys are merged across every configuration.** A package manifest is evaluated once and cannot
vary its settings per build configuration, so a permission declared only in `Info-dev.plist` is
compiled into your release binary too. Declare flavors (below) when that matters.

**Changes are cached.** The manifest is not re-evaluated when an `Info.plist` or an environment
variable changes. Clear DerivedData once afterwards:

```bash
rm -rf ~/Library/Developer/Xcode/DerivedData
```

### Per-flavor permissions

> Swift Package Manager only. Under CocoaPods the macros come from your `Podfile`, where you can
> already set them per configuration; `permission_handler.yaml` is ignored and the build phase
> below is a no-op.

If your flavors need different permissions — a `dev` build that scans QR codes, a `prod` build that
does not — merging is wrong: it compiles the camera code into `prod` too, which is what
`ITMS-90683` rejects. Declare a `permission_handler.yaml` next to your `pubspec.yaml`:

```yaml
strict: true
flavors:
  dev:
    info-plist: ios/Runner/Info-dev.plist
    configurations:
      - Debug-dev
      - Profile-dev
      - Release-dev
  prod:
    info-plist: ios/Runner/Info-prod.plist
    configurations:
      - Debug-prod
      - Profile-prod
      - Release-prod
```

Each flavor names the one `Info.plist` that defines it, and nothing is merged: a flavor can never
inherit another flavor's permissions. `configurations` lists the Xcode build configurations that
belong to the flavor, which is how the build phase below knows what to expect.

`select` validates the file before doing anything else, since it is the only thing that reads the
YAML — a mistake it doesn't catch here has to fail silently later instead:

- Each build configuration must belong to exactly one flavor. Two flavors listing the same one
  leaves the build phase unable to tell which permissions it should ship.
- `configurations` must be a list, even for a single value — `configurations: Debug` (without the
  `-`) is rejected rather than silently treated as "no configurations", which would otherwise
  disable the build phase's verification for that flavor without any warning.
- Flavor names must be strings. A bare `123:` is read as a YAML integer key and rejected — quote
  it (`"123":`) if you actually want that literal name.
- `strict`, if present, must be `true` or `false`.

Select a flavor before building:

```bash
dart run permission_handler_apple:select prod
```

```
Usage: dart run permission_handler_apple:select <flavor>

  --list                  Show the flavors declared in permission_handler.yaml.
  --app=<path>            App directory (defaults to the current directory).
  --derived-data=<path>   Custom DerivedData location, matching xcodebuild's
                          -derivedDataPath.
```

`--app` and `--derived-data` matter mainly in CI, where the command may not run from inside the app
directory and DerivedData may live somewhere other than `~/Library/Developer/Xcode/DerivedData`.

```bash
flutter run --flavor prod
```

Selecting is a separate step because the package manifest is evaluated once, is cached, and is
given none of Xcode's build settings — it cannot tell which configuration is running, and Xcode
will not re-evaluate it just because an environment variable changed. `select` records the choice
*and* clears the caches that would otherwise keep serving the previous flavor's permissions.

`select` is also the only YAML reader in the pipeline. A Swift package manifest cannot parse YAML —
Foundation has no support for it and a manifest cannot import libraries — so `select` translates
your config into a generated `ios/Flutter/permission_handler.resolved.json` that the manifest and
the build phase read with their native JSON parsers. Never edit that file; if you change
`permission_handler.yaml`, re-run `select`. Building with a translation older than the YAML fails
rather than using stale permissions. The file is plain JSON, so it also doubles as a quick way to
see exactly what `select` resolved, without waiting for a build.

With `strict: true` (the default) a build whose flavor cannot be determined compiles no permissions
at all, rather than falling back to the union of every flavor. Set `strict: false` to opt into that
fallback instead: the manifest merges every `Info.plist` it can discover, with a warning, the same
as an app with no `permission_handler.yaml` at all. Treat it as a landing pad while adopting
flavors gradually, not a long-term setting — it is the exact leak per-flavor configuration exists
to close.

#### Fail the build on a stale selection

Nothing inside the manifest can detect a stale selection, because a cached manifest is not
executed. Add a **Run Script** build phase to your Runner target, and drag it to the *top* of the
phase list so a mismatch fails before anything is compiled:

```sh
# Resolve the plugin, wherever this project gets it from.
PLUGIN="$SRCROOT/Flutter/ephemeral/Packages/.packages/permission_handler_apple/../.."
[ -d "$PLUGIN/tool" ] || PLUGIN="$SRCROOT/.symlinks/plugins/permission_handler_apple"
[ -f "$PLUGIN/tool/verify_flavor_selection.sh" ] || exit 0
/bin/sh "$PLUGIN/tool/verify_flavor_selection.sh"
```

It runs on every build, where `CONFIGURATION` is available, and fails with an actionable message
when the selected flavor does not match what is being built:

```
error: [permission_handler_apple] building "Release-prod" needs the "prod" permission flavor,
but "dev" is selected, so this build would ship dev's permissions.
Run: dart run permission_handler_apple:select prod
```

Add these to your `.gitignore` — one records a local choice, the other is generated:

```
ios/Flutter/permission_handler.selected
ios/Flutter/permission_handler.resolved.json
```

### Environment variables

Xcode.app does not inherit your shell's environment, so set these with `launchctl setenv` rather
than exporting them, then restart Xcode.

| Variable | Effect |
| --- | --- |
| `PERMISSION_<NAME>` | Forces a single permission on (`1`) or off (`0`), overriding everything else. For example `launchctl setenv PERMISSION_CAMERA 0`. |
| `PERMISSION_HANDLER_INFO_PLIST` | A `:`-separated list of `Info.plist` paths. When set, replaces automatic discovery entirely. |
| `PERMISSION_HANDLER_FLAVOR` | The active flavor, overriding the one recorded by `select`. Changing it still needs the caches cleared. |
| `PERMISSION_HANDLER_CONFIG` | Path to `permission_handler.yaml`, for builds that cannot locate the app automatically. |
| `PERMISSION_HANDLER_VERBOSE` | Set to `1` to log the `Info.plist` files used, the app root or active flavor, and the resolved macros. |

### Builds started from Xcode.app

Automatic discovery finds your app through the build's working directory, which points at the
Flutter project for `flutter run`, `flutter build ios` and a direct `xcodebuild` invocation. Builds
started from Xcode.app run with `/` as their working directory, and the manifest is given none of
Xcode's build settings, so there is nothing to find the app by. Point it at the plist explicitly:

```bash
launchctl setenv PERMISSION_HANDLER_INFO_PLIST /absolute/path/to/ios/Runner/Info.plist
rm -rf ~/Library/Developer/Xcode/DerivedData
```

If no `Info.plist` is found, every permission is compiled out and permission checks report
`denied`. The manifest warns about this, but Xcode discards Swift package manifest output, so the
warning only reaches you through the command line:

```bash
cd your_app
PERMISSION_HANDLER_VERBOSE=1 swift package --manifest-cache none \
  --package-path ios/Flutter/ephemeral/Packages/.packages/permission_handler_apple \
  dump-package > /dev/null
```

That prints the `Info.plist` files that were used, the app root or the active flavor depending on
whether you declared one, and the value every `PERMISSION_*` macro resolved to — the quickest way
to check what your app will actually be built with.

## Issues

Please file any issues, bugs, or feature requests as an issue on our [GitHub](https://github.com/Baseflow/flutter-permission-handler/issues) page. Commercial support is available, you can contact us at <hello@baseflow.com>.

## Want to contribute

If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug, or adding a cool new feature), please carefully review our [contribution guide](../CONTRIBUTING.md) and send us your [pull request](https://github.com/Baseflow/flutter-permission-handler/pulls).

## Author

This permission_handler plugin for Flutter is developed by [Baseflow](https://baseflow.com).

## Changelog
## 9.6.4

- Fixes `Permission.locationAlways.status` returning `permanentlyDenied` when only "When In Use"
  is granted and "Always" has not been requested yet. It now returns `denied`, so the app can still
  request it (#1145).
- Fixes a deadlock on iOS 27 where `Permission.notification.status` (and 
  `Permission.criticalAlerts.status`) never returned and froze the app: the status is now read
  asynchronously from `getNotificationSettingsWithCompletionHandler` instead of waiting for it with
  a semaphore on the main thread. `request()` for both permissions uses the same asynchronous check.

## 9.6.3

- Fixes `PERMISSION_HANDLER_INFO_PLIST` not replacing automatic discovery entirely: the Swift
  Package Manager manifest still walked the filesystem looking for the app root before reading
  the variable. When it is set the walk is now skipped, as documented (#1574).

## 9.6.2

- Fix SwiftPM compiles requestAlwaysAuthorization for locationWhenInUse when only exist foreground 
  location propouse (NSLocationWhenInUseUsageDescription plistKey)

## 9.6.1

- Fixes small mistakes in the README.md documentation.

## 9.6.0

- Adds opt-in per-flavor permissions for Swift Package Manager builds. An app can declare a
  `permission_handler.yaml` next to its `pubspec.yaml` mapping each flavor to the `Info.plist` that
  defines it, and only the selected flavor's permissions are compiled in — a permission declared by
  `dev` can no longer reach a `prod` binary. Without this file the previous behaviour is unchanged.
  This is a Swift Package Manager feature: CocoaPods builds set the `PERMISSION_*` macros from the
  `Podfile` and are unaffected, including by the build phase below.
- Adds `dart run permission_handler_apple:select <flavor>`, which records the active flavor and
  clears the caches that would otherwise keep serving the previously resolved permissions. Xcode
  does not re-evaluate a package manifest when an environment variable or the selection changes, so
  this step is required when switching flavors. `select` is also the only YAML reader: a Swift
  package manifest cannot parse YAML, so the command translates the config into a generated
  `ios/Flutter/permission_handler.resolved.json` (gitignore it) that the manifest and the build
  phase read with their native JSON parsers. A translation older than the YAML fails the build
  instead of shipping stale permissions.
- Adds `tool/verify_flavor_selection.sh`, a build phase for the app target that fails the build when
  the selected flavor does not match the configuration being built. A package manifest is evaluated
  once and cannot detect that its own result went stale, so this is what catches a forgotten
  `select`. It is a no-op without a `permission_handler.yaml` and on CocoaPods builds.
- Adds the `PERMISSION_HANDLER_FLAVOR` and `PERMISSION_HANDLER_CONFIG` environment variables to set
  the active flavor and the configuration file location explicitly.
- `select` validates the configuration up front and refuses anything ambiguous: a build
  configuration claimed by more than one flavor, a `configurations` that is not a list, a
  non-string flavor name, or a `strict` that is not a boolean. Being the only reader of the YAML,
  it is the only place where these can be reported at all.

## 9.5.1

- Fixes the Swift Package Manager permission auto-detection, which failed to find the host app's
  `Info.plist` and silently compiled out every permission. Apps hit this in two ways: the manifest
  only ever looked at `ios/Runner/Info.plist`, so build-configuration or flavor specific plists such
  as `Info-Debug.plist` were never seen ([#1548](https://github.com/Baseflow/flutter-permission-handler/issues/1548)),
  and the app-root lookup could walk past the app entirely. `Info.plist` locations are now resolved
  from `INFOPLIST_FILE` in the Xcode project and any `.xcconfig` files, with a scan of `ios/` as a
  fallback, and the usage description keys found across them are merged.
- Adds the `PERMISSION_HANDLER_INFO_PLIST` environment variable, which points the manifest at one or
  more `Info.plist` files and replaces automatic discovery. This is required for builds started from
  Xcode.app, which run with `/` as their working directory and cannot be detected automatically.
- Adds the `PERMISSION_HANDLER_VERBOSE` environment variable, which logs the app root, the
  `Info.plist` files used, and the resolved `PERMISSION_*` macros.
- Emits a warning when no `Info.plist` can be located, instead of silently disabling every
  permission. Note that Xcode discards Swift package manifest output, so this warning is only
  visible through the `swift package` command line.

## 9.5.0

- Adds support for the new Android 17 permission `ACCESS_LOCAL_NETWORK`.

## 9.4.10

- Fixed Info.plist lookup in Package.swift to auto-apply permissions.
- You may see build log "Plugin permission_handler_apple has a Package.swift for ios but is missing a dependency on FlutterFramework". FlutterFramework hasn't been added intentionally because it requires to bump flutter constraint to >=3.41.0.

## 9.4.9

- Rewrites copyleft code from stackoverflow to fix compliance issue.

## 9.4.8

- Adds Swift Package Manager (SPM) support for Flutter 3.24+. Permissions are
  enabled automatically based on usage description keys present in `Info.plist`
  — no additional configuration required beyond clearing DerivedData once after
  changes: `rm -rf ~/Library/Developer/Xcode/DerivedData`.
- Moves ObjC sources to SPM-compatible layout (`Sources/permission_handler_apple/`).
  CocoaPods continues to work unchanged.
- Bumps minimum iOS deployment target to 12.0.

## 9.4.7

- Increases minimum supported Flutter version to 3.3.0, and removes code only
  required for iOS versions prior to iOS 11.

## 9.4.6

- Adds the ability to handle `CNAuthorizationStatusLimited` introduced in ios18

## 9.4.5

- Fixes issue #1002, Xcode warning of the unresponsive of main thread when checking isLocationEnabled.
  
## 9.4.4

- Fixes potentially-nil return type of EventPermissionStrategy#getEntityType.
- - Fixes typo in comment for full calendar access.

## 9.4.3

- Adds the `PERMISSION_LOCATION_WHENINUSE` macro, which can be used instead of
the `PERMISSION_LOCATION` macro, and exclusively enables the `requestWhenInUseAuthorization`
and remove the `requestAlwaysAuthorization` when requesting location permission.
- Improves error handling when `Info.plist` doesn't contain the correct declarations.
- Adds support for the `NSLocationAlwaysAndWhenInUseUsageDescription` property list
key.

## 9.4.2

- Updates the privacy manifest to include the use of the `NSUserDefaults` API. 
The permission_handler stores a boolean value to track if permission to always 
access the device location has been requested.

## 9.4.1

- Adds empty privacy manifest.

## 9.4.0

- Adds a new permission `Permission.backgroundRefresh` to check the background refresh permission status.

## 9.3.1

- Updates plist key from `NSPhotoLibraryUsageDescription` to `NSPhotoLibraryAddUsageDescription`.

## 9.3.0

- Adds support to request authorization to access SiriKit via the `Permission.assistant` permission.

## 9.2.0

- Adds the support for `Permission.calendarWriteOnly` and `Permission.calendarFullAccess` permissions which are introduced in iOS 17+.

## 9.1.4

- Adds checking whether Bluetooth service is enabled through `Permission.bluetooth.serviceStatus`.

## 9.1.3

- Fixes an issue where the `Permission.location.request()`, `Permission.locationWhenInUse.request()` and `Permission.locationAlways.request()` calls returned `PermissionStatus.denied` regardless of the actual permission status.

## 9.1.2

- Fixes an issue where the `Permission.locationAlways.request()` call hangs when the application was granted "Allow once" permissions for fetching location coordinates.

## 9.1.1

- Adds the new Android 13 permission "BODY_SENSORS_BACKGROUND" to PermissionHandlerEnums.h.

## 9.1.0

- Adds the "Provisional" permission status which is introduced in iOS 12+.

## 9.0.8

- Adds missing return statement causing the permission_handler to freeze when already requesting permissions.

## 9.0.7

- Adds new Android 13 permissions "SCHEDULE_EXACT_ALARM, READ_MEDIA_IMAGES, READ_MEDIA_VIDEO and READ_MEDIA_AUDIO" to PermissionHandlerEnums.h

## 9.0.6

- Prevents appearing popup that asks to turn on Bluetooth on iOS

## 9.0.5

- Adds new Android 13 NEARBY_WIFI_DEVICES permission to PermissionHandlerEnums.h

## 9.0.4

- Adds flag inside `UserDefaults` to save whether `locationAlways` has already been requested and prevent further requests, which would be left unanswered by the system.

## 9.0.3

- Ensures a request for `locationAlways` permission returns a result unblocking the permission request and preventing the `ERROR_ALREADY_REQUESTING_PERMISSIONS` error for subsequent permission requests.

## 9.0.2

- Moves Apple implementation into its own package.







 
