flutter-geolocator
flutter-geolocator copied to clipboard
[Bug]: Apple complains about the need for NSLocationAlwaysAndWhenInUseUsageDescription
Please check the following before submitting a new issue.
- [X] I have searched the existing issues.
- [X] I have carefully read the documentation and verified I have added the required platform specific configuration.
Please select affected platform(s)
- [ ] Android
- [X] iOS
- [ ] Linux
- [ ] macOS
- [ ] Web
- [ ] Windows
Steps to reproduce
I have the NSLocationWhenInUseUsageDescription set, and don't want/expect my user to grant 'always' permission, so I have not set NSLocationAlwaysAndWhenInUseUsageDescription.
Expected results
No issue with Apple submission
Actual results
Apple rejects the app, because the plugin code in PermissionHandler.m line 76 contains a reference to the 'always' authorization [locationManager requestAlwaysAuthorization];, even though I never request that (because NSLocationAlwaysAndWhenInUseUsageDescription is not set).
You may have to implement an approach where users add a compile constant to the PodFile that allows you to conditionally compile the request for 'always' authorization (using #if, not if). If it's not compiled, Apple won't complain.
See here for how I've done this for a plugin I maintain. (commit)
Code sample
N/A
Screenshots or video
No response
Version
10.1.0
Flutter Doctor output
Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.16.5, on macOS 14.2.1 23C71 darwin-arm64, locale en-US) [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 15.0.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2023.1) [✓] Connected device (4 available) [✓] Network resources
• No issues found!
Dear @781flyingdutchman,
Thanks for your input. I'll label this issue as an enhancement to keep track of it.
Kind regards,
I've submitted a PR for this
Solved in PR #1404, thanks @781flyingdutchman.
@mvanbeusekom @781flyingdutchman The current library version does not address this issue. I encounter it consistently whenever attempting to release the app to the app store. So far, I've attempted to clean the Flutter project and have followed the two solutions outlined in the official library documentation, yet to no avail. This roadblock is hindering me from releasing the app on the Play Store. Your assistance in resolving this matter would be greatly appreciated. Please Help. 1 --> f you don't need to receive updates when your app is in the background, then add a compiler flag as follows: in XCode, click on Pods, choose the Target 'geolocator_apple', choose Build Settings, in the search box look for 'Preprocessor Macros' then add the BYPASS_PERMISSION_LOCATION_ALWAYS=1 flag. Setting this flag prevents your app from requiring the NSLocationAlwaysAndWhenInUseUsageDescription entry in Info.plist, and avoids questions from Apple when submitting your app. 2 -->
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "geolocator_apple"
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BYPASS_PERMISSION_LOCATION_ALWAYS=1']
end
end
end
end
ITMS-90683: Missing purpose string in Info.plist - Your app’s code references one or more APIs that access sensitive user data, or the app has one or more entitlements that permit such access. 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. If you’re using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. For details, visit: https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/requesting_access_to_protected_resources.
That is strange: the use of compiler flags ensures that the code containing references to the API for background location is skipped (not compiled) so it does not appear in the binary that you submit to Apple. The fact that you get this response still from Apple suggests that the flag is not set correctly (by default, the code containing the API reference is compiled).
As I mentioned to @mvanbeusekom the structure of the plugin makes it difficult for me to test, but what I can say is that if the flag is set correctly, then the code that references the sensitive API should show 'dimmed' in Xcode. Perhaps you can check if that's the case for you @yogeshelevn : the file is https://github.com/Baseflow/flutter-geolocator/blob/main/geolocator_apple/ios/Classes/Handlers/PermissionHandler.m, so find that file in your XCode project, and the lines that should show dimmed are 76-78 and 95-104. If they don't show dimmed after you have set the flag manually, then somehow you have not set the flag correctly!
@781flyingdutchman I checked in my xcode project. line number from 76-78, 95-104 is dimmed as you mentioned still I am getting the issue. This is my PodFile and please do let me lnow it is correct or not.
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
platform :ios, '14.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
# post_install do |installer|
# installer.pods_project.targets.each do |target|
# if target.name == "geolocator_apple"
# target.build_configurations.each do |config|
# config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BYPASS_PERMISSION_LOCATION_ALWAYS=1']
# end
# end
# end
# end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
if target.name == "geolocator_apple"
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BYPASS_PERMISSION_LOCATION_ALWAYS=1']
end
end
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
# You can remove unused permissions here
# for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
# e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_CONTACTS=1',
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1',
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=1',
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=1',
'PERMISSION_NOTIFICATIONS=1',
## dart: PermissionGroup.mediaLibrary
'PERMISSION_MEDIA_LIBRARY=1',
]
end
awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks')
require awesome_pod_file
update_awesome_pod_build_settings(installer)
end
awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks')
require awesome_pod_file
update_awesome_main_target_settings('Runner', File.dirname(File.realpath(__FILE__)), flutter_root)
end
https://drive.google.com/file/d/1EHP7dOXJQFmXE9M-6UOIwftIsZH_9k6X/view?usp=sharing https://drive.google.com/file/d/1g20urjIxHxNQwqFdEmgjfeiz2Q0RBQ_O/view?usp=sharing
Very strange. @mvanbeusekom do you have any idea how this could then still get compiled? Did you come across this issue with anyone else?
Hi @yogeshelevn,
I think the problem here is not with the configuration of the geolocator but with the permission_handler plugin. From the supplied content of the Podfile I see the application uses the permission_handler plugin and enables the PERMISSION_LOCATION setting.
Unfortunately the permission_handler does not yet make a distinction between "Location when in use" or "Location always" and declaring the PERMISSION_LOCATION=1 definition includes Objective-C code that calls the requestAlwaysAuthorization method of the CLLocationManager SDK. This is most likely what Apple's static code analysis causes to trigger the error.
At the moment there are two workarounds for you to take:
- Include the missing
NSLocationAlwaysAndWhenInUseUsageDescriptionkey in theios/Runner/Info.plistor; - Fallback on the
geolocatorplugin to request the location permissions and disable / remove thePERMISSION_LOCATION=1line from theios/Podfile.
Alternatively I will research if we can add additional macros in the permission_handler plugin to allow more fine grained control.
@yogeshelevn, we have just release version 11.3.1 of the permission_handler plugin which is updated to allow the use of only "When in use" permission.
To configure this replace the PERMISSION_LOCATION=1 macro in the ios/Podfile with the PERMISSION_LOCATION_WHENINUSE=1 macro. In your case the ios/Podfile will look like this:
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
platform :ios, '14.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
# post_install do |installer|
# installer.pods_project.targets.each do |target|
# if target.name == "geolocator_apple"
# target.build_configurations.each do |config|
# config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BYPASS_PERMISSION_LOCATION_ALWAYS=1']
# end
# end
# end
# end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
if target.name == "geolocator_apple"
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BYPASS_PERMISSION_LOCATION_ALWAYS=1']
end
end
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
# You can remove unused permissions here
# for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
# e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_CONTACTS=1',
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1',
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=1',
## dart: [PermissionGroup.location, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION_WHENINUSE=1',
'PERMISSION_NOTIFICATIONS=1',
## dart: PermissionGroup.mediaLibrary
'PERMISSION_MEDIA_LIBRARY=1',
]
end
awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks')
require awesome_pod_file
update_awesome_pod_build_settings(installer)
end
awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks')
require awesome_pod_file
update_awesome_main_target_settings('Runner', File.dirname(File.realpath(__FILE__)), flutter_root)
end
Hope this helps, if you have any problems please create an issue in the repo of the permission_handler plugin.