写真ライブラリへのアクセスが設定されているかどうかを確認します-PHPhotoLibrary


101

iOS 8の新機能により、アプリでカメラを使用している場合、カメラへのアクセス許可が求められ、写真を撮り直すと、フォトライブラリへのアクセス許可が求められます。次回アプリを起動するときに、カメラとフォトライブラリにアクセス権限があるかどうかを確認したいと思います。

ここに画像の説明を入力してください

カメラについては、私はそれをチェックします

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

フォトライブラリ用にこれに似たものを探しています。

回答:


85

チェック+[PHPhotoLibrary authorizationStatus]–設定されていない場合は、が返されPHAuthorizationStatusNotDeterminedます。(その後+requestAuthorization:、同じクラスでを使用してアクセスを要求できます。)


PHPhotoLibraryを使用するには、ファウンデーションまたはライブラリを追加/インポートする必要がありますか?「宣言されていない識別子の使用」というエラーが表示される
tech_human 2014年

2
代わりに「ALAssetsLibrary」を使用して認証ステータスを確認しましたが、フォトライブラリがオフの場合でもYESが返されます。
tech_human 2014年

「ALAssetsLibrary」でステータスを取得できます。まだ骨董品はPHPhotoライブラリを使用することが可能かどうかを知っています。
tech_human 2014年

3
PHPhotoLibraryはPhotosフレームワークの一部で、iOS 8でのみ利用できます。古いバージョンのiOSのサポートが必要な場合は、ALAssetsLibraryがおそらく最善の策です。
Tim

iOS 9の時点では、ALAssetsLibraryは非推奨になっているので、それが機能しない理由だと思います。
Supertecnoboff

131

私はこれがすでに回答されていることを知っていますが、@ Timの回答を拡張するために、必要なコードを次に示します(iOS 8以降)。

PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];

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

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

else if (status == PHAuthorizationStatusNotDetermined) {

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

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

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

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

することを忘れないでください #import <Photos/Photos.h>

Swift 3.0以降を使用している場合は、次のコードを使用できます。

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

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

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

else if (status == PHAuthorizationStatus.notDetermined) {

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

        if (newStatus == PHAuthorizationStatus.authorized) {

        }

        else {

        }
    })
}

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

することを忘れないでください import Photos


5
なぜこれはiOS 9以降だけなのですか?写真フレームワークはiOS 8以降で利用可能です。
BalázsVincze

1
また、プロジェクトにPhotos Frameworkを追加することを忘れないでください->ターゲット->ビルドフェーズ
stellz

それは適切に機能しません。アクセスを拒否し、再度有効にしましたが、まだ決定されていません。
TomSawyer 2017

"//制限付きアクセス-通常は発生しません。" どうして?「ユーザーがこのアプリケーションのステータスを変更できません。アクティブな制限が原因である可能性があります」
NoKey

PHPhotoLibrary.requestAuthorizationは、許可を求めるダイアログを表示することを想定していますか?Cosがこの回線を右に呼び出しても何も
起こり

49

形式と同じように、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
スウィフト3に忘れないでくださいimport PhotosあなたはPHPhotoLibraryを使用したい場合は、
ronatory

27

iOS 8以降(ALAssetLibraryなし)の完全なガイドは次のとおりです。

まず、PHPhotoLibraryで必要とされるため、使用方法の説明を提供する必要があります。
これを行うinfo.plistには、ファイルを開き、キーPrivacy - Photo Library Usage Descriptionを見つけて、その値を提供する必要があります。キーが存在しない場合は、作成してください。
次に例を示します。
ここに画像の説明を入力してください またBundle nameinfo.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実際には、すべての通話でアラートが表示されるわけではありません。一定時間に1回表示され、ユーザーの回答を保存して、アラートを再度表示する代わりに毎回それを返します。しかし、これは私たちが必要とするものではないので、許可が必要になるたびに常にアラートを表示する便利なコードがあります(設定へのリダイレクトあり):

