Swift/기타
[SWIFT]갤러리 및 카메라 사용 UIImagePickerController(디폴트 UI)
삽질중
2023. 4. 20. 17:36
갤러리와 카메라 사진 촬영 이미지 사용을 위해 싱글톤 타입으로 컴포넌트화 했다.
import UIKit
import MobileCoreServices
import AVFoundation
import Photos
public typealias GlobalBoolCompleteClosure = (Bool) -> Void
enum PHPhotoLibraryAuthorizationError: Error {
case error(PHAuthorizationStatus)
}
extension PHPhotoLibrary {
@discardableResult class func syncRequestAuthorization() throws -> PHAuthorizationStatus {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized:
return status
case .denied, .restricted:
throw PHPhotoLibraryAuthorizationError.error(status)
case .notDetermined:
break
case .limited:
break
default:
break
}
let semaphore = DispatchSemaphore(value: 0)
PHPhotoLibrary.requestAuthorization{ _ in
semaphore.signal()
}
semaphore.wait()
let newStatus = PHPhotoLibrary.authorizationStatus()
switch newStatus {
case .authorized:
return newStatus
case .denied, .restricted, .notDetermined:
throw PHPhotoLibraryAuthorizationError.error(newStatus)
default :
throw PHPhotoLibraryAuthorizationError.error(newStatus)
}
}
}
enum MediaType {
case CAMERA
case PHOTO_LIBRARY
}
class ImagePickerInterface: NSObject {
static let shared = ImagePickerInterface()
// UIImagePickerController의 인스턴스 변수 생성
let imagePicker: UIImagePickerController! = UIImagePickerController()
// 사진을 저장할 변수
var captureImage: UIImage!
// 녹화한 비디오의 URL을 저장할 변수
var videoURL: URL!
// 사진 저장 여부를 나타낼 변수
var flagImageSave = false
var photoImageCompleteClosur: ((Bool, URL?, UIImage?) -> Void)!
var imageCompleteClosur: ((Bool, UIImage?) -> Void)!
override init() {
super.init()
}
static func showImagePickerFileUpload(mediaType: MediaType, completion: @escaping (Bool, URL?, UIImage?) -> Void) {
switch mediaType {
case .PHOTO_LIBRARY:
ImagePickerInterface.shared.checkPhotoLibraryPermission { (isAuthorize) in
if isAuthorize == true {
ImagePickerInterface.shared.photoImageCompleteClosur = { (isSuccess, file_url, image) in
print("Photo Image : \(isSuccess) / \(String(describing: file_url)) / \(String(describing: image))")
completion(isSuccess, file_url, image)
}
ImagePickerInterface.shared.usePhotoLibrary()
} else {
ImagePickerInterface.shared.requestPermissionSettingAlertAction()
}
}
case .CAMERA:
ImagePickerInterface.shared.checkPhotoLibraryPermission { (isAuthorize) in
if isAuthorize == true {
ImagePickerInterface.shared.photoImageCompleteClosur = { (isSuccess, file_url, image) in
print("Camera Image : \(isSuccess) / \(String(describing: file_url)) / \(String(describing: image))")
completion(isSuccess, file_url, image)
}
ImagePickerInterface.shared.useCamera()
}
else {
ImagePickerInterface.shared.requestPermissionSettingAlertAction()
}
}
}
}
///마이크 권한 요청
private func requestMicPermission(completion:@escaping (Bool)->Void){
DispatchQueue.main.async {
AVAudioSession.sharedInstance().requestRecordPermission { (isGranted) in
completion(isGranted)
}
}
}
///카메라 권한 요청
private func requestCameraPermission(completion: @escaping (Bool)->Void ){
DispatchQueue.main.async {
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized{
completion(true)
}else{
AVCaptureDevice.requestAccess(for: .video) { (granted) in
completion(granted)
}
}
}
}
private func goToPermissionSetting(){
if let url = URL(string: UIApplication.openSettingsURLString){
UIApplication.shared.open(url, options: [:]) { (finish) in
}
}
}
}
extension ImagePickerInterface: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
// MARK: 앨범 사진 사용
/// 앨범 사용권한 확인
private func checkPhotoLibraryPermission(complete: @escaping GlobalBoolCompleteClosure) {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized:
complete(true)
case .denied :
complete(false)
case .notDetermined: // 선택안함.
requestPhotoLibraryAuthorization { (isAuthorize) in
complete(isAuthorize)
}
default: break
}
}
/// 앨범 사용권한 요청
private func requestPhotoLibraryAuthorization(complete: @escaping GlobalBoolCompleteClosure ) {
DispatchQueue.main.async {
PHPhotoLibrary.requestAuthorization { (status) in
switch status{
case .authorized:
complete(true)
case .denied:
complete(false)
case .restricted:
complete(false)
default:
complete(false)
}
}
}
}
/// 앨범 라이브러리 호출
private func usePhotoLibrary() {
if (UIImagePickerController.isSourceTypeAvailable(.photoLibrary)){
flagImageSave = true
DispatchQueue.main.async { [self] in
imagePicker.delegate = self
// 이미지 피커의 소스 타입을 PhotoLibrary로 설정
imagePicker.sourceType = .photoLibrary
imagePicker.mediaTypes = [kUTTypeImage as String]
// 편집을 허용
imagePicker.allowsEditing = false
guard let topVC = UIApplication.currentTopViewController() else {
return
}
topVC.present(imagePicker, animated: true, completion: nil)
}
}
}
// MARK: 카메라 촬영 사진 사용
/// 카메라 사용권한 확인
private func checkCameraPermission(complete: @escaping GlobalBoolCompleteClosure) {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .authorized:
complete(true)
case .denied :
complete(false)
case .notDetermined: // 선택안함.
requestCameraAuthorization { (isAuthorize) in
complete(isAuthorize)
}
default: break
}
}
/// 카메라 사용권한 요청
private func requestCameraAuthorization(completion: @escaping GlobalBoolCompleteClosure ) {
DispatchQueue.main.async {
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized{
completion(true)
}else{
AVCaptureDevice.requestAccess(for: .video) { (granted) in
completion(granted)
}
}
}
}
/// 카메라 사용
private func useCamera() {
if (UIImagePickerController.isSourceTypeAvailable(.camera)){
flagImageSave = true
DispatchQueue.main.async { [self] in
imagePicker.delegate = self
// 미디어 소스의 형태지정 (카메라)
imagePicker.sourceType = .camera
// 앱에서 처리할 미디어의 형태 MobileCoreServices 프레임워크에 포함된 값으로 사용할 수 있다.
imagePicker.mediaTypes = [kUTTypeImage as String]
// 편집을 허용
imagePicker.allowsEditing = false
guard let topVC = UIApplication.currentTopViewController() else {
return
}
topVC.present(imagePicker, animated: true, completion: nil)
}
}
}
// MARK: 접근권한 설정 알림(권한설정 거부시)
/// 접근권한 거부시 알림 얼럿 (설정 페이지 이동)
private func requestPermissionSettingAlertAction() {
let alert = UIAlertController(title: "", message: "앨범의 사진을 사용하려면 사진 권한이 필요합니다. 권한 설정 화면으로 이동 하시겠습니까?", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .destructive) { (action) in
log(direction: .SCHEME, ofType: self, datas: "Action Yes")
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
print("setting URL : \(settingsUrl)")
DispatchQueue.main.async {
if UIApplication.shared.canOpenURL(settingsUrl) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(settingsUrl, completionHandler:nil)
} else {
UIApplication.shared.openURL(settingsUrl)
}
}
}
}
let cancel = UIAlertAction(title: "CANCEL", style: .cancel) { (action) in
log(direction: .SCHEME, ofType: self, datas: "Action Cancel")
}
alert.addAction(ok)
alert.addAction(cancel)
guard let topVC = UIApplication.currentTopViewController() else {
return
}
topVC.present(topVC, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// 미디어 종류 확인
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as! NSString
// 미디어 종류가 사진(Image)일 경우
if mediaType.isEqual(to: kUTTypeImage as NSString as String){
// 사진을 가져와 captureImage에 저장
captureImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
if flagImageSave { // flagImageSave가 true이면
// 현재의 뷰 컨트롤러를 제거. 즉, 뷰에서 이미지 피커 화면을 제거하여 초기 뷰를 보여줌
picker.dismiss(animated: true) { [weak self] in
// self?.imageFileSave()
self?.photoImageCompleteClosur?(true, nil, self?.captureImage)
}
}
// 미디어 종류가 비디오(Movie)일 경우
} else if mediaType.isEqual(to: kUTTypeMovie as NSString as String) {
if let image = info[.originalImage] as? UIImage {
captureImage = image
}
if flagImageSave { // flagImageSave가 true이면
// 촬영한 비디오를 옴
picker.dismiss(animated: true) { [weak self] in
// self?.imageFileSave()
self?.photoImageCompleteClosur?(true, nil, self?.captureImage)
}
}
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
사용방법
** 클로저의 fileurl 사용 안함 주의
// 갤러리 라이브러리 사진 이미지 추출
ImagePickerInterface.showImagePickerFileUpload(mediaType: .PHOTO_LIBRARY) { isSuccess, fileurl, image in
log(direction: .ETC, ofType: self, datas: isSuccess, fileurl)
}
// 카메라 촬영 이미지 추출
ImagePickerInterface.showImagePickerFileUpload(mediaType: .CAMERA) { isSuccess, fileurl, image in
log(direction: .ETC, ofType: self, datas: isSuccess, fileurl)
}