61

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.

rptwsthi
  • 10,094
  • 10
  • 68
  • 109
Titouan de Bailleul
  • 12,920
  • 11
  • 66
  • 121

7 Answers7

96

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];
}
Leandros
  • 16,805
  • 9
  • 69
  • 108
Mick MacCallum
  • 129,200
  • 40
  • 280
  • 281
  • 2
    Nice. Thanks for the error.code I had put an alert directly in the failureBlock. – Titouan de Bailleul Nov 26 '12 at 20:44
  • Seems silly that you can't request to get authorisation. I find it sometimes really ugly to just request access to the photos, as you are presenting the picker... – Chris Jun 03 '15 at 10:52
  • This is Deprecated. I was facing a similar issue. Figured it out with this link. http://stackoverflow.com/questions/39519773/nsphotolibraryusagedescription-key-must-be-present-in-info-plist-to-use-camera-r – Pradeep Reddy Kypa Mar 29 '17 at 07:27
  • Here is a solution for iOS 10 and above: http://stackoverflow.com/questions/13572220/ask-permission-to-access-camera-roll/38398067#38398067 – Just Shadow May 06 '17 at 11:59
91

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.

Capella
  • 881
  • 3
  • 19
  • 32
Tomasz Bąk
  • 6,124
  • 3
  • 34
  • 48
  • 9
    For some 'I didn't read the documentation' reason, the code is ran on the background thread. So wrap it in something like this if you need ui changes: `dispatch_async(dispatch_get_main_queue(), ^{ -- ui touching code here -- });` – Alexandre G Mar 06 '15 at 01:13
  • Awesome! Don't forget to add the Photos framework to your target, and add `import Photos` at the top of your Swift class :) – judepereira Jul 10 '16 at 17:28
  • 4
    Note that in iOS 10 and later you also need to have a string for the [NSPhotoLibraryUsageDescription](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW17) key in your Info.plist, or your call to `requestAuthorization` (or to any API dependent on Photos authorization) will crash. – rickster Nov 02 '16 at 19:57
11

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.

Just Shadow
  • 10,860
  • 6
  • 57
  • 75
4

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

  • There's the built-in iOS popover thing that lets you pick images -- for that I see the dialog. When you take the ALAssets route, I don't see the dialog. – Amir Memon Aug 20 '13 at 01:06
4

Swift:

import AssetsLibrary

var status:ALAuthorizationStatus = ALAssetsLibrary.authorizationStatus()

if status != ALAuthorizationStatus.Authorized{
    println("User has not given authorization for the camera roll")
}
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
2
#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;
    }
Dan Atherton
  • 161
  • 6
0

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.

Community
  • 1
  • 1
serge-k
  • 3,394
  • 2
  • 24
  • 55