Определите, установлен ли доступ к библиотеке фотографий или нет - PHPhotoLibrary


101

Благодаря новой функциональности в iOS 8, если вы используете камеру в приложении, она запросит разрешение на доступ к камере, а затем, когда вы попытаетесь повторно сделать снимок, запросит разрешение на доступ к библиотеке фотографий. В следующий раз, когда я запускаю приложение, я хочу проверить, есть ли у камеры и библиотеки фотографий права доступа к нему.

введите описание изображения здесь

Для камеры проверяю

if ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusDenied)
{
// do something
}

Я ищу нечто подобное для библиотеки фотографий.

Ответы:


85

Проверить +[PHPhotoLibrary authorizationStatus]- если не выставлен, вернется PHAuthorizationStatusNotDetermined. (Затем вы можете запросить доступ, используя +requestAuthorization:тот же класс.)


Нужно ли мне добавлять / импортировать какой-либо фундамент или библиотеку для использования PHPhotoLibrary? Я получаю сообщение об ошибке «Использование необъявленного идентификатора»
tech_human

2
Я попытался использовать ALAssetsLibrary вместо этого, чтобы проверить статус авторизации, и он вернул ДА, даже если библиотека фотографий отключена.
tech_human

О, я могу получить статус с помощью "ALAssetsLibrary". Все еще любопытно узнать, можно ли использовать библиотеку PHPhoto.
tech_human

3
PHPhotoLibrary является частью платформы Photos, которая доступна только в iOS 8. Если вам нужна поддержка более старых версий iOS, возможно, лучше всего подойдет ALAssetsLibrary.
Тим

Что касается iOS 9, ALAssetsLibrary устарела, поэтому я думаю, поэтому она не работает.
Supertecnoboff

131

Я знаю, что на это уже был дан ответ, но просто чтобы расширить ответ @Tim, вот код, который вам нужен (iOS 8 и выше):

PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];

if (status == PHAuthorizationStatusAuthorized) {
     // Access has been granted.
}

else if (status == PHAuthorizationStatusDenied) {
     // Access has been denied.
}

else if (status == PHAuthorizationStatusNotDetermined) {

     // Access has not been determined.
     [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {

         if (status == PHAuthorizationStatusAuthorized) {
             // Access has been granted.         
         }

         else {
             // Access has been denied.
         }
     }];  
}

else if (status == PHAuthorizationStatusRestricted) {
     // Restricted access - normally won't happen.
}

Не забывай #import <Photos/Photos.h>

Если вы используете Swift 3.0 или выше, вы можете использовать следующий код:

// Get the current authorization state.
let status = PHPhotoLibrary.authorizationStatus()

if (status == PHAuthorizationStatus.authorized) {
    // Access has been granted.
}

else if (status == PHAuthorizationStatus.denied) {
    // Access has been denied.
}

else if (status == PHAuthorizationStatus.notDetermined) {

    // Access has not been determined.
    PHPhotoLibrary.requestAuthorization({ (newStatus) in

        if (newStatus == PHAuthorizationStatus.authorized) {

        }

        else {

        }
    })
}

else if (status == PHAuthorizationStatus.restricted) {
    // Restricted access - normally won't happen.
}

Не забывай import Photos


5
Почему это только iOS 9 и выше? Фреймворк для фотографий доступен с iOS 8 ..
Балаж Винче,

1
Также не забудьте добавить структуру фотографий в Project -> Target -> Build Phases
stellz

Он не работает должным образом, я отказал в доступе, затем снова включил его, он все еще говорит, что не определен.
TomSawyer

«// Ограниченный доступ - обычно не бывает». Зачем? Это могло произойти: «Пользователь не может изменить статус этого приложения, возможно, из-за активных ограничений»
NoKey

предполагает ли PHPhotoLibrary.requestAuthorization показывать диалоговое окно с запросом разрешения? Потому что правый звонок по этой линии ничего не делает
iori24 06

50

В качестве формальности версия Swift 2.X :

    func checkPhotoLibraryPermission() {
       let status = PHPhotoLibrary.authorizationStatus()
       switch status {
       case .Authorized:
            //handle authorized status
       case .Denied, .Restricted :
            //handle denied status
       case .NotDetermined:
            // ask for permissions
            PHPhotoLibrary.requestAuthorization() { (status) -> Void in
               switch status {
               case .Authorized:
                   // as above
               case .Denied, .Restricted:
                   // as above
               case .NotDetermined:
                   // won't happen but still
               }
            }
        }
    }

