Sprawdź, czy dostęp do biblioteki zdjęć jest ustawiony, czy nie - PHPhotoLibrary

101

Dzięki nowej funkcji w iOS 8, jeśli używasz aparatu w aplikacji, zapyta o pozwolenie na dostęp do aparatu, a następnie, gdy spróbujesz ponownie zrobić zdjęcie, prosi o pozwolenie na dostęp do biblioteki zdjęć. Następnym razem, gdy uruchomię aplikację, chcę sprawdzić, czy aparat i biblioteka zdjęć mają do niej dostęp.

wprowadź opis obrazu tutaj

W przypadku aparatu sprawdzam to

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

Szukam czegoś podobnego do biblioteki zdjęć.

tech_human
źródło

Odpowiedzi:

85

Sprawdź +[PHPhotoLibrary authorizationStatus]- jeśli nie ustawione, zwróci PHAuthorizationStatusNotDetermined. (Następnie możesz poprosić o dostęp, używając +requestAuthorization:tej samej klasy).

Tim
źródło
Czy muszę dodać / zaimportować jakąkolwiek fundację lub bibliotekę, aby używać PHPhotoLibrary? Otrzymuję błąd „Użycie niezadeklarowanego identyfikatora”
tech_human,
2
Zamiast tego próbowałem użyć „ALAssetsLibrary”, aby sprawdzić status autoryzacji, a ta zwraca TAK, nawet jeśli biblioteka zdjęć jest wyłączona.
tech_human
Och, jestem w stanie uzyskać status za pomocą „ALAssetsLibrary”. Jeszcze ciekawostki, aby wiedzieć, czy można korzystać z biblioteki PHPhoto.
tech_human
3
PHPhotoLibrary jest częścią struktury Zdjęcia, która jest dostępna tylko w systemie iOS 8. Jeśli potrzebujesz obsługi starszych wersji iOS, prawdopodobnie najlepszym rozwiązaniem będzie ALAssetsLibrary.
Tim
Podobnie jak w iOS 9, ALAssetsLibrary jest przestarzałe, więc myślę, że dlatego nie działa.
Supertecnoboff
131

Wiem, że już na to odpowiedziano, ale aby rozwinąć odpowiedź @Tim, oto kod, którego potrzebujesz (iOS 8 i nowsze):

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

Nie zapomnij #import <Photos/Photos.h>

Jeśli używasz Swift 3.0 lub nowszego, możesz użyć następującego kodu:

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

Nie zapomnij import Photos

Supertecnoboff
źródło
5
Dlaczego to tylko iOS 9 i nowszy? Framework zdjęć jest dostępny od iOS 8 ..
Balázs Vincze
1
Nie zapomnij również dodać ramy zdjęć w projekcie -> Cel -> Fazy kompilacji
stellz
Nie działa poprawnie, odmówiłem dostępu, a następnie włączam go ponownie, nadal mówi, że nie określono.
TomSawyer
„// Ograniczony dostęp - normalnie się nie wydarzy”. Czemu? Może się zdarzyć: „Użytkownik nie może zmienić stanu tej aplikacji, prawdopodobnie z powodu aktywnych ograniczeń”
NoKey
czy PHPhotoLibrary.requestAuthorization ma pokazywać okno dialogowe z pytaniem o pozwolenie? Bo prawidłowe wywołanie tej linii nic nie daje
iori24
49

Podobnie jak formalność, wersja 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
               }
            }
        }
    }

Oraz 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
                }
            }
        }
    }
Krodak
źródło
6
W Swift 3 nie zapomnij o tym import Photos, jeśli chcesz używać PHPhotoLibrary
ronatory
27

Oto kompletny przewodnik dla iOS 8+ (bez ALAssetLibrary):

Najpierw musimy podać opis użycia, ponieważ teraz jest to wymagane przez PHPhotoLibrary.
Aby to zrobić, musimy otworzyć info.plistplik, znaleźć klucz Privacy - Photo Library Usage Descriptioni podać mu wartość. Jeśli klucz nie istnieje, po prostu go utwórz.
Oto przykładowy obraz:
wprowadź opis obrazu tutaj Upewnij się również, że wartość klucza Bundle namenie jest pusta winfo.plist pliku.

