관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 2. Observable로 Wrapping하여 권한 요청) 사진 권한, 카메라 권한  본문

iOS 응용 (swift)

[iOS - swift] 2. Observable로 Wrapping하여 권한 요청) 사진 권한, 카메라 권한 

jake-kim 2022. 1. 5. 23:25

1. Observable로 Wrapping하여 권한 요청) 위치 권한, 실시간 위치 정보 획득

2. Observable로 Wrapping하여 권한 요청) 사진 권한, 카메라 권한

3. Observable로 Wrapping하여 권한 요청) 마이크 권한, ATT(App Tracking Transparency) 권한

4. Observable로 Wrapping하여 권한 요청) RxSwift의 concat을 이용하여 순서대로 권한 요청 방법

Observable로 wrapping 작업 핵심

  • 기존에 Observable 형태를 리턴해주는 작업이면, RxSwift의 생성자 연산자 중에 deferred 연산자 사용하여 wrapping
  • 기존에 Observable 형태가 아니고 클로저 형태로 값을 받는 경우, create 연산자 사용

필요한 framework 준비

  • framework
pod 'RxSwift'
pod 'RxCocoa'
  • 사진 시스템 접근: Privacy - Photo Library Usage Description

observable로 Wrapping

  • Observable로 Wrapping 방법
    • 기존에 Observable 형태를 리턴해주는 작업이면, RxSwift의 생성자 연산자 중에 deferred 연산자 사용하여 wrapping
    • 기존에 Observable 형태가 아니고 클로저 형태로 값을 받는 경우, create 연산자 사용

ex) deferred 연산자 사용하여 위치 권한 wrapping

func requestLocation() -> Observable<CLAuthorizationStatus> {
  return Observable<CLAuthorizationStatus>
    .deferred { [weak self] in
      guard let ss = self else { return .empty() }
      ss.locationManager.requestWhenInUseAuthorization()
      return ss.locationManager.rx.didChangeAuthorization
        .map { $1 }
        .filter { $0 != .notDetermined }
        .do(onNext: { _ in ss.locationManager.startUpdatingLocation() })
        .take(1)
    }
}​
  • Photo 권한 요청은 기존에 Observable 형태를 리턴해주는 모듈이 없으므로 create연산자를 사용
    • async 작업이 끝나고 completion 클로저에서 observable.onNext()하여 방출하고
    • create 연산자 사용 시 주의사항은 Disposables.create()를 completion 클로저 블록 안에서 사용하지 않는 점
import RxSwift
import RxCocoa
import Photos

class PhotoPermissionManager {
  static let shared = PhotoPermissionManager()
  private init() {}
  
  func requestPhoto() -> Observable<PHAuthorizationStatus> {
    Observable<PHAuthorizationStatus>.create { observable in
      PHPhotoLibrary.requestAuthorization { auth in
        DispatchQueue.main.async {
          observable.onNext(auth)
          observable.onCompleted()
        }
      }
      return Disposables.create()
    }
  }
}
  • 사용하는 쪽
import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
  
  private let disposeBag = DisposeBag()

  @IBAction func didTapPhotoPermissionButton(_ sender: Any) {
    PhotoPermissionManager.shared.requestPhoto()
      .bind { print($0) }
      .disposed(by: self.disposeBag)
  }
}

카메라 권한 요청

  • info.plist에 Privacy - Camera Usage Description 추가

  • create 연산자를 이용하여 wrapping
import RxSwift
import RxCocoa
import AVFoundation

class CameraPermissionManager {
  static let shared = CameraPermissionManager()
  
  func requestCamera(mediaType: AVMediaType = .video) -> Observable<Bool> {
    Observable<Bool>.create { observable in
      AVCaptureDevice.requestAccess(for: mediaType) { isGranted in
        DispatchQueue.main.async {
          observable.onNext(isGranted)
          observable.onCompleted()
        }
      }
      return Disposables.create()
    }
  }
}

* 전체 코드: https://github.com/JK0369/ExPhotoPermission

Comments