Tentukan apakah akses ke perpustakaan foto disetel atau tidak - PHPhotoLibrary

101

Dengan fungsionalitas baru di iOS 8, jika Anda menggunakan kamera di aplikasi, itu akan meminta izin untuk mengakses kamera dan kemudian ketika Anda mencoba untuk mengambil kembali foto, itu meminta izin untuk mengakses perpustakaan foto. Lain kali ketika saya meluncurkan aplikasi, saya ingin memeriksa apakah kamera dan perpustakaan foto memiliki izin akses ke sana.

masukkan deskripsi gambar di sini

Untuk kamera, saya memeriksanya

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

Saya mencari sesuatu yang mirip dengan ini untuk perpustakaan foto.

tech_human
sumber

Jawaban:

85

Periksa +[PHPhotoLibrary authorizationStatus]- jika tidak disetel, itu akan kembali PHAuthorizationStatusNotDetermined. (Anda kemudian dapat meminta akses menggunakan +requestAuthorization:di kelas yang sama.)

Tim
sumber
Apakah saya perlu menambahkan / mengimpor foundation atau library apa pun untuk menggunakan PHPhotoLibrary? Saya mendapatkan pesan kesalahan "Use of undeclared identifier"
tech_human
2
Saya mencoba menggunakan "ALAssetsLibrary" sebagai gantinya untuk memeriksa status otorisasi dan yang mengembalikan YA meskipun perpustakaan foto tidak aktif.
tech_human
Oh saya bisa mendapatkan status menggunakan "ALAssetsLibrary". Masih penasaran untuk mengetahui apakah mungkin menggunakan library PHPhoto.
tech_human
3
PHPhotoLibrary adalah bagian dari framework Foto, yang hanya tersedia di iOS 8. Jika Anda memerlukan dukungan untuk versi iOS yang lebih lama, ALAssetsLibrary mungkin adalah pilihan terbaik Anda.
Tim
Nah pada iOS 9, ALAssetsLibrary tidak digunakan lagi, jadi saya rasa itu sebabnya ini tidak berfungsi.
Supertecnoboff
131

Saya tahu ini sudah dijawab, tetapi hanya untuk memperluas jawaban @Tim, berikut adalah kode yang Anda butuhkan (iOS 8 ke atas):

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

Jangan lupa #import <Photos/Photos.h>

Jika Anda menggunakan Swift 3.0 atau lebih tinggi, Anda dapat menggunakan kode berikut:

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

Jangan lupa import Photos

Supertecnoboff
sumber
5
Mengapa ini hanya iOS 9 ke atas? Kerangka foto telah tersedia sejak iOS 8 ..
Balázs Vincze
1
Juga jangan lupa untuk menambahkan Kerangka Foto di Proyek -> Target -> Fase Bangun
stellz
Itu tidak berfungsi dengan benar, saya menolak akses lalu mengaktifkannya lagi, masih dikatakan tidak ditentukan.
TomSawyer
"// Akses terbatas - biasanya tidak akan terjadi." Mengapa? Itu bisa terjadi: "Pengguna tidak dapat mengubah status aplikasi ini, mungkin karena pembatasan aktif"
NoKey
apakah PHPhotoLibrary.requestAuthorization seharusnya menampilkan dialog yang meminta izin? Karena panggilan yang benar ke jalur ini tidak melakukan apa
iori24
49

Sama seperti formalitas, versi 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
               }
            }
        }
    }

Dan 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
sumber
6
Di Swift 3 jangan lupa import Photos, jika Anda ingin menggunakan PHPhotoLibrary
ronatory
27

Berikut adalah panduan lengkap untuk iOS 8+ (tanpa ALAssetLibrary):

Pertama kita harus memberikan deskripsi penggunaan seperti yang sekarang dibutuhkan oleh PHPhotoLibrary.
Untuk melakukan ini kita harus membuka info.plistfile, menemukan kunci Privacy - Photo Library Usage Descriptiondan memberikan nilainya. Jika kunci tidak ada, buat saja.
Berikut adalah gambarnya misalnya:
masukkan deskripsi gambar di sini Pastikan juga bahwa nilai key Bundle nametidak kosonginfo.plist file.

