Baseflow / Baseflow/flutter-permission-handler

[Bug]: SwiftPM compiles requestAlwaysAuthorization for locationWhenInUse and triggers ITMS-90683

Open
#1,558 4 comments 1 reaction 0 assignees View on GitHub
Dominant language
Dart
Stars
2.2k
Forks
970
Avg merge
14h 22m
Merged PRs (30d)
2

Description

### Please check the following before submitting a new issue.

- [x] I have searched the [existing issues](https://github.com/baseflow/flutter-permission-handler/issues).
- [x] I have carefully [read the documentation](https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler/README.md) and verified I have added the required platform specific configuration.

### Please select affected platform(s)

- [ ] Android
- [x] iOS
- [ ] Windows

### Steps to reproduce

This reproduces in a newly created Flutter application with the default single `ios/Runner/Info.plist`. There are no flavors, extensions, custom plist paths, or permission-related environment variables.

1. Create a clean project and add the current package:

```console
flutter create --platforms=ios permission_handler_repro
cd permission_handler_repro
flutter pub add permission_handler:^13.0.1
```

This resolves `permission_handler_apple 9.6.1`.

2. Add only the foreground location purpose string to `ios/Runner/Info.plist`:

```xml
NSLocationWhenInUseUsageDescription
Location is used while the app is open.
```

Do not add `NSLocationAlwaysAndWhenInUseUsageDescription`.

3. Request only the foreground permission:

```dart
await Permission.locationWhenInUse.request();
```

4. Make sure no location macro overrides are present and build the release application:

```console
unset PERMISSION_LOCATION
unset PERMISSION_LOCATION_ALWAYS
unset PERMISSION_LOCATION_WHENINUSE
flutter clean
flutter pub get
flutter build ios --release --no-codesign
```

5. Inspect the built application:

```console
/usr/libexec/PlistBuddy \
-c 'Print :NSLocationAlwaysAndWhenInUseUsageDescription' \
build/ios/iphoneos/Runner.app/Info.plist

strings build/ios/iphoneos/Runner.app/Runner \
| grep -E '^request(Always|WhenInUse)Authorization$'
```

The plist correctly contains no Always purpose string, but the binary contains `requestAlwaysAuthorization`.

The manifest result can also be inspected with verbose output and the manifest cache disabled:

```console
PERMISSION_HANDLER_VERBOSE=1 \
swift package --manifest-cache none \
--package-path ios/Flutter/ephemeral/Packages/.packages/permission_handler_apple-9.6.1 \
dump-package
```

Relevant output:

```text
PERMISSION_LOCATION=1
PERMISSION_LOCATION_ALWAYS=0
PERMISSION_LOCATION_WHENINUSE=1
```

6. Archive and upload the application to App Store Connect. Validation reports ITMS-90683 and requests `NSLocationAlwaysAndWhenInUseUsageDescription`.

### Expected results

When the app declares only `NSLocationWhenInUseUsageDescription` and requests only `Permission.locationWhenInUse`:

- only foreground location support should be compiled;
- the release binary should contain `requestWhenInUseAuthorization`;
- the release binary should not contain `requestAlwaysAuthorization`;
- App Store Connect should not require `NSLocationAlwaysAndWhenInUseUsageDescription`.

### Actual results

SwiftPM enables both the generic and foreground macros:

```text
PERMISSION_LOCATION=1
PERMISSION_LOCATION_ALWAYS=0
PERMISSION_LOCATION_WHENINUSE=1
```

The release binary contains:

```text
requestAlwaysAuthorization
requestWhenInUseAuthorization
```

App Store Connect then reports:

```text
ITMS-90683: Missing purpose string in Info.plist

The Info.plist file for the “Runner.app” bundle should contain a
NSLocationAlwaysAndWhenInUseUsageDescription key with a user-facing purpose
string explaining clearly and completely why your app needs the data.
```

Adding that key would provide a misleading privacy declaration because the application neither needs nor requests Always location access.

This is not an Info.plist discovery or stale-cache issue: it reproduces in a clean, single-plist Flutter project, and verbose manifest output confirms that the intended plist was discovered.

### Code sample

Code sample
```dart
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(const MaterialApp(home: ReproPage()));

class ReproPage extends StatelessWidget {
const ReproPage({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: Permission.locationWhenInUse.request,
child: const Text('Request location when in use'),
),
),
);
}
}
```

### Screenshots or video

Screenshots or video demonstration

[Upload media here]

### Version

permission_handler: 13.0.1, permission_handler_apple: 9.6.1

### Flutter Doctor output

Doctor output

```console
[✓] Flutter (Channel stable, 3.47.1, on macOS 26.4 25E246 darwin-arm64, locale ru-KZ) [184ms]
• Flutter version 3.47.1 on channel stable at /Users/dev/fvm/versions/3.47.1
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 6655482ec0 (7 days ago), 2026-08-19 10:07:23 -0700
• Engine revision 5d53178869
• Dart version 3.13.1
• DevTools version 2.60.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-record-use, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration

[✓] Android toolchain - develop for Android devices (Android SDK version 37.0.0) [846ms]
• Android SDK at /Users/dev/Library/Android/sdk
• Emulator version 36.6.11.0 (build_id 15507667) (CL:N/A)
• Platform android-37.0, build-tools 37.0.0
• ANDROID_HOME = /Users/dev/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.10+-117844308-b1163.108)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.6) [477ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17F113
• CocoaPods version 1.17.0

[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome) [3ms]
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Connected device (2 available) [5,6s]
• Xs (mobile) • • ios • iOS 18.3.1 22D72
• macOS (desktop) • macos • darwin-arm64 • macOS 26.4 25E246 darwin-arm64

[✓] Network resources [309ms]
• All expected network resources are available.

! Doctor found issues in 1 category.
```

Contributor guide

Open the contributing guide

Research direction

Start with the permission_handler_apple-9.6.1 package under ios/Flutter/ephemeral/Packages/.packages and inspect its SwiftPM manifest configuration. Reproduce the issue with the provided dump-package, strings, and release-build commands, then verify that a foreground-only configuration no longer includes Always location support or triggers ITMS-90683.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, ios, swift
Domain
build-system, mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.