Checking for iOS Location Services - objective-c

I have a view with a map and a button (like the Maps app once) that allows the user to center and zoom his current location on the map. If I can not use the locationServicesEnabled method (always returns YES), should I create a BOOL attribute to check if the didFailWithError method is called and know if I can call the button method?
Thanks for reading.
Edited:
This code does not work for me. I am using the simulator. I am always getting YES when asking locationServicesEnabled.
// Gets the user present location.
- (IBAction)locateUser:(id)sender {
if([CLLocationManager locationServicesEnabled]) {
CLLocationCoordinate2D coordinate;
coordinate.latitude = self.mapView.userLocation.location.coordinate.latitude;
coordinate.longitude = self.mapView.userLocation.location.coordinate.longitude;
[self zoomCoordinate:coordinate];
} else {
[[[[UIAlertView alloc] initWithTitle:#"Warning." message:#"Location services are disabled."
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease] show];
}
}

In Preferences you have two options to disable the location services. The first option is a global switch to disable the location service for all apps "[CLLocationManager locationServicesEnabled]". The second option let you disable the location service for some apps but not for all apps.
To check if its disabled globally and if its disabled for your app use following:
if([CLLocationManager locationServicesEnabled] &&
[CLLocationManager authorizationStatus] != kCLAuthorizationStatusDenied)
{
...
}

"locationServicesEnabled" checks if the user has enabled Location Services in Preferences. Your MapView probably checks this value already and should not set any values to "self.mapView.userLocation" if Location Services are not available. This SO question might give you some more info.

I run into this problem too and still be finding the answer.
take care that authorizationStatus requires iOS4.2+ and + (BOOL)locationServicesEnabled requires iOS4.0... And for previous iOS versions, it is - (BOOL)locationServicesEnabled...

- (BOOL) enableLocationServices
{
if ([CLLocationManager locationServicesEnabled])
{
self.locationManager.distanceFilter = 10;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
[self.mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
return YES;
}
else
{
return NO;
}
}

Related

How to pick photo from camera roll

I do not have a working version or idea how to get photos from your albums via PHPhotoLibrary or ALAssetsLibrary and install them in uicollectionviewcell like in instagram. I'm new to objective c :)
not install - add
I'm not sure what you mean by 'install to uicollectionviewcell' but here's how you would get photos from your album.
Ask for authorization
Show a UIImagePickerController (which is the default image picker view apple created for us)
Implement delegate methods to handle the picked image from the UIImagePickerController
Code would look as follows
Import statement:
#import <Photos/Photos.h>
Instantiate the image picker controller to show:
UIImagePickerController* imagePicker = [[UIImagePickerController alloc]init];
// Check if image access is authorized
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// Use delegate methods to get result of photo library -- Look up UIImagePicker delegate methods
imagePicker.delegate = self;
[self presentViewController:imagePicker animated:true completion:nil];
}
I believe this would usually prompt the user for access to the photo library, but it's always good practice to handle all cases of authorization prior to simply trying to show the imagepicker.
Ask for authorization:
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if(status == PHAuthorizationStatusNotDetermined) {
// Request photo authorization
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
// User code (show imagepicker)
}];
} else if (status == PHAuthorizationStatusAuthorized) {
// User code
} else if (status == PHAuthorizationStatusRestricted) {
// User code
} else if (status == PHAuthorizationStatusDenied) {
// User code
}
Finally implement delegate methods:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
// Do something with picked image
}
After you pick your image, you can add it to a newly instantiated UICollectionViewController. This is probably a whole other question and you would be better off reading documentation for this.
Note that this was introduced in IOS8(I think?), but the AL route code will be similar to the above.
Added
The photo library is just another database, but you still have to ask the user for authorization.
The steps would be as follows:
Ask for authorization
Retrieve photos from photo library
I haven't done #2 myself but there seems to be a way to do it.
Get all of the pictures from an iPhone photoLibrary in an array using AssetsLibrary framework?
From a cursory look, it seems like this is an asynchronous function so you should code accordingly (I would call the requestImage function inside each UICollectionViewCell if I were you).
Leave a comment if you run into any trouble.
Good Luck!
You need to declare delegate UIImagePickerControllerDelegate
like this..
hope its helps you a lot...
- (IBAction)captureImagehandler:(id)sender
{
if (! [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIAlertView *deviceNotFoundAlert = [[UIAlertView alloc] initWithTitle:#"No Device" message:#"Camera is not available"
delegate:nil
cancelButtonTitle:#"exit"
otherButtonTitles:nil];
[deviceNotFoundAlert show];
}
else
{
UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init];
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraPicker.delegate =self;
// Show image picker
[self presentViewController:cameraPicker animated:YES completion:nil];
}
}

