Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> iOS

Cách yêu cầu quyền vị trí (Location Permission) tại runtime trong iOS

Để yêu cầu quyền vị trí, dùng CLLocationManager của Apple. iOS hỗ trợ 2 mức độ:

  • When In Use (Khi sử dụng app): Truy cập vị trí khi app đang foreground
  • Always (Luôn luôn): Truy cập vị trí cả khi app background

Bài này tập trung vào When In Use (phổ biến nhất).

Các bước thực hiện

Bước 1: Tạo dự án

Xcode → Single View App → Tên: "LocationServices".

Bước 2: Thêm Button trên Storyboard

Mở Main.storyboard → Thêm Button "Get Location" → Tạo @IBAction btnGetLocation.

Cách yêu cầu quyền vị trí (Location Permission) tại runtime trong iOS

Bước 3: Import CoreLocation

import CoreLocation

Bước 4: Cấu hình Info.plist (BẮT BUỘC)

Right-click Info.plist → Add Row:

  • Key: NSLocationWhenInUseUsageDescription (String)
  • Value: "App cần truy cập vị trí để hiển thị địa điểm gần bạn"

Nếu cần Always permission, thêm thêm:

  • Key: NSLocationAlwaysAndWhenInUseUsageDescription

Cách yêu cầu quyền vị trí (Location Permission) tại runtime trong iOS

Bước 5: Tạo CLLocationManager instance


class ViewController: UIViewController {
    let locationManager = CLLocationManager()
    // ...
}

Bước 6: Xử lý logic trong Button Action


@IBAction func btnGetLocation(_ sender: Any) {
    let status = CLLocationManager.authorizationStatus()
    
    switch status {
    case .notDetermined:
        // Chưa từng hỏi → Request permission
        locationManager.requestWhenInUseAuthorization()
        
    case .denied, .restricted:
        // User từ chối hoặc bị hạn chế (parental control)
        showLocationDisabledAlert()
        
    case .authorizedWhenInUse, .authorizedAlways:
        // Đã có quyền → Bắt đầu cập nhật vị trí
        startLocationUpdates()
        
    @unknown default:
        break
    }
}

func showLocationDisabledAlert() {
    let alert = UIAlertController(
        title: "Dịch vụ vị trí đã tắt",
        message: "Vui lòng bật dịch vụ vị trí trong Cài đặt → Privacy → Location Services",
        preferredStyle: .alert
    )
    alert.addAction(UIAlertAction(title: "OK", style: .default))
    alert.addAction(UIAlertAction(title: "Mở Cài đặt", style: .default) { _ in
        self.openSettings()
    })
    present(alert, animated: true)
}

func openSettings() {
    guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
    UIApplication.shared.open(url)
}

func startLocationUpdates() {
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.startUpdatingLocation()
}

Bước 7: Implement CLLocationManagerDelegate


extension ViewController: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        print("Latitude: \(location.coordinate.latitude)")
        print("Longitude: \(location.coordinate.longitude)")
        
        // Dừng update nếu chỉ cần vị trí một lần
        locationManager.stopUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("Location error: \(error.localizedDescription)")
    }
    
    // iOS 14+: Delegate khi authorization thay đổi
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        let status = manager.authorizationStatus
        if status == .authorizedWhenInUse || status == .authorizedAlways {
            startLocationUpdates()
        }
    }
}

Mã hoàn chỉnh


import UIKit
import CoreLocation

class ViewController: UIViewController {
    
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
    }
    
    @IBAction func btnGetLocation(_ sender: Any) {
        let status = CLLocationManager.authorizationStatus()
        
        switch status {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .denied, .restricted:
            showLocationDisabledAlert()
        case .authorizedWhenInUse, .authorizedAlways:
            startLocationUpdates()
        @unknown default:
            break
        }
    }
    
    func startLocationUpdates() {
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()
    }
    
    func showLocationDisabledAlert() {
        let alert = UIAlertController(title: "Dịch vụ vị trí đã tắt", 
                                      message: "Vui lòng bật trong Cài đặt", 
                                      preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default))
        alert.addAction(UIAlertAction(title: "Mở Cài đặt", style: .default) { _ in
            self.openSettings()
        })
        present(alert, animated: true)
    }
    
    func openSettings() {
        guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
        UIApplication.shared.open(url)
    }
}

extension ViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let loc = locations.last else { return }
        print("Lat: \(loc.coordinate.latitude), Lng: \(loc.coordinate.longitude)")
        manager.stopUpdatingLocation()
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        let status = manager.authorizationStatus
        if status == .authorizedWhenInUse || status == .authorizedAlways {
            startLocationUpdates()
        }
    }
}

Kết quả chạy

Lần đầu chạy → Hiện dialog xin quyền → User cho phép → In ra lat/lng.

Cách yêu cầu quyền vị trí (Location Permission) tại runtime trong iOS

Lưu ý quan trọng

  • Info.plist key **bắt buộc** - thiếu sẽ crash khi request
  • Luôn check locationServicesEnabled() trước khi request
  • iOS 14+: User chọn "Precise" hoặc "Approximate" - app phải handle cả 2
  • Background location: Cần capability "Location updates" + reason mạnh mẽ cho App Store review
  • Test trên thiết bị thật - Simulator location giả lập