Yêu cầu quyền truy cập thông tin vị trí trong thời gian chạy

Khi một tính năng trong ứng dụng của bạn cần có quyền truy cập thông tin vị trí, hãy đợi cho đến khi người dùng tương tác với tính năng đó rồi mới đưa ra yêu cầu cấp quyền. Quy trình công việc này tuân theo các phương pháp hay nhất để yêu cầu quyền khi bắt đầu chạy trong ngữ cảnh, như mô tả trong hướng dẫn giải thích cách yêu cầu quyền cho ứng dụng.

Hình 1 cho thấy ví dụ về cách thực hiện quy trình này. Ứng dụng chứa một tính năng "chia sẻ vị trí" yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước. Tuy nhiên, ứng dụng chỉ yêu cầu quyền truy cập thông tin vị trí khi người dùng chọn nút Chia sẻ thông tin vị trí.

Sau khi người dùng chọn nút Chia sẻ vị trí, hộp thoại cấp quyền truy cập thông tin vị trí của hệ thống xuất hiện
Hình 1. Tính năng chia sẻ vị trí yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước. Tính năng này sẽ được bật nếu người dùng chọn Chỉ cho phép khi dùng ứng dụng.

Người dùng chỉ có thể cấp quyền truy cập thông tin vị trí gần đúng

Trên Android 12 (API cấp 31) trở lên, người dùng có thể yêu cầu ứng dụng của bạn chỉ truy xuất thông tin vị trí gần đúng, ngay cả khi ứng dụng đó yêu cầu quyền khi bắt đầu chạy ACCESS_FINE_LOCATION.

Để xử lý hành vi tiềm ẩn này của người dùng, đừng yêu cầu quyền ACCESS_FINE_LOCATION. Thay vào đó, hãy yêu cầu cả quyền ACCESS_FINE_LOCATION và quyền ACCESS_COARSE_LOCATION trong một yêu cầu thời gian chạy duy nhất. Nếu bạn chỉ cố yêu cầu ACCESS_FINE_LOCATION, hệ thống sẽ bỏ qua yêu cầu này trên một số bản phát hành của Android 12. Nếu ứng dụng của bạn nhắm đến Android 12 trở lên, hệ thống sẽ ghi lại thông báo lỗi sau trong Logcat:

ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION.

Khi ứng dụng của bạn yêu cầu cả ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION, hộp thoại cấp quyền của hệ thống sẽ bao gồm các tuỳ chọn sau cho người dùng:

  • Chính xác: Cho phép ứng dụng của bạn lấy thông tin vị trí chính xác.
  • Gần đúng: Cho phép ứng dụng của bạn chỉ lấy thông tin vị trí gần đúng.

Hình 3 minh hoạ hộp thoại chứa một chỉ dẫn hình ảnh cho cả hai tuỳ chọn để giúp người dùng chọn. Sau khi quyết định về độ chính xác của vị trí, người dùng nhấn vào một trong 3 nút để chọn khoảng thời gian cấp quyền.

Trên Android 12 trở lên, người dùng có thể chuyển đến phần cài đặt hệ thống để đặt độ chính xác vị trí ưu tiên cho các ứng dụng, bất kể phiên bản SDK mục tiêu của ứng dụng đó là gì. Điều này xảy ra ngay cả khi ứng dụng của bạn được cài đặt trên một thiết bị chạy Android 11 trở xuống, sau đó người dùng nâng cấp thiết bị lên Android 12 trở lên.

Hộp thoại chỉ đề cập đến vị trí gần đúng và có 3 nút, lần lượt nằm phía trên nhau
Hình 2. Hộp thoại cấp quyền của hệ thống xuất hiện khi ứng dụng của bạn chỉ yêu cầu ACCESS_COARSE_LOCATION.
Hộp thoại có 2 nhóm tuỳ chọn, lần lượt nằm phía trên nhau
Hình 3. Hộp thoại cấp quyền của hệ thống xuất hiện khi ứng dụng của bạn yêu cầu cả ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION trong một yêu cầu thời gian chạy.

Lựa chọn của người dùng sẽ ảnh hưởng đến các quyền được cấp

Bảng sau đây cho thấy các quyền mà hệ thống cấp cho ứng dụng của bạn, dựa trên các tuỳ chọn mà người dùng chọn trong hộp thoại cấp quyền khi bắt đầu chạy:

Chính xác Gần đúng
Trong khi dùng ứng dụng ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
ACCESS_COARSE_LOCATION
Chỉ lần này ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
ACCESS_COARSE_LOCATION
Từ chối Không có quyền truy cập thông tin vị trí Không có quyền truy cập thông tin vị trí

Để xác định những quyền mà hệ thống đã cấp cho ứng dụng của bạn, hãy kiểm tra giá trị trả về của yêu cầu cấp quyền của bạn. Bạn có thể dùng thư viện Jetpack trong mã tương tự như sau, hoặc bạn có thể dùng thư viện nền tảng, trong đó bạn tự quản lý mã yêu cầu cấp quyền.

Kotlin

@RequiresApi(Build.VERSION_CODES.N)
fun requestPermissions() {
    val locationPermissionRequest = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        when {
            permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
                // Precise location access granted.
            }
            permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
                // Only approximate location access granted.
            }
            else -> {
                // No location access granted.
            }
        }
    }

    // Before you perform the actual permission request, check whether your app
    // already has the permissions, and whether your app needs to show a permission
    // rationale dialog. For more details, see Request permissions:
    // https://developer.android.com/training/permissions/requesting#request-permission
    locationPermissionRequest.launch(
        arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    )
}

Java