Teraz, gdy mamy opis, możemy normalnie zażądać autoryzacji przez wywołanie requestAuthorizationmetody:

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

UWAGA 1: w requestAuthorization rzeczywistości nie wyświetla powiadomienia przy każdym połączeniu. Pokazuje się raz na jakiś czas, zapisuje odpowiedź użytkownika i zwraca ją za każdym razem, zamiast ponownie pokazywać alert. Ale ponieważ to nie jest to, czego potrzebujemy, oto przydatny kod, który zawsze wyświetla alert za każdym razem, gdy potrzebujemy pozwolenia (z przekierowaniem do ustawień):

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

Typowy problem 1: Niektórzy użytkownicy narzekają, że aplikacja nie wyświetla ostrzeżenia po wprowadzeniu wyżej wymienionych zmian w info.plistpliku.
Rozwiązanie: W celu przetestowania spróbuj zmienić Bundle Identifierplik projektu na inny, wyczyść i przebuduj aplikację. Jeśli zaczął działać, wszystko jest w porządku, zmień nazwę z powrotem.

Typowy problem 2: Jest pewien szczególny przypadek, gdy wyniki pobierania nie są aktualizowane (a widoki, które korzystały z obrazów z tych żądań pobierania, nadal są odpowiednio puste), gdy aplikacja uzyskuje uprawnienia do zdjęć, działając zgodnie z obietnicą w dokumentacji.
Właściwie to się dzieje, gdy używamy ZŁEGO kodu w ten sposób:

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

W takim przypadku, jeśli użytkownik odmówił przyznania uprawnień, viewDidLoada następnie przeskoczył do ustawień, zezwolił i wrócił do aplikacji, widoki nie zostaną odświeżone, ponieważ [self reloadCollectionView]i żądania pobierania nie zostały wysłane.
Rozwiązanie: musimy tylko zadzwonić [self reloadCollectionView]i wykonać inne żądania pobierania, zanim zażądamy autoryzacji w następujący sposób:

- (void)viewDidLoad {
    //Reloading some view which needs photos
    [self reloadCollectionView];
    if ([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusAuthorized)
    {
        // ...
}
Just Shadow
źródło
Jak połączyć ustawienia aplikacji z uprawnieniami?
user2924482
20

Zrobiłem to tak:

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

I wysyłam to, co muszę zrobić jako blok w zależności od sukcesu lub porażki.

Odcienie
źródło
8

AKTUALIZACJA dla: SWIFT 3 IOS10


Uwaga: importuj zdjęcia w AppDelegate.swift w następujący sposób

// AppDelegate.swift

import UIKit

importować zdjęcia

...


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

Odpowiedź zaktualizowana przez Alvin George

MLBDG
źródło
5

Używanie ALAssetsLibrary powinno działać:

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;
    }
}
Richy
źródło
3
Świetna odpowiedź, ale jest to przestarzałe w 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)
    }
}
AG
źródło
0

Oto mały i prosty fragment, którego zwykle używam.

- (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]);
}
Camo
źródło
2
Wydaje się, że nie zwraca się przyznano (TAK) lub przyznano (NIE), jeśli jest nieokreślone?
Shades
jak wyżej + mocne złapanie `` przewodnika '' w tym bloku prawdopodobnie doprowadzi do cyklu utrzymania
Ernest
0

Swift 2.0+

Na podstawie kombinacji odpowiedzi tutaj stworzyłem rozwiązanie dla siebie. Ta metoda sprawdza tylko, czy nie ma pozwolenia.

Mamy metodę, pickVideo()która wymaga dostępu do zdjęć. Jeśli nie, .Authorizedpoproś o pozwolenie.

Jeśli pozwolenie nie zostanie udzielone, pickVideo()nie zostanie wywołane, a użytkownik nie może wybrać wideo.

Dopóki użytkownik nie zapewnił pełnego dostępu do zdjęć, możesz uniknąć wybierania „lub zawieszania się” aplikacji.

  // 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)
        }
      }
    }
Gerrit Post
źródło