Baseflow / Baseflow/flutter-geolocator

BYPASS_PERMISSION_LOCATION_ALWAYS cannot be set under Swift Package Manager (ITMS-90683 returns)

Open
#1,796 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
1.3k
Forks
803
Avg merge
8h 16m
Merged PRs (30d)
1

Description

#1241 was closed by #1403, which added `BYPASS_PERMISSION_LOCATION_ALWAYS`. That
switch is set from the `Podfile`'s `post_install` hook, so it only exists for
CocoaPods builds. Flutter now supports Swift Package Manager for iOS, and under
SPM there is no `Podfile` — and no supported way to set the macro. The coverage
`#1403` established is therefore lost for every project that has migrated.

**A consuming project cannot inject preprocessor macros into a package target.**
`GCC_PREPROCESSOR_DEFINITIONS` on the app target applies to that target only; it
does not propagate into a Swift package's targets. The package manifest is the
only place those settings can come from.

`geolocator_apple` 2.3.14's `Package.swift` has neither a `.define` nor any
environment lookup:

```swift
targets: [
.target(
name: "geolocator_apple",
dependencies: [],
resources: [.process("PrivacyInfo.xcprivacy")],
publicHeadersPath: "include/geolocator_apple",
cSettings: [.headerSearchPath("include/geolocator_apple")]
)
]
```

So `#if !BYPASS_PERMISSION_LOCATION_ALWAYS` in `Handlers/PermissionHandler.m` is
always true under SPM, and `requestAlwaysAuthorization` is compiled into every
app that uses this plugin.

**Consequence: ITMS-90683 is back for every SPM app, even one that only ever
uses when-in-use.** Verified on a release archive built with `flutter build ipa`
(Flutter 3.44.2, geolocator 14.0.3 / geolocator_apple 2.3.14). The app declares
only `NSLocationWhenInUseUsageDescription` and never requests
always-authorization from Dart. From the uploaded archive:

```
$ strings Payload/Runner.app/Runner | grep containsLocationAlwaysDescription
containsLocationAlwaysDescription

$ strings Payload/Runner.app/Runner | grep -x requestAlwaysAuthorization
requestAlwaysAuthorization
```

`containsLocationAlwaysDescription` is declared inside the
`#if !BYPASS_PERMISSION_LOCATION_ALWAYS` block, so its presence is the direct
evidence that the bypass was not set. App Store Connect returned ITMS-90683 on
upload of that build.

Worth noting how dead this code is for such apps: on iOS the always branch is an
`else if` behind the when-in-use check —

```objc
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
[locationManager requestWhenInUseAuthorization];
}
#if !BYPASS_PERMISSION_LOCATION_ALWAYS
else if ([self containsLocationAlwaysDescription]) {
[locationManager requestAlwaysAuthorization];
}
#endif
```

— so for any app that declares the when-in-use key, the always call can never
execute. It is unreachable at runtime and still costs the warning at upload.

### Reproduction

1. `flutter config --enable-swift-package-manager`
2. Any app with `geolocator`, declaring only
`NSLocationWhenInUseUsageDescription`
3. `flutter build ipa`, then `xcrun altool --upload-app`
→ ITMS-90683 (missing `NSLocationAlwaysAndWhenInUseUsageDescription`)

There is no `Podfile` in this setup, so the `post_install` hook from #1403 never
runs.

### Prior art in the sibling package

`permission_handler_apple` 9.6.1 solves exactly this for SPM: its `Package.swift`
locates the app's `Info.plist` (via `INFOPLIST_FILE` from the Xcode project and
`.xcconfig` files) and derives each `PERMISSION_*` macro from the presence of the
matching `NS*UsageDescription` key, with an environment variable as an override.
Measured on the same archive, only the permissions the app declares are compiled
in — `CNContactStore`, `AVCaptureDevice`, `PHPhotoLibrary`, `CBCentralManager`,
`SFSpeechRecognizer`, `ATTrackingManager` and `EKEventStore` are all absent from
the binary.

### Suggestion

Either of these would close the gap:

1. Derive the switch in `Package.swift` the way `permission_handler_apple` does —
compile the always branch only when `NSLocationAlwaysUsageDescription` or
`NSLocationAlwaysAndWhenInUseUsageDescription` is actually present. That
matches the existing runtime condition exactly, so no app changes behaviour.
2. Failing that, read an environment variable in the manifest, or expose it as a
package trait, so the choice is at least expressible.

Happy to open a PR for option 1 if that direction is welcome.

Contributor guide

Open the contributing guide

Research direction

Start with geolocator_apple's Package.swift and Handlers/PermissionHandler.m, then compare the SPM setup with permission_handler_apple's Package.swift. Reproduce with Flutter's SPM configuration and an app declaring only NSLocationWhenInUseUsageDescription. Done means the release archive no longer contains the unreachable always-authorization path or triggers ITMS-90683 for that app.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, flutter, objective-c, swift
Domain
build-system, mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.