private void requestPermissions() {

    ActivityResultLauncher<String[]> locationPermissionRequest =
            registerForActivityResult(new ActivityResultContracts
                            .RequestMultiplePermissions(), result -> {

                Boolean fineLocationGranted = null;
                Boolean coarseLocationGranted = null;

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    fineLocationGranted = result.getOrDefault(
                            Manifest.permission.ACCESS_FINE_LOCATION, false);
                    coarseLocationGranted = result.getOrDefault(
                            Manifest.permission.ACCESS_COARSE_LOCATION,false);
                }

                if (fineLocationGranted != null && fineLocationGranted) {
                    // Precise location access granted.
                } else if (coarseLocationGranted != null && coarseLocationGranted) {
                    // Only approximate location access granted.
                } else {
                    // No location access granted.
                }
            }
        );

    // ...

    // Before you perform the actual permission request, check whether your app
    // already has the permissions, and whether your app needs to show a permission
    // rationale dialog. For more details, see Request permissions.
    locationPermissionRequest.launch(new String[] {
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
    });
}

Yêu cầu nâng cấp lên vị trí chính xác

Bạn có thể yêu cầu người dùng nâng cấp quyền truy cập của ứng dụng từ vị trí gần đúng lên vị trí chính xác. Tuy nhiên, trước khi bạn yêu cầu người dùng nâng cấp quyền truy cập của ứng dụng vào vị trí chính xác, hãy cân nhắc xem trường hợp sử dụng của ứng dụng có tuyệt đối yêu cầu mức độ chính xác này không. Nếu ứng dụng của bạn cần ghép nối thiết bị với các thiết bị ở gần qua Bluetooth hoặc Wi-Fi, hãy cân nhắc dùng tính năng ghép nối thiết bị đồng hành hoặc quyền truy cập Bluetooth, thay vì yêu cầu quyền ACCESS_FINE_LOCATION.

Để yêu cầu người dùng nâng cấp quyền truy cập thông tin vị trí của ứng dụng từ gần đúng lên chính xác, hãy làm như sau:

  1. Giải thích lý do ứng dụng của bạn cần quyền này, nếu cần.
  2. Yêu cầu lại cả quyền ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION. Vì người dùng đã cho phép hệ thống cấp quyền truy cập thông tin vị trí gần đúng cho ứng dụng của bạn nên lần này, hộp thoại của hệ thống sẽ hiển thị khác, như minh hoạ trong hình 4 và hình 5:
Hộp thoại có các tuỳ chọn &quot;Thay đổi thành vị trí chính xác&quot;, &quot;Chỉ lần này&quot; và &quot;Từ chối&quot;.
Hình 4. Người dùng từng chọn Gần đúngTrong khi dùng ứng dụng (trong hộp thoại ở hình 3).
Hộp thoại có các tuỳ chọn &quot;Chỉ lần này&quot; và &quot;Từ chối&quot;.
Hình 5. Người dùng từng chọn Gần đúngChỉ lần này (trong hộp thoại ở hình 3).

Chỉ yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước lúc ban đầu

Ngay cả khi một số tính năng trong ứng dụng của bạn yêu cầu quyền truy cập thông tin vị trí, thì một số tính năng đó có khả năng vẫn sẽ yêu cầu quyền truy cập thông tin vị trí ở chế độ nền. Do đó, ứng dụng của bạn nên thực hiện yêu cầu gia tăng đối với quyền truy cập thông tin vị trí, tức là yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước rồi yêu cầu quyền truy cập thông tin vị trí ở chế độ nền. Bằng cách thực hiện yêu cầu gia tăng, bạn sẽ mang lại cho người dùng nhiều quyền kiểm soát và sự minh bạch hơn vì họ có thể nắm rõ hơn những tính năng nào trong ứng dụng cần quyền truy cập thông tin vị trí ở chế độ nền.

Hình 6 cho thấy ví dụ về một ứng dụng được thiết kế nhằm xử lý yêu cầu gia tăng. Cả hai tính năng "hiển thị vị trí hiện tại" và "đề xuất địa điểm lân cận" đều yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước. Tuy nhiên, chỉ tính năng "đề xuất địa điểm lân cận" yêu cầu quyền truy cập thông tin vị trí ở chế độ nền.

Nút bật quyền truy cập thông tin vị trí ở chế độ nền trước được đặt cách nửa màn hình so với nút bật quyền truy cập thông tin vị trí ở chế độ nền
Hình 6. Cả hai tính năng đều yêu cầu quyền truy cập thông tin vị trí, nhưng chỉ có tính năng "đề xuất địa điểm lân cận" mới yêu cầu quyền truy cập thông tin vị trí ở chế độ nền.

Quy trình thực hiện yêu cầu gia tăng diễn ra như sau:

  1. Đầu tiên, ứng dụng của bạn phải hướng người dùng đến các tính năng yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước, chẳng hạn như tính năng "chia sẻ vị trí" trong Hình 1 hoặc tính năng "hiển thị vị trí hiện tại" trong Hình 2.

    Bạn nên tắt quyền truy cập của người dùng vào các tính năng yêu cầu quyền truy cập thông tin vị trí ở chế độ nền cho đến khi ứng dụng của bạn có quyền truy cập thông tin vị trí ở chế độ nền trước.

  2. Sau đó, khi người dùng khám phá các tính năng yêu cầu quyền truy cập thông tin vị trí ở chế độ nền, bạn có thể yêu cầu quyền truy cập thông tin vị trí ở chế độ nền.

Tài nguyên khác

Để biết thêm thông tin về quyền truy cập thông tin vị trí trong Android, hãy xem các tài liệu sau:

Lớp học lập trình

Video

Mẫu

  • Ứng dụng mẫu để minh hoạ việc sử dụng quyền truy cập thông tin vị trí.