iOS/SwiftUI

[iOS] 앨범/카메라 접근 권한 및 datepicker 연동

yanni13 2024. 8. 11. 10:12

 

 

아이폰에서 앨범 및 카메라에 접근할 때 접근권한 팝업에 대해 본 적 있을 것이다!!

사용자 개인정보에 함부로 접근할 수 없어 동의를 얻고 구해야 한다.

 

따라서 접근권한 팝업 띄우는 것을  SwiftUI에서 적용해보려고 한다

 

 

1️⃣  Info 파일 권한 설정하기

 

접근: 프로젝트파일 -> TARGETS -> Info 

접근해서 맨 밑에 항목을 클릭하면 +를 통해 항목을 추가할 수 있다

 

추가해야 하는 파일은 아래의 항목 2개를 찾아서 추가해 주면 된다

 

  • 카메라 추가 : Privacy - Camera Usage Desciption
  • 앨범 추가:  Privacy - Photo Library Usage Desciption

 

2️⃣ 사용방법

이제 필요한 곳에 연결해 주면 끝이다!

 

 위에 기능을 사용하는 파일에 꼭 아래 프레임워크를 import를 해서 사용해주어야 한다. (아니면 오류남)

import AVFoundation
import Photos

 

 

보통 아래와 같이 사용하면 된다.

// 앨범
PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
      DispatchQueue.main.async {
           self.handlePhotoLibraryStatus(status)
      }
}

//카메라
AVCaptureDevice.requestAccess(for: .video) { granted in
       DispatchQueue.main.async {
           if granted {
                 self.sourceType = .camera
            }
        }
}

 

사용방법은 위와 같지만 PHPhotoLibrary와 AVCaptureDevice가 뭘까???

 

 

PHPhotoLibrary

 

간단하게 설명하면 PHPhotoLibrary란 iOS랑 macOS에서 사용자가 기기에서 앨범에 접근, 관리 하는 권한을 가진다.

공식문서에 들어가보면 이 클래스에 해당하는 엄청 많은 메서드들을 가진다

 

 

우리는 그 중 PHPhotoLibrary에서 제공해주는 requestAuthorization , 접근 권한을 요청하는 메서드를 사용하겠다!! 라고 지정한것이다.

 

 

그럼 저 readWrite는 뭔데??

 

iOS 14이상부터 파라미터에 PHAccessLevel타입이 들어갈 수 있다.

PHAccessLevel 타입은 addOnly, readWrite 두개가 존재한다! 

 

당연히 우리는 사진을 읽어야 하고 저장하고 사용할 수도 있어야 하기 때문에  readWrite를 채택하였다

아마 대부분 서비스에서 readWrite를 채택하지 않을까 싶다.

 

 

그럼 다시 코드로 올라가서 비동기처리를 해주는 DispatchQueue.main.async를 사용해주는 이유는 뭘까?

 

단순하다! 팝업을 불러오는데 지연시간이 어느정도걸리기에 비동기처리를 해서 사용해준것이다!!

 

 

AVCaptureDevice

 

AVCaptureDevice는 iOS 및 macOS에서 카메라, 마이크 등의 입력 장치를 제어하고 관리하는 역할을 하는 클래스이다

 

 

즉 카메라에 대한 접근권한이 필요할 때 사용하면 됨!

 

이 클래스도 마찬가지로 파라미터를 줘서 사용할 수 있는데 찾아보면 엄청 많은 type들을 할당할 수 있다.

우린 그중에 사진기능을 사용하고 싶으니까 video로 선택하기!

 

 

 

나 같은 경우에는 사용자 프로필을 다룰 수 있는 팝업이 존재해서 그 팝업에 switch 문으로 해당하는 기능을 연결시켜 주었다.

앨범에서 사진선택/ 사진 촬영 /삭제 경우에 대한 case를 분류해 주었고 각 기능에 대한 함수로 별도 분리하여 코드의 가독성을 높였다.

 

 

전체 코드를 보면 아래와 같다.

