Yêu cầu quyền truy cập thông tin vị trí

Để bảo vệ quyền riêng tư của người dùng, các ứng dụng dùng dịch vụ vị trí phải yêu cầu quyền truy cập thông tin vị trí.

Khi bạn yêu cầu quyền truy cập thông tin vị trí, hãy làm theo các phương pháp hay nhất giống như với mọi quyền khi bắt đầu chạy khác. Một khác biệt quan trọng khi nói đến quyền truy cập thông tin vị trí là hệ thống bao gồm nhiều quyền liên quan đến vị trí. Quyền mà bạn yêu cầu và cách bạn yêu cầu quyền đó phụ thuộc vào các yêu cầu về vị trí đối với trường hợp sử dụng của ứng dụng.

Trang này mô tả nhiều loại yêu cầu về vị trí và đưa ra hướng dẫn về cách yêu cầu quyền truy cập thông tin vị trí trong từng trường hợp.

Loại quyền truy cập thông tin vị trí

Mỗi quyền có một tổ hợp đặc điểm sau:

Quyền truy cập thông tin vị trí ở chế độ nền trước

Nếu ứng dụng của bạn chứa một tính năng chỉ chia sẻ hoặc nhận thông tin vị trí một lần hoặc trong một khoảng thời gian xác định, thì tính năng đó sẽ yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trước. Sau đây là một số ví dụ:

  • Trong ứng dụng tìm đường, một tính năng cho phép người dùng xem đường đi từng chặng.
  • Trong ứng dụng nhắn tin, một tính năng cho phép người dùng chia sẻ vị trí hiện tại của mình với người dùng khác.

Hệ thống sẽ coi ứng dụng của bạn đang sử dụng thông tin vị trí ở chế độ nền trước nếu một tính năng của ứng dụng truy cập vào vị trí hiện tại của thiết bị ở một trong các tình huống sau:

  • Một hoạt động thuộc ứng dụng của bạn đang hiển thị.
  • Ứng dụng của bạn đang chạy một dịch vụ trên nền trước. Khi một dịch vụ trên nền trước đang chạy, hệ thống sẽ báo cho người dùng biết bằng cách hiển thị một thông báo liên tục. Ứng dụng của bạn vẫn giữ quyền truy cập khi được đặt vào chế độ nền, chẳng hạn như khi người dùng nhấn nút Màn hình chính trên thiết bị hoặc tắt màn hình thiết bị.

    Ngoài ra, bạn nên khai báo loại dịch vụ trên nền trướclocation, như được minh hoạ trong đoạn mã sau. Trên Android 10 (API cấp 29) trở lên, bạn phải khai báo loại dịch vụ trên nền trước này.

    <!-- Recommended for Android 9 (API level 28) and lower. -->
    <!-- Required for Android 10 (API level 29) and higher. -->
    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        <!-- Any inner elements would go here. -->
    </service>

Bạn khai báo nhu cầu về thông tin vị trí ở chế độ nền trước khi ứng dụng yêu cầu cấp quyền ACCESS_COARSE_LOCATION hoặc quyền ACCESS_FINE_LOCATION, như hiển thị trong đoạn mã sau:

<manifest ... >
  <!-- Always include this permission -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Include only if your app benefits from precise location access. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

Quyền truy cập thông tin vị trí ở chế độ nền

Ứng dụng sẽ yêu cầu quyền truy cập thông tin vị trí ở chế độ nền nếu một tính năng trong ứng dụng đó liên tục chia sẻ vị trí với người dùng khác hoặc sử dụng (Geofencing API) API Khoanh vùng địa lý. Sau đây là một số ví dụ:

  • Trong ứng dụng chia sẻ vị trí của nhóm gia đình, một tính năng cho phép người dùng liên tục chia sẻ vị trí với thành viên gia đình.
  • Trong ứng dụng IoT, một tính năng cho phép người dùng định cấu hình các thiết bị trong nhà để tắt thiết bị khi người dùng rời khỏi nhà và bật lại khi người dùng trở về nhà.

