I have an iOS app, which requests location permissions. If the user accepts, everything works fine (of course). But if the user doesn't accept and then manually triggers a localisation, he get the dialog provided by Apple to change the settings for the app in the Settings-App.
But if the user clicks on Settings, it just opens the Settings-App without jumping to the settings of my App. The app is also not listed in the Settings-App mainscreen, but can be found under Privacy -> Location Services.
But once you accept the location (or any other) permissions, the app appears in the Settings and the links work fine.
NSLocationAlwaysAndWhenInUseUsageDescription is included in the pList.
Any ideas on how to guarantee the to appear in the Settings-App mainscreen?
try to check current location permission
and if it's declined show custom alert with this button action
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else { return }
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl)
}
Related
App Store Connection reviewers informed me that my build is in violation of the below rule:
Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage
We noticed that your app requests the user’s consent to access their location but does not clarify the use of the location in the applicable purpose string.
...even though I have included the following key value pair in my App's Info.plist:
Privacy - Location When In Use Usage Description: Access to location
while the app is in use is required initialize your map feed.
...and I am therefore unable to replicate the issue in the screenshot they shared with me below:
Here is the dialogue I have always seen on the same Device (iPad) iOS 13.3:
My understanding of Apple's docs is that I only need NSLocationWhenInUseUsageDescription as my application only requires access to a user's location when in the foreground.
Has anyone encountered a similar issue before or have an idea what the source of it is? Many thanks!
Edit: Below is the code governing this experience.
func requestLocationAuthorization(completion: (() -> Void)?) {
let locationManagerAuthorizationStatus: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
let appName = Bundle.main.infoDictionary![kCFBundleNameKey as String] as! String
switch locationManagerAuthorizationStatus {
case .notDetermined:
LNTLocationManager.sharedInstance.requestAuthorization()
case .denied:
let alertString = "To initialize your map feed to your location, enable " + appName + " to use your location while using the app."
presentSettingsAlert(with: alertString, completion: nil)
default:
break
}
completion?()
return
}
In the case where I don't enable location access, I always see the below prompt, not the one that the Reviewers experience:
The dialog they are displaying is what appears from the system the first time you say startUpdatingLocation at a time when locationServicesEnabled is false. It has nothing to do with the denied alert that you are putting up.
Note that this has nothing to do with user authorization! It has to do with location services being turned off as a whole. Apple, while testing, checks for that circumstance. It looks like your app doesn't.
To prevent the system dialog from appearing, always check whether locationServicesEnabled is true, and if it isn't, go no further.
(However, having said that, the message coming to you from Apple is incorrect if they think that the dialog they show is supposed to include your usage description. It isn't. It always looks the way they show it. You might want to write back and tell them that. They might have some people working for them right now who don't know what they're doing.)
I am new to Xamarin iOS and mobile dev in general.
I have a application which requires location services, on my view controller I have a button which takes the user to location settings for the app, however, if the main device location is off the user will not be able to do anything with the app level location setting.
I am using this code on my button click event to take the user to the settings page.
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
NSString settingsString = UIApplication.OpenSettingsUrlString;
NSUrl url = new NSUrl(settingsString);
UIApplication.SharedApplication.OpenUrl(url);
}
I would like to know if there is a way to check if device level Location services are off and take the user to that settings page instead of app-level location settings and vice versa.
Also how to take users to Location settings screen if device level location services is disabled. I tried a few combinations but I am unsure what the NSUrl will be.
To check the Device level location permission:
bool deviceLevel = CLLocationManager.LocationServicesEnabled;
Document here: determining_the_availability_of_location_services
To check the app level location permission:
public void CheckAuthorization(CLLocationManager manager, CLAuthorizationStatus status)
{
switch (status)
{
case CLAuthorizationStatus.Authorized | CLAuthorizationStatus.AuthorizedAlways | CLAuthorizationStatus.AuthorizedWhenInUse:
Console.WriteLine("Access");
break;
case CLAuthorizationStatus.Denied | CLAuthorizationStatus.NotDetermined | CLAuthorizationStatus.Restricted:
Console.WriteLine("No Access");
break;
default:
Console.WriteLine("No Access");
break;
}
}
Document here: clauthorizationstatus
Update:
Have a look at answers in there two threads: how-to-programmatically-open-settings-privacy-location-services-in-ios-11 and how-to-open-location-services-screen-from-setting-screen
There says
Avoid use of "prefs:root" or "App-Prefs:root" in you app, otherwise
App will be rejected from App Store. Just open Setting page.
You can not open the device location permission directly, it is not allow through App Store rules.
Just use UIApplication.OpenSettingsUrlString; to open the setting page.
Welcome to mobile and Xamarin! Yes there are several Nuget Packages you can add that will help you do this. One that's gaining popularity is Xamarin Essentials.
As they show in the documentation, just try to get the location, it will handle permissions by itself, and if you face PermissionException, then you can open the settings as you are! Happy Coding
You can check if the user has disabled the Location services at the settings level then check the app level:
if(!CLLocationManager.LocationServicesEnabled)
{
Console.WriteLine("Location Services are off globally go to settings");
// This may get your app rejected using the strings below
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=General"));
}
else
{
UIApplication.SharedApplication.OpenUrl(new NSUrl("prefs:root=General"));
}
}
else if (CLLocationManager.Status == CLAuthorizationStatus.Denied ||
CLLocationManager.Status == CLAuthorizationStatus.NotDetermined ||
CLLocationManager.Status == CLAuthorizationStatus.Restricted)
{
Console.WriteLine("Location Services are off just for your app, got to app settings");
UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));
}
In terms of opening to the system settings or the app settings, UIApplication.OpenSettingsUrlString will go to the app settings as per the docs:
UIApplicationOpenSettingsURLString
Used to create a URL that you can pass to the openURL: method. When you open the URL built from this string, the system launches the Settings app and displays the app’s custom settings, if it has any.
You can use the string:
prefs:root=General
or for iOS 10 and above
App-Prefs:root=General
But Apple may reject your app, tbh I think it's not worth trying to go to the settings just for this reason but up to you.
This is my code for Requesting Review :
if #available(iOS 10.3, *) {
SKStoreReviewController.requestReview()
}
else{
print("Review is not available with in the app")
}
In Development Mode it is working properly & I am able to get PopUp like this:
But In Live app downloaded from appstore, App isnot showing this ratings Popup and nothing happens if user taps out on Ratings Button.
From the documentation:
Although you should call this method when it makes sense in the user experience flow of your app, the actual display of a rating/review request view is governed by App Store policy. Because this method may or may not present an alert, it's not appropriate to call it in response to a button tap or other user action.
(Highlight mine)
If you have a Ratings Button like you said in your question, you should not expect it to show the prompt.
The prompt will only show up if:
The user hasn't disabled Review Prompts in Settings.
The prompt has been shown to the user 3 times or less in a year.
If you must request a review upon user interaction, you must direct your users to the App Store page of your app instead, using code like this (taken from Requesting App Store Reviews Sample Code):
#IBAction func requestReviewManually() {
// Note: Replace the XXXXXXXXXX below with the App Store ID for your app
// You can find the App Store ID in your app's product URL
guard let writeReviewURL = URL(string: "https://itunes.apple.com/app/idXXXXXXXXXX?action=write-review")
else { fatalError("Expected a valid URL") }
UIApplication.shared.open(writeReviewURL, options: [:], completionHandler: nil)
}
I've run into a strange case with requesting Calendar access in iOS 9. The logic works fine on all iOS 10 devices.
In our case, we've added a button on a toolbar that the user taps to add an Event to their Calendar.
So, we don't check for permission to access the calendar until the first time the user taps the "Add to Calendar" button. Like this:
#IBAction func addToCalendarPressed(_ sender: UIBarButtonItem) {
eventStore.requestAccess(to: .event, completion: { (granted, error) in
if (granted) && (error == nil) {
// Present the EKEventEditViewController
} else {
// Do something else (show an alert)
}
})
}
In iOS 10, the app displays the prompt for Calendar access as you'd expect.
In iOS 9.x, the prompt doesn't display, the completion handler fires immediately, and granted returns false.
Worse, even though the "Calendar permission" check appears to have completed, you can't go into Settings and manually enable Calendar access. As far as the device is concerned, the app never made the permission check, so the app never appears under Settings > Privacy > Calendar.
I've tried to move the check into viewWillAppear or viewDidLoad instead of waiting for the user to tap the button, and it still doesn't work. I've pulled some sample apps with the event check and they work in iOS 9. I just haven't been able to figure out why the prompt fails in this instance.
The app also checks for location (but not on this screen), and those work correctly in iOS 9.
We found the issue. Somehow our project didn't have CFBundleDisplayName in the info.plist. At a later point in development, opening the project in Xcode 8 added the property, but left the name blank.
Both the Calendar permission and Photos permission prompts for iOS 9 use that value when displaying the application name in the permission prompt.
The fix was to simply set $(PRODUCT_NAME) for CFBundleDisplayName in our info.plist.
When my app is launched it requests to use location services.
If a user selects 'Don't Allow' I prompt again letting them know that Location Services are required for the best experience and they can enable in the settings app.
If a user does not allow and still creates an account, the main screen will not fully function without the location feature part.
From this point, if I manually enable in the Settings app I'm still not getting the main page to pick up the current location.
How do I detect that location services have been enabled from the Settings App?
Is there a method I need to enforce again from the AppDelegate?
You can tell if location has been enabled for your app using CLLocationManager.AuthorizationStatus, which returns a member of the CLAuthorizationStatus enum. If location is disabled completely, your app won't be authorized, so you know everything you need to know.
let authorization = CLLocationManager.authorizationStatus()
if authorization == .AuthorizedWhenInUse || authorization == .Authorized {
...
}
If you request authorization using CLLocationManager and the user denies it, you can't cause the window to come up again.
From a UX point of view, be careful about nags as well. Communicate clearly that your app benefits from using location, but try to avoid browbeating the user about it.
See also how to determine when settings change on ios to have your app retry location access right after a user (hopefully) enabled it.