Xác định xem quyền truy cập vào thư viện ảnh đã được thiết lập hay chưa - PHPhotoLibrary


100

Với chức năng mới trong iOS 8, nếu bạn đang sử dụng máy ảnh trong ứng dụng, nó sẽ yêu cầu quyền truy cập vào máy ảnh và sau đó khi bạn cố gắng chụp lại ảnh, nó sẽ yêu cầu quyền truy cập thư viện ảnh. Lần tới khi khởi chạy ứng dụng, tôi muốn kiểm tra xem máy ảnh và thư viện ảnh có quyền truy cập vào ứng dụng đó hay không.

nhập mô tả hình ảnh ở đây

Đối với máy ảnh, tôi kiểm tra bằng cách

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

Tôi đang tìm kiếm thứ gì đó tương tự như thế này cho thư viện ảnh.

Câu trả lời:


85

Kiểm tra +[PHPhotoLibrary authorizationStatus]- nếu không được đặt, nó sẽ trở lại PHAuthorizationStatusNotDetermined. (Sau đó, bạn có thể yêu cầu quyền truy cập bằng cách sử dụng +requestAuthorization:trên cùng một lớp.)


Tôi có cần thêm / nhập bất kỳ nền tảng hoặc thư viện nào để sử dụng PHPhotoLibrary không? Tôi gặp lỗi "Sử dụng số nhận dạng không được khai báo"
tech_human

2
Thay vào đó, tôi đã thử sử dụng "ALAssetsLibrary" để kiểm tra trạng thái ủy quyền và điều đó trả về CÓ ngay cả khi thư viện ảnh tắt.
tech_human

Ồ, tôi có thể nhận được trạng thái bằng cách sử dụng "ALAssetsLibrary". Vẫn tò mò muốn biết liệu có thể sử dụng thư viện PHPhoto hay không.
tech_human

3
PHPhotoLibrary là một phần của khung Photos, chỉ khả dụng trên iOS 8. Nếu bạn cần hỗ trợ cho các phiên bản iOS cũ hơn, ALAssetsLibrary có lẽ là lựa chọn tốt nhất cho bạn.
Tim

Cũng như iOS 9, ALAssetsLibrary không được dùng nữa, vì vậy tôi đoán đó là lý do tại sao nó không hoạt động.
Supertecnoboff

131

Tôi biết điều này đã được trả lời, nhưng chỉ để mở rộng trên câu trả lời @Tim, đây là mã bạn cần (iOS 8 trở lên):

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

Đừng quên #import <Photos/Photos.h>

Nếu bạn đang sử dụng Swift 3.0 trở lên, bạn có thể sử dụng mã sau:

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

Đừng quên import Photos


5
Tại sao đây chỉ là iOS 9 trở lên? Hình ảnh khuôn khổ đã có sẵn từ iOS 8 ..
Balázs Vincze

1
Cũng đừng quên thêm Khung ảnh trong Dự án -> Mục tiêu -> Xây dựng giai đoạn
stellz

Nó không hoạt động bình thường, tôi đã từ chối quyền truy cập, sau đó bật lại, nó vẫn thông báo là không xác định.
TomSawyer

"// Quyền truy cập bị hạn chế - thông thường sẽ không xảy ra." Tại sao? Nó có thể xảy ra: "Người dùng không thể thay đổi trạng thái của ứng dụng này, có thể do các hạn chế hoạt động"
NoKey

PHPhotoLibrary.requestAuthorization có giả sử hiển thị hộp thoại yêu cầu quyền không? Vì gọi đúng dòng này không làm được gì
iori24

49

Cũng giống như hình thức, phiên bản 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
Trong Swift 3 đừng quên import Photos, nếu bạn muốn sử dụng PHPhotoLibrary
ronatory

27

Dưới đây là hướng dẫn đầy đủ cho iOS 8+ (không có ALAssetLibrary):

Đầu tiên, chúng tôi phải cung cấp mô tả sử dụng vì bây giờ nó được yêu cầu bởi PHPhotoLibrary.
Để làm điều này, chúng ta phải mở info.plisttệp, tìm khóa Privacy - Photo Library Usage Descriptionvà cung cấp giá trị cho nó. Nếu khóa không tồn tại thì chỉ cần tạo nó.
Đây là một hình ảnh ví dụ:
nhập mô tả hình ảnh ở đây Đồng thời đảm bảo rằng giá trị của khóa Bundle namekhông trống tronginfo.plist tệp.

