permission_handler_apple

v9.6.1

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

Архив пакета: https://pubdev.letsnova.ru/api/archives/permission_handler_apple/9.6.1.tar.gz

Установкаdart pub add permission_handler_apple

README

permission_handler_apple

pub package Build status style: flutter lints

The official iOS implementation of the permission_handler plugin by Baseflow.

Usage

Since version 9.1.0 of the 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 of the 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:

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:

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:

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.

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:

# 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:

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:

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 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 and send us your pull request.

Author

This permission_handler plugin for Flutter is developed by Baseflow.

История изменений

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), 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.