PhotoKit

https://developer.apple.com/documentation/photokit

사용자가 앱이 접근할 수 있는 사진을 지정할 수 있게 되는 것이 포인트다
-> limited photo library라고 부른다

import PhotoKit

이렇게 해보려고 했더니 모듈이 없다고 나온다^^
UIKit는 되잖아요ㅠㅠ

프레임워크로 아래와 같은 것을 포함하고 있으니

  • Photos
  • PhotosUI
import Photos

이렇게 import 해줬다


https://developer.apple.com/documentation/photokit/delivering_an_enhanced_privacy_experience_in_your_photos_app

Delivering an Enhanced Privacy Experience in Your Photos App

💡 iOS 14에서 PhotoKit을 사용하면 limited Photos library는 모든 앱에 영향을 끼친다. 잘 작동하는지 확인해봐야 한다.

Determine Your App’s Access Needs

iOS14에서 Photos library에 read-only 목적으로 접근한다면 PHPickerViewController를 사용하면 UX를 강화할 수 있다.

Session 10652: Meet the New Photos Picker
https://developer.apple.com/videos/play/wwdc2020/10652/

Describe Your Appʼs Photo Library Use

Info.plist파일에
앱에서 라이브러리를 추가만 하려면 NSPhotoLibraryAddUsageDescription를 추가해주고
read/write 하려면
NSPhotoLibraryUsageDescription를 추가해준다


Privacy - Photo Library Usage Description

Determine and Request Authorization

PHPhotoLibrary를 사용해 사용자가 승인한 권한의 종류를 알 수 있다

// 앱 권한 상태 체크 (either read/write or add-only access).
let readWriteStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)

시스템에서 앱이 실행되면 자동으로 권한을 비동기적으로 물어보는데
plist에서 그렇지 않게 설정을 한 뒤
사용자의 액션에 따라서 권한을 요구하도록 할 수도 있다

Prevent limited photos access alert
1

// Request read-write access to the user's photo library.
PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
    switch status {
    case .notDetermined:
        // The user hasn't determined this app's access.
    case .restricted:
        // The system restricted this app's access.
    case .denied:
        // The user explicitly denied this app's access.
    case .authorized:
        // The user authorized this app to access Photos data.
    case .limited:
        // The user authorized this app for limited Photos access.
    @unknown default:
        fatalError()
    }
}

💡 limited access only라면
authorizationStatus()requestAuthorization(_:)은 비교가 불가능하고(옛날에 만들어진 것이기도 하고, limited가 아직 없기 때문이다) PHAuthorizationStatus.authorized를 리턴한다.
authorizationStatus(for:)requestAuthorization(for:handler:)를 사용해야한다.

💡 무슨 말이냐면 💡
PHPhotoLibrary.requestAuthorization(for: .readWrite)에서
addOnly나 readWrite를 사용할 수 있는데
기본적으로 사용자가 선택한 사진만을 추가할 수 있다는 것이 공통으로 깔려있다.
addOnly가 되면 앱이 사용자가 선택한 사진만 추가할 수 있다는 것이고,
readWrite가 되면 앱이 사용자가 선택한 사진을 사용할 수 있거나(limited) 모든 사진을 사용할 수 있게 되는거다(authorized)

Work with the Limited Library

iOS14가 되면서 사진을 선택적으로 공유를 할 수 있게 되었다

PHAuthorizationStatus.limited상태라면 시스템은 PHAssetCreationRequest로 에셋을 자동으로 추가한다
앨범을 생성하거나 가져오려면 PHAuthorizationStatus.limited를 다른 상태로 바꿔야 한다.

Present the Limited-Library Selection Interface

권한 물어보는 피커 띄우기

// Present the limited-library selection user interface.
let viewController = // The UIViewController from which to present the picker.
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController)

iOS15부터는 limited권한을 사용 중인 사용자 행동을 observing하다가 권한을 콜백으로 실행시킬 수 있게 될거다

// Present the limited-library selection user interface with a callback.
let viewController = // The UIViewController from which to present the picker.
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController) { identifiers in
    for newlySelectedAssetIdentifier in identifiers {
        // Stage asset for app interaction.
    }
}

PHPickerViewController

UIImagePickerControllerPHPickerViewController가 되었다!

Cannot inherit from non-open class 'PHPickerViewController' outside of its defining module
cocoa touch class를 사용해 ViewController 만들 듯이 만들었는데
오류가 난다
안쪽에 만들어서 사용하는건가부당🥲
💡 You can’t subclass PHPickerViewController because its view hierarchy is private and not accessible through the public API.
PHPickerViewController를 subclass할 수 없습니다. 왜냐하면 뷰 계층이 private이거든요🥲

class PHPickerViewController : UIViewController
뷰컨트롤러를 상속받았구나

PhotosUI프레임워크 안에 들어있기 때문에 import 해줘야한다

PHPicker
필요한 경우

뭔가 사용자의 접근 권한이 없을 때 선택적으로 선택하게 만들어서 사진을 관리하는건감

아래는 예시코드

import UIKit
import PhotosUI

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    
    //라이브러리에서 가져온 사진 저장할 공간
    var itemProviders: [NSItemProvider] = []
    var iterator: IndexingIterator<[NSItemProvider]>?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var configuration = PHPickerConfiguration()
        configuration.selectionLimit = 0
        configuration.filter = .images
        
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        
        present(picker, animated: true)
    }


    func displayNextImage() {
        if let itemProvider = iterator?.next(), itemProvider.canLoadObject(ofClass: UIImage.self) {
            let previousImage = imageView.image
            itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
                DispatchQueue.main.async {
                    guard let self = self, let image = image as? UIImage, self.imageView.image == previousImage else { return }
                    self.imageView.image = image
                }
            }
        }
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        displayNextImage()
    }
}

extension ViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        
        if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
            itemProvider.loadObject(ofClass: UIImage.self) { image, error in

                self.itemProviders = results.map(\.itemProvider)
                self.iterator = self.itemProviders.makeIterator()
                self.displayNextImage()
                
            }
        }
    }
}

PhotoKit

let photoLibrary = PHPhotoLibrary.shared()
let configuration = PHPickerConfiguration(photoLibrary: photoLibrary)

let identifiers: [String] = results.compactMap(\.itemProvider)
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)

PhotoKit와 PHPickerViewController를 사용하자
AssetLibrary는 deprecated되었고
UIImagePickerController는 deprecated되고 있당

🍎 사용자가 사진을 사용할때까지 권한을 요구하지 마라!!! 이게 핵심이다

좋은 웹페이지 즐겨찾기