[iOS] 사용자에게 사진권한 받아오기

Jehyeon Lee·2023년 11월 28일
0
post-thumbnail

결과화면

제가 만드는 프로젝트에서 사용자에게 기기의 사진권한을 받아야 얼굴사진을 받아올 수 있기에 사진권한 기능을 추가하였습니다.

extension SignUpPictureViewController: PHPickerViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

일단 PHPickerViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate 이 세종류의 프로토콜을 채택해야 합니다.
이 프로토콜들은 이미지 피커와 네비게이션 컨트롤러와 관련된 상호작용을 다루기 위한 것입니다.

 @objc private func openPhotoLibrary() {
        // 포토 라이브러리에 대한 권한이 허용되었는지 확인
        if PHPhotoLibrary.authorizationStatus() == .authorized {
            // PHPickerViewController 구성
            var configuration = PHPickerConfiguration()
            configuration.selectionLimit = 3 // 최대 선택 가능한 이미지 수
            let picker = PHPickerViewController(configuration: configuration)
            picker.delegate = self
            // 이미지 선택 뷰컨트롤러 표시
            present(picker, animated: true, completion: nil)
        } else {
            // 권한이 거부된 경우 처리
            pictureManager.unauthorized(in: self)
        }
    }

코드설명

  • 사용자가 프로필 사진을 선택하려면 openPhotoLibrary 메서드를 호출합니다.
  • PHPhotoLibrary.authorizationStatus()를 사용하여 앱이 포토 라이브러리에 접근할 수 있는지 확인합니다.
  • 권한이 허용되어 있다면, PHPickerViewController를 설정하고 화면에 나타냅니다. 이때 최대 3개의 이미지를 선택할 수 있도록 설정되어 있습니다.
  • 권한이 거부되었다면, pictureManager.unauthorized(in: self)를 호출하여 사용자에게 앱 권한이 필요하다는 메시지를 표시합니다.

이제 이미지를 선택했을때 처리를 해줘야합니다

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true, completion: nil)
    var selectedImages: [UIImage] = []
    
    for result in results where result.itemProvider.canLoadObject(ofClass: UIImage.self) {
        result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, _ ) in
            guard let self = self else { return }
            
            guard let image = image as? UIImage else { return }
            selectedImages.append(image)
            
            guard selectedImages.count == results.count else { return }
            userImages = selectedImages
            DispatchQueue.main.async { [weak self] in
                guard let self = self else { return }
                
                collectionView.reloadData()
                configNextButton(isEnabled: true)
            }
        }
    }
}

코드설명

  • 사용자가 이미지를 선택하고 나면, picker(didFinishPicking:) 메서드가 호출됩니다.
  • 선택한 이미지를 저장할 배열 selectedImages를 초기화합니다.
  • 결과에서 UIImage를 로드할 수 있는지 확인하고, 가능하다면 이미지를 배열에 추가합니다.
  • 모든 선택이 완료되면, userImages 배열을 업데이트하고, 메인 스레드에서 컬렉션 뷰를 리로드하고 다음 버튼을 활성화합니다.

이전까지는 뷰컨트롤러에서 사진 델리게이트를 활용하여 사진첩에 간편하게 접근하고 최대 3장의 사진을 선택할 수 있도록 구현했습니다. 이제는 사용자에게 사진 권한을 묻기 위한 알림을 띄우기 위한 코드를 작성해야합니다. 저는 사진권한을 묻기 위한 기능들을 하나의 서비스로 따로빼서 작업하였습니다.

PictureService

final class PictureService {
    func unauthorized(in viewController: UIViewController) {
        DispatchQueue.main.async {
            viewController.showCustomAlert(alertType: .canCancel, titleText: "사진 라이브러리 권한 필요", messageText: "사진을 선택하려면 사진 라이브러리 권한이 필요합니다. 설정에서 권한을 변경할 수 있습니다.", confirmButtonText: "설정으로 이동", comfrimAction: {
                if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
                    UIApplication.shared.open(settingsURL)
                }
            })
        }
    }

코드설명

  • unauthorized 함수: unauthorized 함수는 권한이 거부되었을 때 호출되어 사용자에게 알림을 띄웁니다.
  • showCustomAlert 는 프로젝트에서 미리 커스텀해서 만들어놓은 알럿창입니다.
  • if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
    UIApplication.shared.open(settingsURL)
    }
    이부분은 핸드폰의 설정 화면으로 가는 코드입니다.

이제 각 권한 상태에 따른 처리를 위해 switch 문을 사용하여 엑세스 요청을 조건별로 처리해야합니다.

func requestPhotoLibraryAccess(in viewController: UIViewController) {
        PHPhotoLibrary.requestAuthorization { [weak self] status in
            guard let self = self else { return }
            switch status {
            case .authorized:
                break
            case .denied, .restricted, .notDetermined, .limited:
                self.unauthorized(in: viewController)
            @unknown default:
                self.unauthorized(in: viewController)
            }
        }
    }

코드설명

  • PHPhotoLibrary.requestAuthorization: 이 부분은 Photos 프레임워크에서 권한을 요청하는 메서드입니다. 사용자에게 권한을 요청하고, 결과에 따라 클로저가 호출됩니다.

  • switch status: status 값을 기반으로 한 switch 문으로, 다양한 권한 상태에 대한 처리를 합니다.

  • .authorized: 권한이 허용된 상태이므로 별도의 처리 없이 break로 종료합니다.

  • .denied, .restricted, .notDetermined, .limited: 권한이 거부되었거나, 제한되었거나, 아직 결정되지 않았거나, 제한적인 권한이 있는 경우에는 unauthorized 함수를 호출하여 사용자에게 알림을 표시합니다.

  • @unknown default: 알 수 없는 다른 상태가 발생한 경우에도 unauthorized 함수를 호출하여 알림을 표시합니다.

트러블

현재 구현한 기능에서는 사용자가 사진 접근을 거부하고 설정으로 이동한 후 권한을 변경하면, 다시 앱으로 돌아올 때 네비게이션 스택의 첫 번째 화면으로 이동하는 문제가 발생하고 있습니다. 이 문제는 현재로서는 공식 문서나 다른 출처에서 명확한 해결책을 찾기 어렵습니다. 배달의 민족과 같은 다른 앱에서도 동일한 문제가 발견되어, 이는 애플의 내부 정책에서 비롯된 것으로 보입니다. 현재까지는 이 문제에 대한 공식적인 해결 방법이 알려지지 않았습니다.

해결한 방법

  • 사진권한같은 부분을 시나리오의 앞부분으로 가져와서 미리 권한을 수락 받게끔 뷰의 시나리오를 작성하여 맨 앞단에서 권한을 요청하였습니다.
profile
공부한거 느낌대로 써내려갑니당

0개의 댓글

관련 채용 정보