AddressBook privacy settings not enforced

I'm doing some working getting an app to line up with the new privacy settings in iOS 8. I've completed the requirements satisfactorily for camera access and now I'm taking a look at how this app access the address book. I'm new to working with address book APIs so these questions may have obvious answers.
As with camera access, I was thinking that access to contacts would behave similarly with respect to the status of the privacy settings granted to the app. The thing is, so far, no matter what the value of ABAuthorizationStatus is - kABAuthorizationStatusNotDetermined or kABAuthorizationStatusDenied - access is always allowed.
Also, when the status is kABAuthorizationStatusNotDetermined, the 'Okay/Don't Allow' dialog is never displayed to the user (I've erased the phone and resinstalled the app to confirm). Furthermore, the app never shows up under the privacy settings. I assume this is because the status is always kABAuthorizationStatusNotDetermined.
The code to initiate access to contacts is below. The controller is shown (read only) and contacts' information can be obtained. Delegate code not shown.
// Debug - Value is always denied or not determined.
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
// Existing code since iOS 7 - always works despite status.
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentViewController:picker animated:YES completion:nil];
It's great that everything seems to be working but I'd like what, if anything, I'm doing wrong.
iPhone 6,
iOS 8.0.2,
Xcode 6
Thanks!
From what I've found (and I could be wrong) while dealing with updating a code base to correctly deal with the new privacy settings in iOS 8 is that such settings are not respected uniformly across features. For example, without changes to address privacy settings for locations, access to CLLocationManager won't work. Depending on the app, this may appear to the user as though nothing is happening or an error message may appear. However, if no such changes are made for address book privacy settings, access is always granted.
I figured out my error after stumbling upon some extremely helpful example code posted by Apple. Below is code I add/modified so that privacy settings are respected properly in the app I work on. When I find the link to the code example I will post it.
-(void) presentAddressBookPicker {
switch (ABAddressBookGetAuthorizationStatus()) {
case kABAuthorizationStatusAuthorized:
[self accessGrantedForAddressBook];
break;
case kABAuthorizationStatusNotDetermined:
[self requestAccessToAddressBook];
break;
case kABAuthorizationStatusRestricted:
case kABAuthorizationStatusDenied:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:#"Unable to access address book"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
break;
default:
// Unlikely but log it anyway.
DLog(#"Unknown address book status.");
break;
}
}
-(void) accessGrantedForAddressBook {
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
-(void) requestAccessToAddressBook {
__weak MyWebViewController* weakSelf = self;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForAddressBook];
});
}
CFRelease(addressBook);
});
}

Ask permission to access Camera Roll