Bây giờ khi chúng tôi có mô tả, thông thường chúng tôi có thể yêu cầu ủy quyền bằng requestAuthorizationphương thức gọi :

[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;
    }
}];

LƯU Ý 1: requestAuthorization thực tế không hiển thị cảnh báo trong mỗi cuộc gọi. Nó hiển thị một lần một lúc, lưu câu trả lời của người dùng và trả lại nó mọi lúc thay vì hiển thị lại cảnh báo. Nhưng vì nó không phải là thứ chúng ta cần, đây là một đoạn mã hữu ích luôn hiển thị cảnh báo mỗi khi chúng ta cần sự cho phép (với chuyển hướng đến cài đặt):

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

Sự cố thường gặp 1: Một số người dùng phàn nàn rằng ứng dụng không hiển thị cảnh báo sau khi thực hiện các thay đổi nêu trên trong info.plisttệp.
Giải pháp: Để thử nghiệm, hãy thử thay đổi Bundle Identifiertừ tệp dự án sang tệp khác, làm sạch và xây dựng lại ứng dụng. Nếu nó bắt đầu hoạt động thì mọi thứ vẫn ổn, hãy đổi tên nó trở lại.

Sự cố phổ biến 2: Có một số trường hợp cụ thể khi kết quả tìm nạp không được cập nhật (và các chế độ xem đã sử dụng hình ảnh từ các yêu cầu tìm nạp đó vẫn trống tương ứng) khi ứng dụng nhận được quyền đối với ảnh, trong khi chạy như đã hứa trong tài liệu.
Trên thực tế, nó xảy ra khi chúng ta sử dụng mã SAI như thế này:

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

Trong trường hợp này, nếu người dùng từ chối cấp quyền viewDidLoadsau đó chuyển đến cài đặt, được phép và quay lại ứng dụng, các lượt xem sẽ không được làm mới vì [self reloadCollectionView]và yêu cầu tìm nạp không được gửi.
Giải pháp: Chúng tôi chỉ cần gọi [self reloadCollectionView]và thực hiện các yêu cầu tìm nạp khác trước khi yêu cầu ủy quyền như sau:

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

Làm cách nào để bạn liên kết cài đặt của ứng dụng với quyền?
user2924482

20

Tôi đã làm nó như thế này:

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

Và tôi gửi những gì tôi cần làm dưới dạng khối tùy thuộc vào thành công hay thất bại.


8

CẬP NHẬT cho: SWIFT 3 IOS10


Lưu ý: nhập Ảnh trong AppDelegate.swift như sau

// AppDelegate.swift

nhập UIKit

nhập ảnh

...


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

Câu trả lời được cập nhật từ Alvin George


5

Sử dụng ALAssetsLibrary sẽ hoạt động:

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
Câu trả lời rất lớn nhưng điều này bị phản đối trong iOS 9.
Supertecnoboff

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

0

Đây là một đoạn mã nhỏ và đơn giản mà tôi thường sử dụng.

- (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
Nó dường như không trả lại được cấp (CÓ) hoặc cấp (KHÔNG) nếu nó không được xác định?
Shades

như trên + nắm bắt mạnh mẽ 'trình xử lý' trong khối này có khả năng dẫn đến chu kỳ giữ lại
Ernest

0

Swift 2.0+

Dựa trên sự kết hợp của các câu trả lời ở đây, tôi đã tạo ra một giải pháp cho chính mình. Phương pháp này chỉ kiểm tra nếu không có quyền.

Chúng tôi có một phương pháp pickVideo()yêu cầu quyền truy cập vào ảnh. Nếu nó không được .Authorizedxin phép.

Nếu quyền không được cấp, pickVideo()sẽ không được gọi và người dùng không thể chọn video.

Miễn là người dùng không cấp toàn quyền truy cập vào ảnh, bạn có thể tránh để họ chọn 'hoặc làm hỏng' ứng dụng của bạn.

  // 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)
        }
      }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.