iOS

[Swift] 권한 요청 사용 + 구현하기 (feat. SwiftUI)

GODOLs 2023. 12. 1. 17:15

 

 

[Swift] 권한 요청 정리

iOS를 개발하면서 외부 장치에 대한 권한을 요청해야하는 경우가 있습니다. 그래서 권한을 어떤 상황에서 어떻게 사용되는지 그리고 어떻게 함수로 구현했는지 정리해보겠습니다. 1.위치권한

development.godol.kr

이전글에 이어 권한 요청을 구현해 보겠습니다. 

사용하는 개발자 마다 다르지만 저는 앱설치 후 첫화면의 ViewModel을 만들어 사용하는게 편리하여 사용하고 있습니다.
만약 첫 화면에서 허용을 누르지 않더라도 기능을 사용할 때 사용 할 수 있도록 ViewModel로 관리하는게 좋아 보였습니다.

 

Info.plist 설정

각 Permission을 받기 위해 사용 용도를 적으면 됩니다. 각 앱에 어떤 기능에서 사용될 것인지 서술하시면 됩니다.

View 구조

import SwiftUI

struct ContentView: View {
    
    @StateObject var permissionViewModel = PermissionViewModel()
    
    var body: some View {
        
        VStack{
            Text("앱 시작 ㄱㄱ")
        }
        //앱 시작전에 권한 설정을 요청하는 FullScreenCover를 구현해보겠습니다. 이게 False가 되어야 앱을 사용할 수 있도록 합니다.
        .fullScreenCover(isPresented: $permissionViewModel.permissionNotCompleted, content: {
            VStack {
                Text("어서오세요 앱 시작하기전에 권한을 추가 해볼까요?")
               Button(action: {
                   permissionViewModel.requestPermission()
               }, label: {
                   RoundedRectangle(cornerRadius: 10)
                       .overlay(
                        Text("권한 추가")
                            .foregroundColor(.white)
                       )
                       .foregroundColor(.mint)
               })
               .frame(width: 100,height: 50)
            }
            .padding()
        })
        
        
    }
}
  1. 로그인 화면이나, 앱 최초 시작시 진행하면 됩니다. 
  2. FullScreenCover를 사용하여 조건(Permission이 대한 절차가 완료되면 사라지도록) 하는 상태 변수를 Binding 합니다. (ViewModel에 @Published 변수로 사용하고 있습니다.)

 

ViewModel 구조

import Foundation
import AVFoundation
import Photos
import PhotosUI
import Contacts

class PermissionViewModel : ObservableObject{
    
    // 첫 화면에서 1회용으로 사용할 것이기 떄문에 UserDefaults를 사용합니다.
    @Published var permissionNotCompleted: Bool {
        didSet {
            UserDefaults.standard.set(permissionNotCompleted, forKey: "PermissionNotCompleted")
        }
    }
    
    init() {
        // UserDefaults에서 값을 가져오고, 값이 없으면 true로 설정합니다.
        self.permissionNotCompleted = UserDefaults.standard.object(forKey: "PermissionNotCompleted") as? Bool ?? true
    }
    
    // 권한 요청 시작
    func requestPermission() {
        requestAccessCamera()
    }
    // 카메라 권한 요청
    func requestAccessCamera(){
        AVCaptureDevice.requestAccess(for: .video) { granted in
            self.requestAccessAlbum()
        }
    }
    // 엘범 권한 요청
    func requestAccessAlbum(){
        PHPhotoLibrary.requestAuthorization(){ granted in
            
            switch granted {
            case .authorized:
                // 허용 되었을 때 필요한 부분 추가
                print("Album: 권한 허용")
            case .denied:
                // 허용거부 했을 때 필요한 부분 추가
                print("Album: 권한 거부")
            case .restricted, .notDetermined:
                print("Album: 선택하지 않음")
            default:
                break
            }
            self.requestAccessAudio()
        }
    }
    // 오디오 권한 요청
    func requestAccessAudio() {
        AVCaptureDevice.requestAccess(for: .audio, completionHandler: { accessGranted in
            self.requestMicrophonePermission()
        })
    }
    // 마이크 권한 요청
    func requestMicrophonePermission() {
        AVAudioSession.sharedInstance().requestRecordPermission { granted in
            DispatchQueue.main.async {
                if granted {
                    // 허용 되었을 때 필요한 부분 추가
                    self.requestContact()
                } else {
                    // 허용거부 했을 때 필요한 부분 추가
                    self.requestContact()
                }
            }
        }
    }
    // 연락처 권한 요청
    func requestContact() {
        let status = CNContactStore.authorizationStatus(for: .contacts)
        if status == .notDetermined {
            CNContactStore().requestAccess(for: .contacts) { (authorized, error) in
                if !authorized {
                    // 허용 되었을 때 필요한 부분 추가
                    self.complete()
                }else {
                    // 허용거부 했을 때 필요한 부분 추가
                    self.complete()
                }
            }
        }
    }
    // 완료되면 FullScreen을 내리기 위해 false로 처리
    func complete() {
        self.permissionNotCompleted = false
    }
}
  1. import를 합니다. 각 모듈과 관련있는 부분을 import를 하면 됩니다. 
  2. View에 최초로 권한 요청을 위한 변수(여기서는 permissionNotCompleted)를 둡니다. UserDefaults 를 이용하여 한번 사용한 권한 함수는 다시 사용되지 않을 것입니다.
  3. 권한 요청을 시작합니다. 원하시는 순서가 있다면 그 순서대로 바꾸면 됩니다. 
    저는 카메라 -> 앨범 -> 오디오 -> 마이크 -> 연락처 순서대로 추가했습니다. 
  4. 더 필요한 권한이 있다면 언제든지 함수를 추가하여 사용하면 됩니다.
  5. 마지막으로 완성이 되었다면 permissionNotCompleted 변수를 false로 만들어 다음에 앱을 실행하더라도 권한 화면이 나오지 않도록 막습니다.

구현화면

순차적으로 원하는대로 접근 권한을 요청했습니다.

 

앱의 기능을 사용할 때 앱 최초 실행시 온보딩과 동시에 권한을 요청할때가 많습니다. 이런 방식으로 진행하신다면 조금 관리가 더 편하다고 생각합니다. 

반응형