[iOS] MapKit Privacy & Authorization

린다·2021년 10월 20일
0

Learning iOS

목록 보기
5/13
post-thumbnail

Info.plist(권한 설정)

사용자의 정보를 사용하기 위해서는 가장 먼저 plist에 사용자 권한을 얻어야 하는 부분과 멘트를 추가해야합니다. 위치 관련 데이터는 Privacy - Location까지 검색하면 사용 가능한 항목들을 확인할 수 있습니다.
권한 설정은 굉장히 중요한 부분인데 꼭 필요한 부분만 설정해야합니다. 필요하지 않은 부분에 대한 권한을 설정하거나 권한에 대한 자세한 설명(Description)이 없을 경우 앱 출시 시 리젝의 사유가 될 수 있다고 합니다🥲

  • Privacy - Location When In Use Usage Description
    (iOS11 이상) iOS 앱이 포그라운드에서 실행 중인 경우에만 위치 정보에 엑세스하는 경우
  • Privacy - Location Always and When In Use Usage Description
    (iOS11 이상) 앱이 백그라운드에서 위치 정보에 엑세스하는 경우
  • Privacy - Location Default Accuracy Reduced
    (iOS14 이상) Bool Type으로 기본적으로 앱이 정확도가 떨어지는 위치를 요구하는지 설정할 수 있음
    → true: 모든 Core Location 서비스가 reduced-accuracy level로 정보를 제공받음
    → false: 값을 false로 설정하면 자세한 위치 정보를 묻는 메세지를 표시할 수 있음
  • 키 값을 따로 설정하지 않으면 기본으로 false가 설정돼있음.
  • Privacy - Location Temporary Usage Description Dictionary
    (iOS14 이상) Dictionary Type으로 앱이 유저의 위치에 일시적인 엑세스를 요청하는 이유에 대한 메세지의 collection
    → 주변 친구들 찾기와 같은 기능을 사용하는 경우
    "friends":"Your location is used to connect with nearby friends"와 같이 키를 추가해줄 수 있음
    → 엑세스를 요청하는 경우 requestTemporaryFullAccuracyAuthorization(withPurposeKey:) 메서드에 필요한 key를 제공함으로써 접근할 수 있음
// Request location access to find coffee shops.
manager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: "friends")
  • Privacy - Location Always Usage Description
    Deprecated(iOS11 이전의 대상에 배포하는 경우)
  • Privacy - Location Usage Description
    macOS앱 개발 시 사용

1. CLLocationManager()

앱으로 위치 관련 이벤트 전달을 시작하거나 멈추는데 사용하는 개체

The object that you use to start and stop the delivery of location-related events to your app.

위치와 관련된 이벤트를 제어하는데 사용되는 CLLocationManager class를 사용하기 위해서 먼저 인스턴스를 생성해주고 locationManager에 할당해줍니다.

let locationManager = CLLocationManager()

delegate도 선언해줍니다.

locationManager.delegate = self

2. CLLocationManagerDelegate

extension을 통해 delegate 프로토콜을 채택해줍니다.

extension LocationViewController: CLLocationManagerDelegate {
}

3. (위치 서비스가 켜져있는 경우) 사용자 권한 확인

사용자가 위치 서비스를 사용하는 경우(일반 설정에서 위치 서비스 사용 on인 상태) CLAuthorizationStatus를 통해 사용자 권한을 확인하고 각 Case별로 해야할 일을 처리해줘야합니다.

3-1. CLAuthorizationStatus

사용자 권한 승인 상태는 총 5가지로 나뉩니다.
1. case notDetermined
사용자가 위치 권한 허용 여부를 아직 선택하지 않은 경우
2. case restricted
앱이 위치 서비스를 사용할 권한이 없는 경우
→ 주로 보호자 통제 모드로 인해 사용자가 앱의 허용 권한을 변경할 수 없는 경우
3. case denied
사용자가 권한 요청 얼럿창에서 거절을 선택한 경우
→ 허용 선택 후 추후에 설정에서 비활성화 한 경우
→ 거부한 경우
→ 위치 서비스 자체를 사용 중지한 경우
→ 비행기 모드로 인해 위치 서비스를 사용할 수 없는 상태
4. case authorizedAlways
언제든지 위치 서비스를 사용할 수 있도록 승인한 상태(백그라운드 포함)
5. case authorizedWhenInUse
앱을 사용하는 동안에만 위치 서비스를 사용할 수 있도록 허용한 상태

  • 사용자 권한 확인 및 각 케이스별로 처리해주기 위해서 프로토콜 내에 정의된 메서드를 불러오는 것이 아니라 사용자 정의 함수를 구현해줍니다.
    func checkCurrentLocationAuthorization(_ authorizationStatus: CLAuthorizationStatus) {
        switch authorizationStatus {
        case .notDetermined:
            // 앱이 받고 싶어하는 위치 데이터의 정확도 설정
            // 이 설정은 배터리 사용량에도 영향을 미친다. 그러니 사용용도에 적합한 value를 할당하는 것이 중요함
            // 설정하지 않으면 KCLLocationAuccracyBest가 default값으로 적용됨
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            // 앱을 사용하는 동안에 대한 위치 권한 요청(위치 권한 띄우기)
            // 해당 메서드는 현재 authorization status가 not determined 상태일 때 부르는 것이 적합함
            locationManager.requestWhenInUseAuthorization()
            // 반드시 들어가야함. 위치 접근 시작~ 사용자 위치를 얻어주세요~ 시작해주세요~
            // 이 메서드를 실행하면 초기 위치 수정 사항에 대해 가져오고
            // didUpdateLocations 메서드를 통해 delegate에게 알려준다.
            locationManager.startUpdatingLocation()
        case .restricted, .denied:
            // 보통 이 부분에서 alert창을 이용해 설정으로 이동시키는 코드를 구현함
            print("denied, 설정으로 유도")
        case .authorizedWhenInUse:
            // 앱을 사용하는 동안만, 위치 접근 시작 => didUpdateLocations 실행
            locationManager.startUpdatingLocation()
        case .authorizedAlways:
            print("always")
        @unknown default:
            print("default")
        }
     }