И Swift 3 / Swift 4 :

    import Photos

    func checkPhotoLibraryPermission() {
        let status = PHPhotoLibrary.authorizationStatus()
        switch status {
        case .authorized: 
        //handle authorized status
        case .denied, .restricted : 
        //handle denied status
        case .notDetermined: 
            // ask for permissions
            PHPhotoLibrary.requestAuthorization { status in
                switch status {
                case .authorized: 
                // as above
                case .denied, .restricted: 
                // as above
                case .notDetermined: 
                // won't happen but still
                }
            }
        }
    }

6
В Swift 3 не забудьте import Photos, если вы хотите использовать PHPhotoLibrary
ronatory

27

Вот полное руководство для iOS 8+ (без ALAssetLibrary):

Во-первых, мы должны предоставить описание использования, поскольку теперь это требуется PHPhotoLibrary.
Для этого мы должны открыть info.plistфайл, найти ключ Privacy - Photo Library Usage Descriptionи указать для него значение. Если ключа не существует, просто создайте его.
Вот изображение, например:
введите описание изображения здесь Также убедитесь, что значение ключа Bundle nameне пусто в info.plistфайле.

Теперь, когда у нас есть описание, мы обычно можем запросить авторизацию, вызвав requestAuthorizationметод:

[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    switch (status) {
        case PHAuthorizationStatusAuthorized:
            NSLog(@"PHAuthorizationStatusAuthorized");
            break;
        case PHAuthorizationStatusDenied:
            NSLog(@"PHAuthorizationStatusDenied");
            break;
        case PHAuthorizationStatusNotDetermined:
            NSLog(@"PHAuthorizationStatusNotDetermined");
            break;
        case PHAuthorizationStatusRestricted:
            NSLog(@"PHAuthorizationStatusRestricted");
            break;
    }
}];

ПРИМЕЧАНИЕ 1: на requestAuthorization самом деле оповещение не отображается при каждом вызове. Он отображается один раз в какое-то время, сохраняет ответ пользователя и возвращает его каждый раз вместо того, чтобы снова показывать предупреждение. Но поскольку это не то, что нам нужно, вот полезный код, который всегда показывает предупреждение каждый раз, когда нам нужно разрешение (с перенаправлением на настройки):

- (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];
                }
            }];
        }
    });
}

Распространенная проблема 1. Некоторые пользователи жалуются, что приложение не отображает предупреждение после внесения вышеупомянутых изменений в info.plistфайл.
Решение: для тестирования попробуйте перейти Bundle Identifierс файла проекта на что-то другое, очистить и пересобрать приложение. Если заработало то все нормально, переименуйте обратно.

Распространенная проблема 2: существует конкретный случай, когда результаты выборки не обновляются (и представления, которые использовали изображения из этих запросов на выборку, по-прежнему пусты), когда приложение получает разрешения на фотографии во время работы, как было обещано в документации.
На самом деле это происходит, когда мы используем НЕПРАВИЛЬНЫЙ код, например:

- (void)viewDidLoad {
    if ([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusAuthorized)
    {
        //Reloading some view which needs photos
        [self reloadCollectionView];
        // ...
    } else {
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if (status == PHAuthorizationStatusAuthorized)
                [self reloadCollectionView];
            // ...
        }];
    }
    // ...
}

В этом случае, если пользователь отказался предоставлять разрешения, viewDidLoadзатем перешел к настройкам, разрешил и перешел обратно в приложение, представления не будут обновлены, потому что [self reloadCollectionView]запросы на выборку не были отправлены.
Решение: нам просто нужно позвонить [self reloadCollectionView]и выполнить другие запросы на выборку, прежде чем запрашивать авторизацию, например:

- (void)viewDidLoad {
    //Reloading some view which needs photos
    [self reloadCollectionView];
    if ([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusAuthorized)
    {
        // ...
}

Как связать настройки приложения с разрешениями?
user2924482

20

У меня так получилось:

- (void)requestPermissions:(GalleryPermissions)block
{
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];

    switch (status) 
    {
        case PHAuthorizationStatusAuthorized:
            block(YES);
            break;
        case PHAuthorizationStatusNotDetermined:
        {
            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus authorizationStatus)
            {
                if (authorizationStatus == PHAuthorizationStatusAuthorized)
                {
                    block(YES);
                }
                else
                {
                    block(NO);
                }
            }];
            break;
        }
        default:
            block(NO);
            break;
    }
}

И я отправляю то, что мне нужно сделать, как блок в зависимости от успеха или неудачи.


8

ОБНОВЛЕНИЕ для: SWIFT 3 IOS10


Примечание: импортируйте фотографии в AppDelegate.swift следующим образом

// AppDelegate.swift

импорт UIKit

импорт фотографий

...


func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    photoLibraryAvailabilityCheck()

}