private func handleOption(_ option: String) {
        switch option {
        case "앨범에서 사진 선택":
            checkPhotoLibraryPermission()
        case "사진 촬영":
            checkCameraPermission()
        case "삭제":
            image = nil
            selectedUIImage = nil
        default:
            break
        }
    }
	
    // 앨범
    private func checkPhotoLibraryPermission() {
        let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
        handlePhotoLibraryStatus(status)
    }
    
    // 사진
    private func checkCameraPermission() {
        let status = AVCaptureDevice.authorizationStatus(for: .video)
        switch status {
        case .authorized:
            sourceType = .camera
            showImagePicker = true
        case .denied, .restricted:
            showAlertAuth(type: "카메라")
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { granted in
                DispatchQueue.main.async {
                    if granted {
                        self.sourceType = .camera
                        self.showImagePicker = true
                    }
                }
            }
        @unknown default:
            break
        }
    }

 

 

📍 동작과정 및 주의할 점

 

동작과정 !!!!

 

 

위에 동작과정을 보면 동의항목을 구하는 문구가 나오는데 이건 내가 설정한 거다!

 

보통 다른 앱을 보면 

왜냐면 사용자가 설정에서 어떤 접근권한에 체크하느냐에 따라 팝업 종류도 다르고 아예 안뜨기도 한다.

 

 

* 설정에서 앨범 및 사진 접근 권한에 대한 설정

1. 사용자가 아무런 접근권한에 대해 선택하지 않은 경우(기본 상태인 경우) -> '접근하겠냐'는 팝업이 한번 뜸
2. 사용자가 '안 함'에 체크했을 경우 -> 팝업 안 뜨고 앨범에 접근 안 됨
3. 사용자가 '제한된 접근'에 체크했을 경우 -> 제한된 사진에 대해서만 접근 가능
4. 사용자가 '항상 허용'에 체크했을 경우 -> 앨범 접근 권한 가능

 

 

 그래서 사용자가 설정에 대해서 어떤 상태를 체크했는지에 따라 case 별로 분류해 주었다.

 

  • 거부, 제한했을 경우 -> 커스텀 팝업 띄워서 설정으로 강제 이동해 사용자가 접근 권한 다시 설정할 수 있도록 하기
  • 결정하지 않았을 경우 -> 이미지 동의항목 구하는 팝업 띄움
  • 항상 허용했을 경우 -> photoLibrary 띄움
private func handlePhotoLibraryStatus(_ status: PHAuthorizationStatus) {
        switch status {
        case .authorized, .limited:
            sourceType = .photoLibrary
            showImagePicker = true
        case .denied, .restricted:
            showAlertAuth(type: "앨범")
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
                DispatchQueue.main.async {
                    self.handlePhotoLibraryStatus(status)
                }
            }
        @unknown default:
            break
        }
    }

 

 

📍CustomPopUp

 

 

 

문구는 조금 수정해야 하겠지만 거부했거나 제한된 사용을 선택했을 경우 customPopUp을 띄우게 해 주었고 이 팝업에서 확인을 누르면 설정에 앨범 및 카메라 접근제한을 설정할 수 있는 창으로 이동하도록 구현하였다.

 

이거 개발하려고 다른 앱도 조금 뒤져보니까 이런 방식을 채택하는 경우가 많았다.

 

인스타그램은 페이지를 하나 더 띄워서 앨범 접근권한 동의해라~라고 사용하였고,

네이버 블로그에서도 위와 같은 팝업을 띄워서 설정 창으로 강제 이동하게 하였다.

 

 

구현 방법

private func showAlertAuth(type: String) {
        let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "이 앱"
        let alertVC = UIAlertController(
            title: "설정",
            message: "\(appName)이(가) \(type) 접근 허용되어 있지 않습니다. 설정화면으로 가시겠습니까?",
            preferredStyle: .alert
        )
        let cancelAction = UIAlertAction(title: "취소", style: .cancel, handler: nil)
        let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in
            UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
        }
        alertVC.addAction(cancelAction)
        alertVC.addAction(confirmAction)
        UIApplication.shared.windows.first!.rootViewController!.present(alertVC, animated: true, completion: nil)
    }

 

 

저 팝업을 뜨게 하는 게 alert를 통해서 띄워야 하고 '확인'버튼을 누르면 설정 창으로 넘어가야 하기 때문에 UIApplication.openSettingsURLString 을 통해 강제로 넘어가도록 하였다.~

 

 

 

 

 

참고


https://randy95.tistory.com/29