Sekarang ketika kami memiliki deskripsi, kami biasanya dapat meminta otorisasi dengan memanggil requestAuthorizationmetode:

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

CATATAN 1: requestAuthorization sebenarnya tidak menunjukkan peringatan pada setiap panggilan. Ini ditampilkan sekali per beberapa waktu, menyimpan jawaban pengguna dan mengembalikannya setiap kali alih-alih menampilkan peringatan lagi. Tetapi karena bukan itu yang kita butuhkan, berikut adalah kode berguna yang selalu menunjukkan peringatan setiap kali kita membutuhkan izin (dengan pengalihan ke pengaturan):

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

Masalah umum 1: Beberapa pengguna mengeluh bahwa aplikasi tidak menunjukkan peringatan setelah melakukan perubahan info.plistfile yang disebutkan di atas .
Solusi: Untuk pengujian, coba ubah Bundle Identifierdari file proyek ke yang lain, bersihkan dan bangun kembali aplikasi. Jika mulai berfungsi maka semuanya baik-baik saja, ganti namanya kembali.

Masalah Umum 2: Ada beberapa kasus khusus ketika hasil pengambilan tidak diperbarui (dan tampilan yang menggunakan gambar dari permintaan pengambilan tersebut masih kosong) saat aplikasi mendapat izin untuk foto, saat berjalan seperti yang dijanjikan dalam dokumentasi.
Sebenarnya itu terjadi ketika kita menggunakan kode SALAH seperti ini:

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

Dalam kasus ini, jika pengguna menolak memberikan izin viewDidLoadkemudian melompat ke pengaturan, diizinkan dan kembali ke aplikasi, tampilan tidak akan disegarkan karena [self reloadCollectionView]dan permintaan pengambilan tidak dikirim.
Solusi: Kami hanya perlu menelepon [self reloadCollectionView]dan melakukan permintaan pengambilan lainnya sebelum memerlukan otorisasi seperti ini:

- (void)viewDidLoad {
    //Reloading some view which needs photos
    [self reloadCollectionView];
    if ([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusAuthorized)
    {
        // ...
}
Hanya Bayangan
sumber
Bagaimana Anda menghubungkan pengaturan aplikasi ke izin?
pengguna2924482
20

Saya melakukannya seperti ini:

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

Dan saya mengirimkan apa yang perlu saya lakukan sebagai blok tergantung pada keberhasilan atau kegagalan.

Shades
sumber
8

UPDATE untuk: SWIFT 3 IOS10


Catatan: impor Foto di AppDelegate.swift sebagai berikut

// AppDelegate.swift

impor UIKit

impor Foto

...


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

Jawaban diperbarui dari Alvin George

MLBDG
sumber
5

Menggunakan ALAssetsLibrary seharusnya berfungsi:

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;
    }
}
kaya
sumber
3
Jawaban yang bagus tapi ini tidak digunakan lagi di 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
sumber
0

Berikut ini potongan kecil dan sederhana yang biasa saya gunakan.

- (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
sumber
2
Tampaknya tidak kembali diberikan (YA) atau diberikan (TIDAK) jika tidak ditentukan?
Shades
seperti di atas + menangkap 'penangan' dengan kuat di blok ini kemungkinan besar akan mengarah ke siklus
penahanan
0

Swift 2.0+

Berdasarkan kombinasi jawaban di sini, saya telah membuat solusi untuk diri saya sendiri. Metode ini hanya memeriksa jika tidak ada izin.

Kami mendapat metode pickVideo()yang membutuhkan akses ke foto. Jika tidak.Authorized minta izin.

Jika izin tidak diberikan, pickVideo() tidak akan dipanggil, dan pengguna tidak dapat memilih video.

Selama pengguna tidak memberikan akses penuh ke foto, Anda dapat menghindari untuk membiarkan mereka memilih 'atau merusak' aplikasi Anda.

  // 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
sumber