//MARK:- PHOTO LIBRARY ACCESS CHECK
func photoLibraryAvailabilityCheck()
{
    if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized
    {

    }
    else
    {
        PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
    }
}
func requestAuthorizationHandler(status: PHAuthorizationStatus)
{
    if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized
    {

    }
    else
    {
        alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
    }
}

//MARK:- CAMERA & GALLERY NOT ALLOWING ACCESS - ALERT
func alertToEncourageCameraAccessWhenApplicationStarts()
{
    //Camera not available - Alert
    let internetUnavailableAlertController = UIAlertController (title: "Camera Unavailable", message: "Please check to see if it is disconnected or in use by another application", preferredStyle: .alert)

    let settingsAction = UIAlertAction(title: "Settings", style: .destructive) { (_) -> Void in
        let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
        if let url = settingsUrl {
            DispatchQueue.main.async {
                UIApplication.shared.open(url as URL, options: [:], completionHandler: nil) //(url as URL)
            }

        }
    }
    let cancelAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
    internetUnavailableAlertController .addAction(settingsAction)
    internetUnavailableAlertController .addAction(cancelAction)
    self.window?.rootViewController!.present(internetUnavailableAlertController , animated: true, completion: nil)
}
func alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
{
    //Photo Library not available - Alert
    let cameraUnavailableAlertController = UIAlertController (title: "Photo Library Unavailable", message: "Please check to see if device settings doesn't allow photo library access", preferredStyle: .alert)

    let settingsAction = UIAlertAction(title: "Settings", style: .destructive) { (_) -> Void in
        let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
        if let url = settingsUrl {
            UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
        }
    }
    let cancelAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
    cameraUnavailableAlertController .addAction(settingsAction)
    cameraUnavailableAlertController .addAction(cancelAction)
    self.window?.rootViewController!.present(cameraUnavailableAlertController , animated: true, completion: nil)
}

Ответ обновлен от Элвина Джорджа


5

Использование ALAssetsLibrary должно работать:

ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
    case ALAuthorizationStatusNotDetermined: {
        // not determined
        break;
    }
    case ALAuthorizationStatusRestricted: {
        // restricted
        break;
    }
    case ALAuthorizationStatusDenied: {
        // denied
        break;
    }
    case ALAuthorizationStatusAuthorized: {
        // authorized
        break;
    }
    default: {
        break;
    }
}

3
Отличный ответ, но это устарело в iOS 9.
Supertecnoboff

4
I have a simple solution on swift 2.0

//
//  AppDelegate.swift
//  HoneyBadger
//
//  Created by fingent on 14/08/15.
//  Copyright (c) 2015 fingent. All rights reserved.
//

import UIKit
import Photos

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        self.window?.makeKeyAndVisible()

             self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginPageID")
            self.window?.rootViewController = initialViewController
            self.window?.makeKeyAndVisible()
        return true
    }
    func applicationDidEnterBackground(application: UIApplication) {
        print("Application On background", terminator: "")
    }
    func applicationDidBecomeActive(application: UIApplication) {
        cameraAllowsAccessToApplicationCheck()
        photoLibraryAvailabilityCheck()
    }
    //MARK:- CAMERA ACCESS CHECK
    func cameraAllowsAccessToApplicationCheck()
    {
        let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
        switch authorizationStatus {
        case .NotDetermined:
            // permission dialog not yet presented, request authorization
            AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo,
                completionHandler: { (granted:Bool) -> Void in
                    if granted {
                        print("access granted", terminator: "")
                    }
                    else {
                        print("access denied", terminator: "")
                    }
            })
        case .Authorized:
            print("Access authorized", terminator: "")
        case .Denied, .Restricted:
            alertToEncourageCameraAccessWhenApplicationStarts()
        default:
            print("DO NOTHING", terminator: "")
        }
    }
    //MARK:- PHOTO LIBRARY ACCESS CHECK
    func photoLibraryAvailabilityCheck()
    {
        if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized
        {

        }
        else
        {
            PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
        }
    }
    func requestAuthorizationHandler(status: PHAuthorizationStatus)
    {
        if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized
        {

        }
        else
        {
            alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
        }
    }

    //MARK:- CAMERA & GALLERY NOT ALLOWING ACCESS - ALERT
    func alertToEncourageCameraAccessWhenApplicationStarts()
    {
        //Camera not available - Alert
        let internetUnavailableAlertController = UIAlertController (title: "Camera Unavailable", message: "Please check to see if it is disconnected or in use by another application", preferredStyle: .Alert)

        let settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
            let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
            if let url = settingsUrl {
                dispatch_async(dispatch_get_main_queue()) {
                    UIApplication.sharedApplication().openURL(url)
                }

            }
        }
        let cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
        internetUnavailableAlertController .addAction(settingsAction)
        internetUnavailableAlertController .addAction(cancelAction)
        self.window?.rootViewController!.presentViewController(internetUnavailableAlertController , animated: true, completion: nil)
    }
    func alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
    {
//Photo Library not available - Alert
        let cameraUnavailableAlertController = UIAlertController (title: "Photo Library Unavailable", message: "Please check to see if device settings doesn't allow photo library access", preferredStyle: .Alert)

        let settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
            let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
            if let url = settingsUrl {
                UIApplication.sharedApplication().openURL(url)
            }
        }
        let cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
        cameraUnavailableAlertController .addAction(settingsAction)
        cameraUnavailableAlertController .addAction(cancelAction)
        self.window?.rootViewController!.presentViewController(cameraUnavailableAlertController , animated: true, completion: nil)
    }
}