- (void)requestAuthorizationWithRedirectionToSettings {
    dispatch_async(dispatch_get_main_queue(), ^{
        PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
        if (status == PHAuthorizationStatusAuthorized)
        {
            //We have permission. Do whatever is needed
        }
        else
        {
            //No permission. Trying to normally request it
            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
                if (status != PHAuthorizationStatusAuthorized)
                {
                    //User don't give us permission. Showing alert with redirection to settings
                    //Getting description string from info.plist file
                    NSString *accessDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSPhotoLibraryUsageDescription"];
                    UIAlertController * alertController = [UIAlertController alertControllerWithTitle:accessDescription message:@"To give permissions tap on 'Change Settings' button" preferredStyle:UIAlertControllerStyleAlert];
                    
                    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
                    [alertController addAction:cancelAction];
                    
                    UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:@"Change Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
                    }];
                    [alertController addAction:settingsAction];
                    
                    [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
                }
            }];
        }
    });
}

一般的な問題1:一部のユーザーは、ファイルで上記の変更を行った後、アプリがアラートを表示しないと不平言いinfo.plistます。
解決策:テストの場合Bundle Identifierは、プロジェクトファイルから別のものに変更して、アプリをクリーンアップして再ビルドしてください。それが機能し始めたら、すべてが問題なく、名前を元に戻します。

よくある問題2:ドキュメントで約束されたとおりに実行しているときに、アプリが写真へのアクセス許可を取得すると、フェッチ結果が更新されない(そして、それらのフェッチリクエストからの画像を使用するビューが空のままである)場合があります。
実際、次のような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)
    {
        // ...
}

アプリの設定を権限にどのようにリンクしますか?
user2924482

20

私はそれをこのようにしました:

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

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

そして、成功または失敗に応じて、ブロックとして実行する必要があるものを送信します。


8

更新:SWIFT 3 IOS10


注:次のようにAppDelegate.swiftに写真をインポートします

// AppDelegate.swift

UIKitをインポートする

写真をインポート

...


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

}

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

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

    }
    else
    {
        alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
    }
}

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

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

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

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

回答をAlvin Georgeから更新しました


5

ALAssetsLibraryを使用すると機能します。

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

3
グレート答えが、これは、iOS 9に廃止されました
Supertecnoboff

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

これは、私が通常使用する小さくてシンプルなスニペットです。

- (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
不明な場合は、granted(YES)またはgranted(NO)を返さないようです。
シェード2015

上記のように+このブロックで「ハンドラー」を強くキャプチャすると、保持サイクルにつながる可能性があります
Ernest

0

Swift 2.0以降

ここでの回答の組み合わせに基づいて、私は自分のためのソリューションを作成しました。このメソッドは、権限がないかどうかを確認するだけです。

pickVideo()写真へのアクセスを必要とするメソッドを取得しました。.Authorized許可がない場合は許可を求めます。

許可が与えられていない場合、pickVideo()は呼び出されず、ユーザーはビデオを選択できません。

ユーザーが写真への完全なアクセス権を与えなかった限り、ユーザーにアプリケーションの「またはクラッシュ」を選択させないようにすることができます。

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

  func requestAuthorizationHandler(status: PHAuthorizationStatus){
    if PHPhotoLibrary.authorizationStatus() == .Authorized{
      // The user did authorize, so, pickVideo may be opened
      // Ensure pickVideo is called from the main thread to avoid GUI problems
      dispatch_async(dispatch_get_main_queue()) {
        pickVideo()
      }
    } else {
      // Show Message to give permission in Settings
      let alertController = UIAlertController(title: "Error", message: "Enable photo permissions in settings", preferredStyle: .Alert)
      let settingsAction = UIAlertAction(title: "Settings", style: .Default) { (alertAction) in
        if let appSettings = NSURL(string: UIApplicationOpenSettingsURLString) {
          UIApplication.sharedApplication().openURL(appSettings)
        }
      }
      alertController.addAction(settingsAction)
      // If user cancels, do nothing, next time Pick Video is called, they will be asked again to give permission
      let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
      alertController.addAction(cancelAction)
      // Run GUI stuff on main thread
        dispatch_async(dispatch_get_main_queue()) {      
          self.presentViewController(alertController, animated: true, completion: nil)
        }
      }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.