【问题标题】:Determine if the access to photo library is set or not - PHPhotoLibrary确定是否设置了对照片库的访问权限 - PHPhotoLibrary
【发布时间】:2014-12-23 02:10:57
【问题描述】:

使用 iOS 8 中的新功能,如果您在应用程序中使用相机,它会请求访问相机的权限,然后当您尝试重新拍摄照片时,它会请求访问照片库的权限。下次我启动应用程序时,我希望检查相机和照片库是否具有访问权限。

对于相机,我检查它通过

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

我正在为照片库寻找类似的东西。

【问题讨论】:

    标签: ios ios8 phphotolibrary


    【解决方案1】:

    这里是 iOS 8+ 的完整指南(没有 ALAssetLibrary):

    首先,我们必须提供usage description,因为现在它是 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];
                    }
                }];
            }
        });
    }
    

    常见问题一: 部分用户complain 表示在info.plist 文件中进行上述更改后,应用程序没有显示警报。
    解决方案:为了测试尝试将Bundle Identifier 从项目文件更改为其他内容,清理并重建应用程序。如果它开始工作,那么一切都很好,将其重命名。

    常见问题 2: 当应用程序获得照片权限时,当获取结果未更新(并且使用这些获取请求中的图像的视图仍然为空)时,存在一些特定情况,按照文档中的承诺在运行时
    实际上,当我们像这样使用 WRONG 代码时会发生这种情况:

    - (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)
        {
            // ...
    }
    

    【讨论】:

    • 如何将应用的设置链接到权限?
    【解决方案2】:

    iOS 14 及更高版本 Apple 添加了一项新功能,可限制对照片库的访问。根据您的要求(例如创建自定义照片库),您必须检查用户是否仅授予有限访问权限并希望授予完全访问权限。

    为了向后兼容,即使您获得有限访问权限,不带参数的旧版本也会返回 .authorized。

    斯威夫特 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
    }
    

    有一个代码可以再次调用受限访问屏幕。如果用户仅授予 .limited 访问权限,并且您希望用户再次选择图像。

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

    在应用程序每次重新启动时,iOS 都会显示警报以通知用户访问受限。如果您想停止该警报,请添加 PHPhotoLibraryPreventAutomaticLimitedAccessAlertInfo.plist

    中为“是”

    【讨论】:

    • 此解决方案不起作用 PHPhotoLibraryPreventAutomaticLimitedAccessAlert 设置为 YES。在 info.plist 中添加此键后是否需要进行其他设置?
    【解决方案3】:

    和形式一样,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
                    }
                }
            }
        }
    

    【讨论】:

    • Swift 3 中,如果你想使用 PHPhotoLibrary,别忘了import Photos
    【解决方案4】:

    我知道这已经得到解答,但只是为了扩展@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

    【讨论】:

    • 为什么只有iOS 9及以上?照片框架从 iOS 8 开始就可用了。..
    • 另外别忘了在Project -> Target -> Build Phases中添加Photos Framework
    • 它不能正常工作,我拒绝访问然后再次启用它,它仍然说未确定。
    • ""// 受限访问 - 通常不会发生。"为什么?可能会发生:“用户无法更改此应用程序的状态,可能是由于活动限制”
    • PHPhotoLibrary.requestAuthorization 是否假设显示一个请求许可的对话框?因为右调用这条线没有任何作用
    【解决方案5】:

    更新:SWIFT 3 IOS10


    注意:在 AppDelegate.swift 中导入 Photos 如下

    // 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)
    }
    

    答案更新自Alvin George

    【讨论】:

      【解决方案6】:

      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)
              }
            }
          }
      

      【讨论】:

        【解决方案7】:
        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)
            }
        }
        

        【讨论】:

          【解决方案8】:

          我是这样做的:

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

          我会根据成功或失败将我需要做的事情作为块发送。

          【讨论】:

            【解决方案9】:

            这里是我常用的一个小而简单的sn-p。

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

            【讨论】:

            • 如果未确定,它似乎不会返回granted(YES) 或granted(NO)?
            • 如上 + 在此块中强烈捕获“处理程序”可能会导致保留周期
            【解决方案10】:

            使用 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;
                }
            }
            

            【讨论】:

            • 很好的答案,但在 iOS 9 中已弃用。
            【解决方案11】:

            检查+[PHPhotoLibrary authorizationStatus] - 如果未设置,它将返回PHAuthorizationStatusNotDetermined。 (然后您可以在同一个班级使用+requestAuthorization: 请求访问权限。)

            【讨论】:

            • 我是否需要添加/导入任何基础或库才能使用 PHPhotoLibrary?我收到一个错误“使用未声明的标识符”
            • 我尝试使用“ALAssetsLibrary”来检查授权状态,即使照片库已关闭,它也会返回 YES。
            • 哦,我可以使用“ALAssetsLibrary”获取状态。仍然很想知道是否可以使用 PHPhoto 库。
            • PHPhotoLibrary 是 Photos 框架的一部分,仅在 iOS 8 上可用。如果您需要对旧版本 iOS 的支持,ALAssetsLibrary 可能是您的最佳选择。
            • 从 iOS 9 开始,ALAssetsLibrary 已被弃用,所以我猜这就是它不起作用的原因。
            猜你喜欢
            • 1970-01-01
            • 2019-04-17
            • 1970-01-01
            • 1970-01-01
            • 2016-01-26
            • 1970-01-01
            • 1970-01-01
            • 2011-04-16
            • 1970-01-01
            相关资源
            最近更新 更多