I have a settings view where the user can choose switch on or off the feature 'Export to Camera Roll'
When the user switches it on for the first time (and not when he takes the first picture), I would like the app to ask him the permission to access the camera roll.
I've seen behavior in many app but can't find the way to do it.
I'm not sure if there is some build in method for this, but an easy way would be to use ALAssetsLibrary to pull some meaningless bit of information from the photo library when you turn the feature on. Then you can simply nullify what ever info you pulled, and you will have prompted the user for access to their photos.
The following code for example does nothing more than get the number of photos in the camera roll, but will be enough to trigger the permission prompt.
#import <AssetsLibrary/AssetsLibrary.h>
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
NSLog(#"%zd", [group numberOfAssets]);
} failureBlock:^(NSError *error) {
if (error.code == ALAssetsLibraryAccessUserDeniedError) {
NSLog(#"user denied access, code: %zd", error.code);
} else {
NSLog(#"Other error code: %zd", error.code);
}
}];
EDIT: Just stumbled across this, below is how you can check the authorization status of your applications access to photo albums.
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
if (status != ALAuthorizationStatusAuthorized) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Attention" message:#"Please give this app permission to access your photo library in your settings app!" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil, nil];
[alert show];
}
Since iOS 8 with Photos framework use:
Swift 3.0:
PHPhotoLibrary.requestAuthorization { status in
switch status {
case .authorized:
<#your code#>
case .restricted:
<#your code#>
case .denied:
<#your code#>
default:
// place for .notDetermined - in this callback status is already determined so should never get here
break
}
}
Objective-C:
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusAuthorized:
<#your code#>
break;
case PHAuthorizationStatusRestricted:
<#your code#>
break;
case PHAuthorizationStatusDenied:
<#your code#>
break;
default:
break;
}
}];
Important note from documentation:
This method always returns immediately. If the user has previously granted or denied photo library access permission, it executes the handler block when called; otherwise, it displays an alert and executes the block only after the user has responded to the alert.
Since iOS 10, we also need to provide the photo library usage description in the info.plist file, which I described there. And then just use this code to make alert appear every time we need:
- (void)requestAuthorizationWithRedirectionToSettings {
dispatch_async(dispatch_get_main_queue(), ^{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized)
{
//We have permission. Do whatever is needed
}
else
{
//No permission. Trying to normally request it
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status != PHAuthorizationStatusAuthorized)
{
//User don't give us permission. Showing alert with redirection to settings
//Getting description string from info.plist file
NSString *accessDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSPhotoLibraryUsageDescription"];
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:accessDescription message:#"To give permissions tap on 'Change Settings' button" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:cancelAction];
UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:#"Change Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}];
[alertController addAction:settingsAction];
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
}
}];
}
});
}
Also, there are some common cases when the alert doesn't appear. To avoid copying I would like you to take a look at this answer.
The first time the user tries to write to camera roll on ios 6 he/she is automatically asked for permission. You don't have to add extra code (before that the authorisationstatus is ALAuthorizationStatusNotDetermined ).
If the user denies the first time you cannot ask again (as far as I know). The user has to manually change that app specific setting in the settings->privacy-> photos section.
There is one other option and that is that it the user cannot give permission due other restrictions like parental control, in that case the status is ALAuthorizationStatusRestricted
Swift:
import AssetsLibrary
var status:ALAuthorizationStatus = ALAssetsLibrary.authorizationStatus()
if status != ALAuthorizationStatus.Authorized{
println("User has not given authorization for the camera roll")
}
#import <AssetsLibrary/AssetsLibrary.h>
//////
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusRestricted:
{
//Tell user access to the photos are restricted
}
break;
case ALAuthorizationStatusDenied:
{
// Tell user access has previously been denied
}
break;
case ALAuthorizationStatusNotDetermined:
case ALAuthorizationStatusAuthorized:
// Try to show image picker
myPicker = [[UIImagePickerController alloc] init];
myPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
myPicker.delegate = self;
[self presentViewController: myPicker animated:YES completion:NULL];
break;
default:
break;
}
iOS 9.2.1, Xcode 7.2.1, ARC enabled
'ALAuthorizationStatus' is deprecated: first deprecated in iOS 9.0 -
Use PHAuthorizationStatus in the Photos framework instead
Please see this post for an updated solution:
Determine if the access to photo library is set or not - PHPhotoLibrary (iOS 8)
Key notes:
Most likely you are designing for iOS7.0+ as of todays date, because of this fact you will need to handle both ALAuthorizationStatus and PHAuthorizationStatus.
The easiest is to do...
if ([PHPhotoLibrary class])
{
//Use the Photos framework
}
else
{
//Use the Asset Library framework
}
You will need to decide which media collection you want to use as your source, this is dictated by the device that your app. will run on and which version of OS it is using.
You might want to direct the user to settings if the authorization is denied by user.

Authenticating the local player - Game Center - iOS6

