Để 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.

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

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.

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