Hệ thống sẽ coi ứng dụng của bạn đang sử dụng thông tin vị trí ở chế độ nền nếu ứng dụng truy cập vào thông tin vị trí hiện tại của thiết bị trong bất kỳ tình huống nào trừ những tình huống được mô tả trong phần thông tin vị trí ở chế độ nền trước. Độ chính xác của vị trí ở chế độ nền giống như độ chính xác của vị trí ở chế độ nền trước, tuỳ thuộc vào quyền truy cập thông tin vị trí mà ứng dụng của bạn khai báo.

Trên Android 10 (API cấp 29) trở lên, bạn phải khai báo ACCESS_BACKGROUND_LOCATIONquyền trong tệp kê khai của ứng dụng để yêu cầu quyền truy cập thông tin vị trí ở chế độ nền trong thời gian chạy. Trên các phiên bản Android cũ, khi ứng dụng nhận được quyền truy cập thông tin vị trí ở chế độ nền trước, ứng dụng đó cũng tự động nhận được quyền truy cập thông tin vị trí ở chế độ nền.

<manifest ... >
  <!-- Required only when requesting background location access on
       Android 10 (API level 29) and higher. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>

Độ chính xác

Android hỗ trợ độ chính xác của vị trí ở mức độ sau:

Gần đúng
Cung cấp thông tin vị trí ước tính của thiết bị. Nếu thông tin vị trí ước tính này là từ LocationManagerService hoặc FusedLocationProvider, thì ước tính này sẽ chính xác trong phạm vi khoảng 3 kilômét vuông (khoảng 1,2 dặm vuông). Ứng dụng của bạn có thể nhận được thông tin vị trí ở mức độ chính xác này khi bạn khai báo quyền ACCESS_COARSE_LOCATION chứ không phải quyền ACCESS_FINE_LOCATION.
Chính xác
Cung cấp thông tin vị trí ước tính của thiết bị một cách chính xác nhất có thể. Nếu thông tin vị trí ước tính là từ LocationManagerService hoặc FusedLocationProvider, thì ước tính này thường nằm trong phạm vi khoảng 50 mét (160 feet) và đôi khi chính xác nhất là trong phạm vi vài mét (10 feet). Ứng dụng của bạn có thể nhận được thông tin vị trí ở mức độ chính xác này khi bạn khai báo quyền ACCESS_FINE_LOCATION.

Nếu người dùng cấp quyền truy cập thông tin vị trí gần đúng, thì ứng dụng của bạn chỉ có quyền truy cập thông tin vị trí gần đúng, bất kể ứng dụng đó khai báo quyền truy cập thông tin vị trí nào.

Ứng dụng của bạn sẽ vẫn hoạt động khi người dùng chỉ cấp quyền truy cập thông tin vị trí gần đúng. Nếu một tính năng trong ứng dụng của bạn tuyệt đối yêu cầu quyền truy cập thông tin vị trí chính xác thông qua quyền ACCESS_FINE_LOCATION, thì bạn có thể yêu cầu người dùng cho phép ứng dụng của bạn truy cập vào vị trí chính xác.

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

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.
locationPermissionRequest.launch(arrayOf(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION))

Java