I'm completely new to development in Game Center. I have watched the videos in WWDC and looked at the developer website. They suggest I enter code like this for iOS 6:
- (void) authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil)
{
[self showAuthenticationDialogWhenReasonable: viewController
}
else if (localPlayer.isAuthenticated)
{
[self authenticatedPlayer: localPlayer];
}
else
{
[self disableGameCenter];
}
}];
}
I have copied this into the app delegate.m file, however it does not like it, showing errors like expecting a ] after [self showAuthenticationDialogWhenReasonable: viewController
} amongst others.
Can anyone please tell me how to authenticate the user for game center in iOS 6?
To get an introduction to GameKit, there are samples available from apple, for example:
https://developer.apple.com/library/ios/#samplecode/GKLeaderboards/Introduction/Intro.html.
In your code you are missing the closing "]", but of course you need more than just this function to connect to the gameCenter. Best start with one of the samples.
Apple has posted incorrect code, the ]; towards the end of the code belongs at the end of this line [self showAuthenticationDialogWhenReasonable: viewController
this code is not needed because this is just explaining how the method authenticateLocalPlayer works inside of Gamekit
Here's what I did without having to use the deprecated methods:
Set the authentication handler immediately in the AppDelegate by calling the function below (I put it in a singleton helper object). At this time, there is no view controller from which to show the login view controller, so if authentication fails, and the handler gives you a view controller, just save it away. This is the case when the user is not logged in.
- (void)authenticateLocalUserNoViewController {
NSLog(#"Trying to authenticate local user . . .");
GKLocalPlayer *_localPlayer = [GKLocalPlayer localPlayer];
__weak GKLocalPlayer *localPlayer = _localPlayer; // Avoid retain cycle inside block
__weak GCHelper *weakself = self;
self.authenticationViewController = nil;
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if (viewController) {
NSLog(#"User not logged in");
weakself.authenticationViewController = viewController; // save it away
} else if (localPlayer.authenticated) {
[[GKLocalPlayer localPlayer] unregisterListener:self];
[[GKLocalPlayer localPlayer] registerListener:self];
NSLog(#"Local player %# (%#) authenticated. ID = %#",localPlayer.alias, localPlayer.displayName, localPlayer.playerID);
} else {
// Probably user cancelled the login dialog
NSLog(#"Problem authenticating %#", [error localizedDescription]);
}
};
}
Then, once your main screen has loaded, and the user wants to press a button the start an online game, present the login view controller that you stashed away earlier. I put this in another method in my helper class. When the user logs in, it will trigger an execution of your original authentication block, but the viewcontroller parameter will be nil.
-(BOOL) showGameCenterLoginController:(UIViewController *)presentingViewController {
if (self.authenticationViewController) {
[presentingViewController presentViewController:self.authenticationViewController animated:YES completion:^{
}];
return YES;
} else {
NSLog(#"Can't show game center view controller!");
return NO; // Show some other error dialog like "Game Center not available"
}
}

Working with iOS Location Manager

I am developing an app that has many view. Into my app sometimes the user arrives to a view where he can ask for his position clicking over a button. I am trying to follow the Apple guide lines to only ask for the user position if the user allows to do it. What should I do, use the next first code into the app delegate and declare a location manager attribute into any view that the user invokes, passing the location manager attribute to the new view and from the old view and asking with the second next code anytime that the user clicks the button to locate himself?; or just use the second code, declaring a location manager attribute only into the views that allow to get the user location with a button, to check if the location services are enable?
First snippet.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
// Create a location manager instance to determine if location services are enabled. This manager instance will be
// immediately released afterwards.
CLLocationManager *manager = [[CLLocationManager alloc] init];
if (manager.locationServicesEnabled == NO) {
UIAlertView *servicesDisabledAlert = [[UIAlertView alloc] initWithTitle:#"Location Services Disabled" message:#"You currently have all location services for this device disabled. If you proceed, you will be asked to confirm whether location services should be reenabled." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[servicesDisabledAlert show];
[servicesDisabledAlert release];
}
[manager release];
return YES;
}
Second snippet.
- (IBAction)locateUser:(id)sender {
if([CLLocationManager locationServicesEnabled]) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
} else {
[[[[UIAlertView alloc] initWithTitle:#"Location services."
message:#"Location services are disabled."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] autorelease] show];
}
}
Thanks for reading.
CoreLocation will handle all the alerts for you. If locations services are disabled and that you ask for the location, CoreLocation will show an alert telling so to the user with a button to go directly to Settings.app.
If you want to know what append you can check for the delegate call
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
The error here contains a code that will be kCLErrorDenied if the user doesn't let the app use location services.
Also, you should use CoreLocation when the user need it. It's not necessary to check for location services at launch and the overhead of multiple CLLocationManager is almost inexistent.