In android, you define permissions for gps, sms sending, location , .., in the manifest file.
Is there anything similar in the iOS, so the user would know what capabilities of the phone some app uses before installation?
Or is the user warned during app use when some function wants to use something (e.g. gps, sms...)?
In iOS you declare your application requirements in its manifest-like Info.plist. But this information is not used to ask user permission, only for ensuring device compatibility.
Only Notifications and Location Services require user permission, which is automatically asked to the user the very first time your application attempt to use the corresponding API.
My guess is that many other permissions are already granted via the Apple Store license agreement, that the user must have accepted, unlike Android (I guess you can install an app without using the market isnt? which changes a lot from a legal point of view)
There's no such things as permissions on iPhone.
The only thing that user is warned about is when application uses his current location - then user is prompted with system alert and must explicitly allow or deny application's access to location data.
What concerns sms and email, they can be created and sent only via standard controllers so user will be aware of that anyway
on iOS you don't have to declare all necessary permissions in some specific file. You just use them. For example location
info.plist
//Privacy - Location When In Use Usage Description
<key>NSLocationUsageDescription</key>
<string>title</string>
//Privacy - Location Always and When In Use Usage Description
<key>NSLocationWhenInUseUsageDescription</key>
<string>description</string>
import CoreLocation
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
}
[IDFA]
Related
I'm building a running-based app in Swift that requests the user's location. For the sake of this question, let's just assume the app runs only on iOS 13+. Shortly after launching the app, we prompt the user for location access via the CLLocationManager method: requestWhenInUseAuthorization().
However, this app actually needs access to the user's location all the time, so only being able to request "When In Use" location access (per iOS 13) restricts the UX (other apps like Zenly and Snapchat do this as well since getting constant location updates improves the experience for their users and/or their friends).
After prompting for the location permission, we then grab the latest location authorization status. If that value is not equal to authorizedAlways (and it won't be unless the user changes that value in his/her Settings app), we present a new screen basically telling the user, "Since this is a running app, we really need your location all the time, so please go to settings and change the permission to 'Always' since we can't do it for you."
The issue I'm running into here is that when listening for updates on the CLLocationManagerDelegate method: locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus), sometimes that method provides the incorrect location authorization status.
Specifically, after a user selects "When In Use" and runs the app a few times, the value returned from that delegate method frequently reads as "Always," even though the Settings app on the phone still reflects the original, unchanged value ("When In Use").
Has anyone run into this before and, if so, do you have any ideas on what might cause it or how to fix it? Happy to provide more info on my setup. Thanks.
I have followed the apple developer guide on location services.
I have included the info.plist key value pair:
key: Privacy - Location Always Usage Description
value: The application myTestApp needs access to location services even in the background
I have created an instance of CLLocationManager as a class variable of the view controller:
var locationManager = CLLocationManager()
I have code in the view controller viewDidLoad() function that assigns the delegate and checks for the current status:
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
let status = CLLocationManager.authorizationStatus()
switch status {
case .denied, .restricted, .notDetermined, .authorizedWhenInUse :
print("The switch detected a state other than always")
locationManager.requestAlwaysAuthorization()
default:
print("Services Authorized")
}
Yet, when I build and run the application after making small changes it does not prompt for user access, and even worse, when it does sometimes work it thinks the user is in the middle of the Atlantic ocean at Lat: 0.0 and Long: 0.0.
Is there anything outside of the code I need to do so that I can recreate the user experience of authorizing the application and then seeing it zoom to a real location?
The user permission prompt is one time only. Once it is allowed,
device would fetch user location automatically from that point.
Try setting the custom location in the simulator via these two methods.
1. Using the simulator menu actions
2. Using the Xcode debugger options
The simulator handles location a bit differently from the device. I'd suggest pushing the app over to the device itself and running from there to see how it asks for permission and make sure it is giving the right location. It's very easy to do and very helpful for testing with apps that use access to location services.
https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/LaunchingYourApponDevices/LaunchingYourApponDevices.html
Essentially, plug phone in, select it from the list of devices to simulate with, press play and accept your developer access on the phone to run the app from your device.
I am using the google google places api or an iOS app and was wondering how to avoid having to ask for allowing "always on" location (NSLocationAlwaysUsageDescription). I do not think my app needs to access the location while in the background (is there a reason to?)
My google places api call is in a callback in viewDidLoad. Should I put it elsewhere in order to only ask for less intrusive permissions?
Thanks
There are 2 methods on CLLocationManager that request the location access. In order to request location access while the app is running you need to call requestWhenInUseAuthorization.
For example:
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
I'm assuming you were following this guide where it show location access like this:
locationManager.requestAlwaysAuthorization()
That method does request the access to always use your device's location, even while the app is in the background.
Hope that helps!
My app requires users current location to show him direction to a particular location in google map
Below is the code to show location on web view-
[self.getDirectionsWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://maps.google.com/maps?saddr=%f,%f&daddr=%f,%f",currentLocation.coordinate.latitude,currentLocation.coordinate.longitude,self.projectLatitude,self.projectLongitude]]]];
The app declares support for location in .plist by using NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
Apple rejected the app with following reason
2.16 Details
Your app declares support for location in the UIBackgroundModes key in
your Info.plist file but still does not declare any features that
require persistent location. Apps that declare support for location in
the UIBackgroundModes key in your Info.plist file must have features
that require persistent location.
Specifically, we noticed that the Directions feature does not require
persistent location information, since it does not include
turn-by-turn navigation.
Any help will be appreciated, Thanks in Advance.
You just remove the location support from UIBackgroundModes key in info.plist
As you must only use UIBackgroundModes for location when you want to fetch location when your app is in background.
In your app declaration of NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription is enough.
Based on:
My app requires users current location to show him direction to a particular location in google map.
NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription
we noticed that the Directions feature does not require persistent location information, since it does not include turn-by-turn navigation
It looks like they're stating you shouldn't need location information unless the app is actually active. Since the location information is used to show the user the direction they need to head in, you should be able to simply adjust (with a little latency of course) when your app comes to the fore.
From Apple's documentation:
UIBackgroundModes (Array - iOS) specifies that the app provides specific background services and must be allowed to continue running while in the background.
These keys should be used sparingly and only by apps providing the indicated services. Where alternatives for running in the background exist, those alternatives should be used instead.
For example, apps can use the significant location change interface to receive location events instead of registering as a background location app.
That'd be my analysis though it's equally likely that the reviewer just had an argument with their significant other that morning, and is just being capricious :-) Nah, just joking, but it does sometimes seem to outsiders that the decisions they make are, shall we say, less than perfectly consistent.
It's is not necessary to request the background mode to request the user's current location.
I would recommend to use NSLocationWhenInUseUsageDescription if you don't need to use the user's location in background. Users are more inclined to deny the user location authorization when they see NSLocationAlwaysUsageDescription because they think that reduce the device's battery
When the user launches the app for the first time and attempts to login, they are prompted with the iOS dialog - "Turn On Location Services".
I need to capture when the user clicks "cancel". Is there a Notification sent? If so, what is its name? I've been unable to locate it.
The CLAUthorizationStatus is kCLAuthorizationDenied when Location Services are Disabled OR the user clicked "Don't allow". When the user clicks "Cancel", it does not fire the authorizationChange event. When user clicks "Cancel", the app just hangs.
Short answer: You can't catch that notification. You can infer about the user choice and act consequently by using CLLocationManager methods (the longer answer below).
Longer answer:
Firstly, welcome on Stack Overflow. Before kindly posing your question, and trying to be collaborative with people that are here to help, it's a good idea to search if somebody else previously posed the same question.
A brief search gave (just to mention some of them):
How to handle “Cancel” button on Alert pop up for Location services
How to get location services to reprompt the user for location permission if they accidentally refused it?
locationManager:didFailWithError: not called if user Location Services are off
How to prompt user to turn on Location Services…again
How can I prompt the user to turn on location services after user has denied their use
How to ask permission from user for second time to allow to access the current location?
Now, let's try to summarize them all, starting from iOS docs:
If your app relies on location services to function properly, you should include the UIRequiredDeviceCapabilities key in the app’s Info.plist file. You use this key to specify the location services that must be present in order for your app to run. The App Store uses the information in this key from preventing users from downloading apps to devices that do not contain the listed features.
Important: If your app uses location services but is able to operate successfully without them, do not include the corresponding strings in the UIRequiredDeviceCapabilities key.
So, if your app really needs to access the user's position you should add location-services and eventually gps to UIRequiredDeviceCapabilities.
Then, somewhere in your code - when needed, you have to check if the location services are enabled.
[CLLocationManager locationServicesEnabled]
they may be disallowed for three reasons:
The user can disable location services in the Settings app.
The user can deny location services for a specific app.
The device might be in Airplane mode and unable to power up the necessary hardware.
You are interested in the second case: the user refused to allow your app to use the location services.
Again, from the docs:
Important: In addition to hardware not being available, the user has the option of denying an application’s access to location service data. During its initial uses by an application, the Core Location framework prompts the user to confirm that using the location service is acceptable. If the user denies the request, the CLLocationManager object reports an appropriate error to its delegate during future requests. You can also check the application’s explicit authorization status using the authorizationStatus method.
[CLLocationManager authorizationStatus]
That may return:
kCLAuthorizationStatusNotDetermined if the user has not yet made a choice regarding whether this application can use location services.
kCLAuthorizationStatusRestricted this application is not authorized to use location services. The user cannot change this application’s status, possibly due to active restrictions such as parental controls being in place.
kCLAuthorizationStatusDenied The user explicitly denied the use of location services for this application or location services are currently disabled in Settings.
kCLAuthorizationStatusAuthorized This application is authorized to use location services.
If[CLLocationManager locationServicesEnabled] returns NO and you attempt to start location services anyway (i.e. calling [locationManager startUpdatingLocation]), the system prompts the user to confirm whether location services should be re-enabled. Given that location services are very likely to be disabled on purpose, the user might not welcome this prompt.
I suppose you know, and did all the previous steps (I'm only sure you checked the authorizationStatus). You refused to show us the significant code of your app so I can only suppose the overall logic behind. Now you said your app hangs. This should be because you didn't catch the error properly? Catching the error is the way to re-prompt the user, if you wish.
After calling [locationManager startUpdatingLocation], if not authorized, your delegate should define a locationManager:didFailWithError: in order to catch the kCLErrorDenied.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
You may show, at this point, a UIAlert to insist asking the user to give you access to its position, or trigger a change in the UI or whatever you like.
Final notes
I hope you understand why I was asking for the code: the reason was to offer you an alternative solution instead of reply "You can't catch the 'Cancel' notification".
If this answer does not satisfy your question please elaborate why you need to catch the pushing of the "Cancel"/"Do not allow" button, so we can provide alternatives.
Clearly my advice is to not annoy people to death by continuously ask them for enabling location services if they don't want.
Post scriptum: Maybe that the answer looks pedantic and obvious in certain parts if not all to you, but we are here to provide answers also for future readers.