ActivityResultLauncher<String[]> locationPermissionRequest =
    registerForActivityResult(new ActivityResultContracts
        .RequestMultiplePermissions(), result -> {
            Boolean fineLocationGranted = result.getOrDefault(
                    Manifest.permission.ACCESS_FINE_LOCATION, false);
            Boolean 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 4hì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á chức 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.

Yêu cầu quyền truy cập thông tin vị trí ở chế độ nền nếu cần

Hình 7. Trang Cài đặt có một tuỳ chọn tên là Luôn cho phép. Tuỳ chọn này cấp quyền truy cập thông tin vị trí ở chế độ nền.

Nội dung của hộp thoại cấp quyền phụ thuộc vào phiên bản SDK mục tiêu

Khi một 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í ở chế độ nền trên một thiết bị chạy Android 10 (API cấp 29), hộp thoại cấp quyền của hệ thống sẽ bao gồm một tuỳ chọn có tên là Luôn cho phép. Nếu người dùng chọn tuỳ chọn này, tính năng trong ứng dụng của bạn sẽ có quyền truy cập thông tin vị trí ở chế độ nền.

Tuy nhiên, trên Android 11 (API cấp 30) trở lên, hộp thoại của hệ thống sẽ không bao gồm tuỳ chọn Luôn cho phép. Thay vào đó, người dùng phải bật quyền truy cập thông tin vị trí ở chế độ nền trên trang cài đặt, như minh hoạ trong hình 7.

Bạn có thể giúp người dùng chuyển đến trang cài đặt này bằng cách làm theo các phương pháp hay nhất khi yêu cầu quyền truy cập thông tin vị trí ở chế độ nền. Quy trình cấp quyền này phụ thuộc vào phiên bản SDK mục tiêu của ứng dụng.

Ứng dụng nhắm đến Android 11 trở lên

Nếu ứng dụng của bạn chưa được cấp quyền ACCESS_BACKGROUND_LOCATIONshouldShowRequestPermissionRationale() trả về true, hãy hiển thị cho người dùng một giao diện người dùng hướng dẫn bao gồm:

  • Nội dung giải thích rõ lý do tính năng của ứng dụng cần quyền truy cập thông tin vị trí ở chế độ nền.
  • Nhãn mà người dùng nhìn thấy của chế độ cài đặt cấp quyền truy cập thông tin vị trí ở chế độ nền (ví dụ: Luôn cho phép trong hình 7). Bạn có thể gọi getBackgroundPermissionOptionLabel() để lấy nhãn này. Giá trị trả về của phương thức này sẽ được bản địa hoá sang ngôn ngữ mà người dùng ưu tiên lựa chọn trên thiết bị.
  • Một tuỳ chọn để người dùng từ chối cấp quyền. Nếu từ chối cấp quyền truy cập thông tin vị trí ở chế độ nền, thì người dùng vẫn có thể dùng ứng dụng của bạn.
Người dùng có thể nhấn vào thông báo hệ thống để thay đổi chế độ cài đặt vị trí cho một ứng dụng
Hình 8. Thông báo nhắc người dùng rằng họ đã cấp cho một ứng dụng quyền truy cập thông tin vị trí ở chế độ nền.

Ứng dụng nhắm đến Android 10 trở xuống

Khi một 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í ở chế độ nền, người dùng sẽ thấy một hộp thoại của hệ thống. Hộp thoại này có một tuỳ chọn để chuyển đến các tuỳ chọn cấp quyền truy cập thông tin vị trí cho ứng dụng trên trang cài đặt.

Miễn là ứng dụng của bạn đã làm theo các phương pháp hay nhất để yêu cầu quyền truy cập thông tin vị trí, thì bạn không cần thực hiện thay đổi nào để hỗ trợ hành vi này.

Người dùng có thể ảnh hưởng đến độ chính xác của vị trí ở chế độ nền

Nếu người dùng yêu cầu vị trí gần đúng, thì các lựa chọn của người dùng trong hộp thoại cấp quyền truy cập thông tin vị trí cũng áp dụng cho quyền truy cập thông tin vị trí ở chế độ nền. Nói cách khác, nếu người dùng cấp cho ứng dụng của bạn quyền ACCESS_BACKGROUND_LOCATION nhưng chỉ cấp quyền truy cập thông tin vị trí gần đúng ở chế độ nền trước, thì ứng dụng của bạn cũng chỉ có quyền truy cập thông tin vị trí gần đúng ở chế độ nền.

Nhắc nhở cấp quyền truy cập thông tin vị trí ở chế độ nền

Trên Android 10 trở lên, khi một tính năng trong ứng dụng của bạn truy cập thông tin vị trí ở chế độ nền lần đầu tiên sau khi người dùng cấp quyền truy cập thông tin vị trí ở chế độ nền, hệ thống sẽ lên lịch gửi thông báo cho người dùng. Thông báo này nhắc người dùng rằng họ đã luôn cho phép ứng dụng của bạn truy cập vào thông tin vị trí của thiết bị. Hình 8 minh hoạ một thông báo mẫu.

Kiểm tra các yêu cầu về vị trí trong phần phụ thuộc SDK của ứng dụng

Kiểm tra xem ứng dụng của bạn có dùng SDK nào phụ thuộc vào quyền truy cập thông tin vị trí hay không, đặc biệt là quyền ACCESS_FINE_LOCATION. Hãy tham khảo bài viết này trên Medium để Tìm hiểu hành vi của các phần phụ thuộc SDK.

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í.