iOS

Access Photo Library & Delete Asset

GREEN.1229 2021. 10. 3. 09:58

안녕하세요. 그린입니다🟢

이번 포스팅에서는 디바이스 사진 앨범에 접근하는 방법 및 에셋을 삭제하는 방법에 대해 알아보겠습니다🧑🏻‍💻

 

이전에 제 포스팅중에서 화면 캡쳐 및 녹화 방지에 대해 학습해본적이 있습니다!

https://green1229.tistory.com/169

 

화면 캡쳐 및 녹화 방지

안녕하세요. 그린입니다🟢 이번 포스팅에서는 화면 캡쳐 및 녹화 방지에 대해 포스팅해보겠습니다🧑🏻‍💻 제공하는 앱에서 화면 캡쳐와 녹화를 원천적으로 차단할 수 있을까요? 우선, 가능

green1229.tistory.com

그런데 화면 캡쳐와 녹화 방지된것을 얼럿만 띄워주는걸 보았는데요.

더 발전시켜서 사용자가 원한다면 캡쳐 및 녹화된 사진과 영상을 삭제할 수도 있어야 될것 같아요.

그렇다면 디바이스 사진 앨범에 접근할 수 있어야겠죠?

 

그래서 오늘 준비한것이 바로 그것입니다🙌

정말 간단히 슉하고 지나갈테니 잘 캐치해주시면 감사하겠습니다!

아! 추가로 사진 앨범 삭제에 대해 묻는 얼럿 기능은 구현했단 가정하에 앨범 접근에 대해서만 구현해볼께요!

[전체 코드]

import Photos

struct PhotoService {
  ...
  init() { }
  ...
  // 사진 접근 권한 판별
  func checkAccessPhotoLibrary() {
    let authorizationStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
    if authorizationStatus == .authorized {
      deleteLatestAsset()
    } else {
    // 접근 권한이 없다는 얼럿 노출
    }
  }
  ...
  // 마지막 사진or영상 에셋 삭제
  func deleteLatestAsset() {
    let fetchScreenshotOptions = PHFetchOptions()
    fetchScreenshotOptions.sortDescriptors = [NSSortDescriptor(
      key: "creationDate", 
      ascending: true
    )]
    fetchScreenshotOptions.predicate = NSPredicate(
      format: "mediaType = %d || mediaType = %d", 
      PHAssetMediaType.image.rawValue,
      PHAssetMediaType.video.rawValue
    )
    
    guard let latestScreenshot = PHAsset.fetchAssets(with: fetchScreenshotOptions).lastObject else {
      // 사진 패치 실패 시 처리
    }
    
    PHPhotoLibrary.shared().performChanges {
      PHAssetChangeRequest.deleteAssets([lastestScreenshot] as NSFastEnumeration)
    }
  }
}

자 코드론 이렇습니다!

일단 제가 편하게 설명하기 위해 코드바이코드로 설명보다는 전체 코드를 툭 던지고 핵심 부분만 설명해볼께요☺️

 

PHPhotoLibrary

공식 문서의 설명을 보면 사진 라이브러리에 접근하거나 변경 할 수 있는 오브젝트입니다.

즉 사진 앨범에 관해 모든걸 처리해줄 수 있죠!

그래서 먼저 사진 라이브러리 접근 권한이 있는지부터 판단해야겠죠?

 

authorizationStatus(for:)

해당 메서드는 PHPhotoLibrary에 속한 메서드로 아래와 같이 정의되어 있습니다.

class func authorizationStatus(for accessLevel: PHAccessLevel) -> PHAuthorizationStatus

자 PHAccessLevel 타입의 파라미터를 받아 PHAuthorizationStatus 타입을 반환합니다.

접근 레벨을 받아 접근 상태를 반환한다!

그럼 PHAccessLevel와 PHAuthorizationStatus에 대해 알아봐야겠죠?

 

PHAccessLevel

말그대로 사진 권한레벨입니다.

아래와 같이 열거형으로 정의되어 있습니다.

enum PHAccessLevel : Int

addOnlyreadWrite 케이스가 존재합니다.

addOnly는 사진 라이브러리에 추가하는것만 가능하고 

readWrite는 수정과 가져오기 모두 가능합니다.

 