1

iOS 14 и более поздние версии Apple добавила новую функцию, которая предоставит ограниченный доступ к библиотеке фотографий. В зависимости от ваших требований (пример создания настраиваемой фотогалереи) вы должны проверить, предоставил ли пользователь только ограниченный доступ и хочет ли предоставить полный доступ.

Для обратной совместимости старые версии без параметра возвращают .authorized даже при ограниченном доступе.

Swift 5 :

switch PHPhotoLibrary.authorizationStatus(for: .readWrite) {
case .notDetermined:
    // ask for access
case .restricted, .denied:
    // sorry
case .authorized:
    // we have full access
 
// new option: 
case .limited:
    // we only got access to some photos of library
}

Есть код для повторного вызова экрана ограниченного доступа. если пользователь предоставил только .ограниченный доступ, и вы хотите, чтобы пользователь снова выбирал изображения.

PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: presentVCObj)

При каждом перезапуске приложения iOS будет показывать предупреждение, чтобы уведомить пользователя об ограниченном доступе. Если вы хотите остановить это предупреждение, добавьте PHPhotoLibraryPreventAutomaticLimitedAccessAlertДА в Info.plist


0

Вот небольшой и простой фрагмент, который я обычно использую.

- (void)requestPhotoAuthorization:(void (^)(BOOL granted))granted
{
    void (^handler)(PHAuthorizationStatus) = ^(PHAuthorizationStatus status)
    {
        if (status == PHAuthorizationStatusAuthorized) granted(YES);
        else if (status == PHAuthorizationStatusNotDetermined) [PHPhotoLibrary requestAuthorization:handler];
        else granted(NO);
    };
    handler([PHPhotoLibrary authorizationStatus]);
}

2
Кажется, что он не возвращает предоставленный (ДА) или предоставленный (НЕТ), если он не определен?
Shades

как указано выше + сильный захват «обработчика» в этом блоке, вероятно, приведет к циклу сохранения
Эрнест

0

Swift 2.0+

Основываясь на комбинации ответов здесь, я создал решение для себя. Этот метод проверяет только отсутствие разрешения.

У нас есть метод pickVideo(), требующий доступа к фотографиям. Если это не так.Authorized спросите разрешения.

Если разрешение не дано, pickVideo() он не будет вызываться, и пользователь не сможет выбрать видео.

Пока пользователь не предоставил полный доступ к фотографиям, вы можете не позволять ему выбирать или «вылетать» ваше приложение.

  // Method that requires access to photos
  func pickVideo(){
    // Check for permission
    if PHPhotoLibrary.authorizationStatus() != .Authorized{
      // If there is no permission for photos, ask for it
      PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
      return
    }
    //... pick video code here...
  }

  func requestAuthorizationHandler(status: PHAuthorizationStatus){
    if PHPhotoLibrary.authorizationStatus() == .Authorized{
      // The user did authorize, so, pickVideo may be opened
      // Ensure pickVideo is called from the main thread to avoid GUI problems
      dispatch_async(dispatch_get_main_queue()) {
        pickVideo()
      }
    } else {
      // Show Message to give permission in Settings
      let alertController = UIAlertController(title: "Error", message: "Enable photo permissions in settings", preferredStyle: .Alert)
      let settingsAction = UIAlertAction(title: "Settings", style: .Default) { (alertAction) in
        if let appSettings = NSURL(string: UIApplicationOpenSettingsURLString) {
          UIApplication.sharedApplication().openURL(appSettings)
        }
      }
      alertController.addAction(settingsAction)
      // If user cancels, do nothing, next time Pick Video is called, they will be asked again to give permission
      let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
      alertController.addAction(cancelAction)
      // Run GUI stuff on main thread
        dispatch_async(dispatch_get_main_queue()) {      
          self.presentViewController(alertController, animated: true, completion: nil)
        }
      }
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.