AndroidManifest Permissions là các khai báo quyền trong tệp AndroidManifest.xml xác định ứng dụng có thể truy cập vào những tài nguyên và dữ liệu hệ thống nào. Android yêu cầu mỗi quyền phải được khai báo trong tệp kê khai trước khi sử dụng API tương ứng: từ máy ảnh và định vị địa lý đến gửi SMS và truy cập danh bạ. Theo Tài liệu dành cho nhà phát triển Android, mỗi quyền thuộc một trong bốn cấp độ bảo vệ: normal, dangerous, signature và special.
Những điểm chính
AndroidManifest Permissions là cơ chế bảo mật của Android kiểm soát quyền truy cập của ứng dụng vào dữ liệu được bảo vệ và chức năng hệ thống. Mỗi ứng dụng phải khai báo các quyền cần thiết trong tệp AndroidManifest.xml bằng phần tử
Mô hình quyền của Android đã trải qua nhiều giai đoạn phát triển. Trước Android 6.0 (API 23), tất cả quyền được cấp khi cài đặt — người dùng thấy danh sách đầy đủ và đồng ý hoặc từ chối cài đặt ứng dụng. Bắt đầu từ Android 6.0, quyền cấp độ dangerous được yêu cầu trong thời gian chạy (Runtime Permissions), mang lại cho người dùng sự kiểm soát linh hoạt hơn.
Quyền được chia thành bốn cấp độ bảo vệ: normal (tự động cấp khi cài đặt), dangerous (yêu cầu yêu cầu trong thời gian chạy), signature (chỉ khả dụng cho ứng dụng được ký bằng cùng chứng chỉ) và special (yêu cầu kích hoạt riêng trong cài đặt). Mỗi cấp độ có cơ chế cấp và thu hồi riêng.
Theo Google I/O 2024, Android 15 dự kiến giới thiệu quyền chi tiết hơn — người dùng có thể cấp quyền truy cập chỉ vào các tệp cụ thể trong thư viện phương tiện, thay vì toàn bộ bộ sưu tập. Điều này tiếp tục xu hướng của Android là giảm thiểu lượng dữ liệu được cung cấp theo mặc định.
Không giống iOS, nơi tất cả quyền được yêu cầu trong thời gian chạy, Android chia quyền thành loại cài đặt (install-time) và thời gian chạy (runtime). Cấp độ normal được cấp tự động khi cài đặt mà không thông báo cho người dùng. Cấp độ dangerous yêu cầu hộp thoại rõ ràng, giống như iOS.
Một khác biệt khác: trong Android, quyền được nhóm thành nhóm quyền. Nếu người dùng đồng ý truy cập máy ảnh, ứng dụng tự động có quyền truy cập micrô — chúng nằm trong cùng nhóm MICROPHONE. Trong iOS, mỗi quyền được yêu cầu độc lập bất kể nhóm.
| Phiên bản Android | Thay đổi trong mô hình quyền |
|---|---|
| Android 1.0–5.x | Tất cả quyền được cấp khi cài đặt |
| Android 6.0 (API 23) | Giới thiệu Runtime Permissions cho cấp độ dangerous |
| Android 10 (API 29) | Scoped Storage — truy cập hạn chế vào hệ thống tệp |
| Android 11 (API 30) | Tự động đặt lại quyền — quyền không sử dụng bị đặt lại |
| Android 14 (API 34) | Quyền thời gian chạy cho truy cập phương tiện (ảnh, video, âm thanh) |
Android xác định bốn cấp độ bảo vệ cho quyền, mỗi cấp độ có quy tắc cấp riêng. Hãy xem xét từng cấp độ chi tiết.
Quyền Normal được cấp tự động khi cài đặt ứng dụng mà không thông báo hoặc yêu cầu người dùng. Chúng bao gồm các chức năng rủi ro thấp không đe dọa quyền riêng tư của người dùng: INTERNET, ACCESS_NETWORK_STATE, VIBRATE, BLUETOOTH. Người dùng không thấy hộp thoại đồng ý — quyền được coi là đã cấp khi cài đặt.
Nhà phát triển không cần xử lý yêu cầu trong mã cho quyền normal — chỉ cần khai báo chúng trong tệp kê khai. Tuy nhiên, trên Android 12+, khi cài đặt từ Google Play, người dùng thấy tab “Quyền” liệt kê tất cả quyền normal, tăng tính minh bạch. Theo Statista (2024), hơn 90% ứng dụng trên Google Play sử dụng INTERNET là quyền normal phổ biến nhất.
Quyền Dangerous bao gồm quyền truy cập vào dữ liệu và chức năng có thể xâm phạm quyền riêng tư: máy ảnh, micrô, định vị địa lý, danh bạ, SMS, điện thoại, lịch, cảm biến cơ thể. Các quyền này yêu cầu cơ chế hai bước: khai báo trong tệp kê khai + yêu cầu trong thời gian chạy qua ActivityCompat.requestPermissions().
Người dùng có thể từ chối quyền dangerous, và ứng dụng phải xử lý tình huống này đúng cách. Trên Android 11+, nếu người dùng từ chối hai lần, các yêu cầu tiếp theo không hiển thị hộp thoại hệ thống — hệ thống tự động trả về DENIED. Trong trường hợp này, ứng dụng nên hướng người dùng đến cài đặt.
Cấp độ signature — quyền được cấp tự động nếu ứng dụng được ký bằng cùng chứng chỉ với hệ thống hoặc ứng dụng khác đã xác định quyền. Được sử dụng cho ứng dụng hệ thống và doanh nghiệp. Ví dụ: BIND_ACCESSIBILITY_SERVICE — chỉ khả dụng cho ứng dụng hệ thống.
Cấp độ special (SYSTEM_ALERT_WINDOW, WRITE_SETTINGS, REQUEST_INSTALL_PACKAGES, MANAGE_EXTERNAL_STORAGE) — yêu cầu hành động rõ ràng của người dùng thông qua cài đặt hệ thống. Ứng dụng có thể mở trang cài đặt bằng Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION). Google Play hạn chế sử dụng quyền special và yêu cầu giải trình trong biểu mẫu khi xuất bản.
Từ Android 6.0, tất cả quyền dangerous yêu cầu yêu cầu trong thời gian chạy. Hãy xem xét quy trình làm việc đầy đủ với runtime permissions trong Kotlin.
Trước khi gọi API yêu cầu quyền dangerous, luôn kiểm tra trạng thái hiện tại qua ContextCompat.checkSelfPermission(). Nếu trạng thái là PERMISSION_GRANTED, bạn có thể gọi API. Nếu PERMISSION_DENIED, bạn cần yêu cầu quyền qua ActivityResultContract RequestPermission (AndroidX) hoặc requestPermissions() cũ.
Nên sử dụng ActivityResultContracts.RequestMultiplePermissions để yêu cầu nhiều quyền cùng lúc. Google khuyến nghị nhóm các quyền liên quan (ví dụ: máy ảnh + micrô để ghi video) vào một hộp thoại, để người dùng thấy bối cảnh đầy đủ của yêu cầu.
import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
class CameraActivity : AppCompatActivity() {
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
} else {
explainWhyPermissionNeeded()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkCameraPermission()
}
private fun checkCameraPermission() {
when {
ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
shouldShowRequestPermissionRationale(
Manifest.permission.CAMERA
) -> {
showRationale()
}
else -> {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
}
Nếu người dùng từ chối hai lần, Android chuyển yêu cầu sang trạng thái “Never ask again”. Trong trường hợp này, shouldShowRequestPermissionRationale() trả về false và hộp thoại hệ thống sẽ không hiển thị. Ứng dụng nên hướng người dùng đến cài đặt hệ thống qua Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).
Quan trọng: không hiển thị hộp thoại đề nghị mở cài đặt ngay sau lần từ chối đầu tiên — điều này bị coi là hành vi hung hăng. Sử dụng shouldShowRequestPermissionRationale() để xác định xem có cần hiển thị giải thích hay không. Nguyên tắc Material Design khuyến nghị hiển thị màn hình giải thích giá trị của quyền truy cập, không chỉ nút “Mở cài đặt”.
private fun openAppSettings() {
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
).also { intent ->
startActivity(intent)
}
}
private fun showPermissionSettings() {
AlertDialog.Builder(this)
.setTitle("Truy cập máy ảnh")
.setMessage("Cho phép truy cập máy ảnh trong Cài đặt, "
+ "để chụp ảnh hồ sơ")
.setPositiveButton("Mở cài đặt") { _, _ ->
openAppSettings()
}
.setNegativeButton("Hủy", null)
.show()
}
Tệp AndroidManifest.xml chứa phần tử
Mỗi quyền được khai báo bằng một phần tử
Ví dụ, quyền WRITE_EXTERNAL_STORAGE không cần thiết trên Android 10+ (Scoped Storage), vì vậy hãy chỉ định maxSdkVersion="28" (Android 9). Điều này ngăn các câu hỏi không cần thiết từ người dùng trên các phiên bản mới hơn. Android Studio cảnh báo về maxSdkVersion được khuyến nghị qua Lint.
<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Normal permissions (install-time) -->
<uses-permission
android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Dangerous permissions (runtime) -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Legacy storage permission limited to API 28 and below -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<application>
<!-- ... -->
</application>
</manifest>
Phần tử
Nên đặt required="false" cho tất cả tính năng phần cứng và kiểm tra khả năng khả dụng theo chương trình qua PackageManager.hasSystemFeature(). Điều này mở rộng đối tượng người dùng của ứng dụng. Ngoại lệ duy nhất là nếu tính năng quan trọng cho hoạt động của ứng dụng (ứng dụng gọi taxi không có GPS thì vô nghĩa).
Xử lý quyền đúng cách là một khía cạnh quan trọng của chất lượng ứng dụng Android. Hãy xem xét các khuyến nghị chính và lỗi điển hình.
Chỉ yêu cầu những quyền thực sự cần thiết cho hoạt động của ứng dụng. Mỗi quyền thừa làm giảm tỷ lệ chuyển đổi cài đặt và tăng số lượng từ chối. Google Play Console hiển thị bao nhiêu người dùng đã từ chối cài đặt do tập hợp quyền. Theo AppBrain (2024), ứng dụng có 10+ quyền dangerous có số lượng cài đặt ít hơn 35%.
Thường xuyên xem xét danh sách quyền của bạn. Loại bỏ những quyền không sử dụng, đặc biệt khi di chuyển lên phiên bản Android mới hơn nơi một số quyền trở thành tùy chọn. Ví dụ, với trình chọn ảnh (ActivityResultContracts.PickVisualMedia) trên Android 13+, có thể truy cập thư viện phương tiện mà không cần quyền dangerous READ_MEDIA_IMAGES.
Trước khi yêu cầu quyền dangerous, hãy hiển thị cho người dùng màn hình giải thích tại sao cần quyền này và giá trị nó mang lại. Material Design khuyến nghị sử dụng bottom sheet hoặc hộp thoại có biểu tượng, văn bản ngắn và nút “Tiếp tục”. Giải thích làm tăng sự đồng ý lên 20–30% so với yêu cầu trực tiếp.
Kiểm tra shouldShowRequestPermissionRationale() trước khi gọi launch(). Nếu true, hiển thị giải thích. Nếu false, quyền đã được cấp hoặc người dùng đã từ chối vĩnh viễn (không hỏi lại). Trong trường hợp sau, hiển thị nút “Mở cài đặt” thay vì lặp lại yêu cầu.
Kiểm tra tất cả các kịch bản có thể: cấp quyền, từ chối, từ chối vĩnh viễn, thu hồi quyền trong cài đặt, đặt lại quyền (Android 11+ tự động đặt lại). Mỗi kịch bản phải được xử lý mà không bị treo hoặc mất dữ liệu. Hướng dẫn kiểm thử Android khuyến nghị sử dụng thư viện TestPermission để tự động hóa kiểm thử.
Đặc biệt chú ý đến kịch bản người dùng thu hồi quyền trong khi ứng dụng đang chạy (ứng dụng thu nhỏ → Cài đặt → thu hồi). Khi quay lại ứng dụng, kiểm tra lại tất cả quyền trong onResume(). Không dựa vào bộ nhớ đệm trạng thái quyền — người dùng có thể thay đổi chúng bất cứ lúc nào.
Câu hỏi thường gặp
Có, nếu SDK bao gồm quyền trong tệp kê khai của nó, nó sẽ được hợp nhất với tệp kê khai của ứng dụng khi xây dựng. Bạn có thể loại bỏ quyền SDK không cần thiết bằng tools:node="remove" trong AndroidManifest.xml.
Gọi API mà không có quyền sẽ gây ra SecurityException, dẫn đến ứng dụng bị treo. Luôn kiểm tra trạng thái quyền trước khi sử dụng API tương ứng và xử lý từ chối đúng cách.
Trong cài đặt thiết bị: Cài đặt → Ứng dụng → [ứng dụng của bạn] → Quyền. Để đặt lại tất cả quyền, sử dụng lệnh adb: adb shell pm reset-permissions.
Có, bằng cách sử dụng ActivityResultLauncher trong Fragment hoặc Service. Tuy nhiên, hộp thoại yêu cầu luôn yêu cầu ngữ cảnh giao diện Activity. Đối với Service, bạn có thể hiển thị Notification với Intent mở Activity yêu cầu.
Ví dụ, WRITE_EXTERNAL_STORAGE không cần thiết trên Android 10+ (Scoped Storage). Bằng cách chỉ định android:maxSdkVersion="28", bạn loại trừ khai báo quyền trên các phiên bản mới hơn, cải thiện khả năng tương thích và giảm danh sách quyền được yêu cầu.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.