PHAuthorizationStatus

접근레벨에 대한 상태값입니다.

enum PHAuthorizationStatus : Int

똑같이 열거형으로 정의되어 있고,

  • notDetermind: 정해지지 않은 상태
  • restricted: 제한
  • denied: 거부
  • authorized: 허용
  • limited: 제한된 허용

위와 같이 5가지의 케이스가 있습니다.

 

자 그럼 다시 본론으로가서 readWrite 상태로 정의해주고 .authorized의 케이스일때만 사진앨범에서 에셋을 가져와 삭제할 수 있도록 함수를 호출합니다.

 

그럼 두번째 메서드를 보시죠!

 

PHFetchOptions

class PHFetchOptions : NSObject

에셋을 가져오는 옵션에 대해 정의해주는 객체입니다.

sortDescriptors 메서드와 predicate 메서드를 호출하여 옵션을 줄 수있습니다.

 

sortDescriptors

var sortDescriptors: [NSSortDescriptor]? { get set }

에셋을 정렬해서 가져오는 상세를 만들어줍니다.

조금 더 디테일하게 구현을 보자면,

let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
let fetchResult = PHAsset.fetchAssets(with: fetchOptions)
return fetchResult.firstObject

이렇게 공식문서에서는 사용하고 있습니다.

key는 생성된 날짜와 ascending을 통해 나열해줍니다.

그리고 위의 예시는 첫번째 에셋을 가져오게됩니다.

다만 저희 프로젝트는 가장 최근 에셋을 삭제해야함으로 lastObject를 통해 가져옵니다.

 

predicate

어떠한 형식의 파일을 가져올지 정해줍니다.

var predicate: NSPredicate? { get set }

위와 같이 선언이 되어있습니다.

사용은 아래와 같이 합니다.

(근데 아직 공식문서에서는 스위프트로 변환이 안되어있는것 같네요?)

PHFetchOptions* fetchOptions = [PHFetchOptions new];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"(mediaSubtypes & %d) != 0 || (mediaSubtypes & %d) != 0", PHAssetMediaSubtypePhotoPanorama, PHAssetMediaSubtypeVideoHighFrameRate];
PHFetchResult* fetchResult = [PHAsset fetchAssetsWithOptions:fetchOptions];

무튼 간단히 보자면, 어떤 형식의 에셋 파일을 가져올지 지정해주는것입니다.

공식문서 사용법보다 저희 프로젝트 사용법을 보는게 더 나을거에요!

사진과 영상 에셋에 대해 가져오도록 옵션을 주어줍니다.

 

마지막으로 해당 옵션들을 다 만들었으면 사진을 삭제하는 기능을 수행해줘봅시다🔥

 

PHPhotoLibrary의 performchanges 메서드를 보시죠.

 

performchanges(_:completionHandler:)

어떠한 변경이 되면 수행하도록 해주는 메서드입니다.

func performChanges(
  _ changeBlock: @escaping () -> Void, 
  completionHandler: ((Bool, Error?) -> Void)? = nil
)

호출이되면 핸들러를 실행하죠.

우리는 핸들러에 가져온 사진 및 영상에 대해 삭제해주도록 해볼께요.

 

deleteAssets(_:)

지정한 에셋을 삭제해주는 메서드입니다.

class func deleteAssets(_ assets: NSFastEnumeration)

위와 같이 선언되어있고 에셋 파라미터에 지정한 에셋을 넣어줍니다.

에셋은 NSFastEnumeration 타입입니다.

 

NSFastEnumeration

protocol NSFastEnumeration

프로토콜로 객체의 빠른 열거를 지원해줍니다.

삭제는 하나의 항목만 가져옴으로 빠른 열거를 통해 한번에 하나씩 항목을 반환하는데 사용하여 구현됩니다.

 

자! 많이도 왔습니다ㅎㅎ
이렇게 해준다면 사진접근 권한에 대해 파악하고 그에 따라 사진 및 영상을 삭제해줄 수 있습니다!
아래와 같이 구동됩니다☺️


[구현영상]

Access
Delete

[참고자료]

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

 

Apple Developer Documentation

 

developer.apple.com

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

 

Apple Developer Documentation

 

developer.apple.com