3-2. CLAccuracyAuthorization

enum CLAccuracyAuthorization : Int
  • iOS14 이상에서 사용 가능합니다.
  • 위치 정확도 수준을 나타내는 Int 타입
    1. fullAccuracy
    사용자가 위치 데이터에 최대한 정확하게 엑세스할 수 있도록 권한을 부여한 경우
    2. reducedAccuracy
    사용자가 위치 데이터에 엑세스할 수 있는 정확도를 낮춰서 권한을 부여한 경우
        if #available(iOS 14.0, *) {
            let accurancyState = locationManager.accuracyAuthorization
            
            switch accurancyState {
            case .fullAccuracy:
                print("Full")
            case .reducedAccuracy:
                print("reduced")
            @unknown default:
                print("DEFAULT")
            }
        }

4. 위치서비스가 켜져있는지 확인 (분기 처리)

iOS 버전에 따른 분기 처리와 iOS 위치 서비스 여부 확인

    func checkUserLocationServicesAuthorization() {
        let authorizationStatus: CLAuthorizationStatus
        
        if #available(iOS 14.0, *) {
            authorizationStatus = locationManager.authorizationStatus // iOS14 이상
        } else {
            authorizationStatus = CLLocationManager.authorizationStatus() // iOS14 미만
        }
        
        // iOS 위치 서비스 확인
        if CLLocationManager.locationServicesEnabled() {
        // 만약 사용자가 위치 서비스를 사용하고 있다면 위치 권한을 확인 후 이에 맞는 메서드를 실행한다.
            // 권한 상태 확인 및 권한 요청 가능
            checkCurrentLocationAuthorization(authorizationStatus)
        } else {
            // iOS 위치 권한을 허락해달라는 alert 띄우기
            print("iOS 위치 서비스 켜주세요")
        }
    }

5. 권한 상태가 변경될 때 실행되는 메서드

아래 두 메서드는 사용자가 권한 상태를 변경할 때 마다 실행되는 메서드입니다.

    // 6. iOS14 미만: 앱이 위치 관리자를 생성하고, 승인 상태가 변경이 될 때 대리자에게 승인 상태를 알려줌
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        print(#function)
        checkUserLocationServicesAuthorization()
    }
    
    // 7. iOS14 이상: 앱이 위치 관리자를 생성하고, 승인 상태가 변경이 될 때 대리자에게 승인 상태를 알려줌
    // 14부터 정확도에 대한 내용이 추가됨
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        print(#function)
        checkUserLocationServicesAuthorization() // viewDidLoad에서 실행하지않음!
    }

6. 사용자가 위치 사용을 허락한 경우, 현재 위치로 mapView 변경

 // 4. 사용자가 위치 허용을 한 경우
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print(#function)
        print(locations)
        
        if let coordinate = locations.last?.coordinate {
            let annotation = MKPointAnnotation()
            annotation.title = "CURRENT LOCATION"
            annotation.coordinate = coordinate
            mapView.addAnnotation(annotation)
            
            // 지도의 중심 바꾸기
            let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
            let region = MKCoordinateRegion(center: coordinate, span: span)
            mapView.setRegion(region, animated: true)
            
            // 10. (중요) 업데이트가 너무 많이 되는 경우, 비효율적 -> 업데이트 멈춰달라고 요청
            // 비슷한 반경에서!
            locationManager.stopUpdatingLocation()
        } else {
            print("Location Can not find")
        }
    }

7. 위치 접근이 실패한 경우

// 5. 위치 접근이 실패했을 경우
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(#function)
    }

0개의 댓글