AndroidManifest Permissions: khái niệm chính, khai báo và các loại quyền

Tác giả: IT Sectr Đã đăng: 2026-05-21 Thời gian đọc: 10 phút

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.xml — tệp kê khai chứa khai báo tất cả quyền của ứng dụng
  • Cấp độ bảo vệ — normal, dangerous, signature, special với cơ chế yêu cầu khác nhau
  • Runtime Permission — quyền dangerous yêu cầu yêu cầu trong thời gian chạy (Android 6+)
  • Khai báo vs Yêu cầu — khai báo trong tệp kê khai là bắt buộc, nhưng dangerous cần yêu cầu bổ sung trong mã
  • Nhóm — quyền được nhóm lại, đồng ý một quyền cho phép truy cập toàn bộ nhóm

AndroidManifest Permissions là gì?

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ử . Nếu không khai báo, việc gọi API tương ứng sẽ gây ra lỗi bảo mật SecurityException.

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ác biệt với mô hình quyền iOS

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.

Sự phát triển của quyền theo phiên bản Android

Phiên bản AndroidThay đổi trong mô hình quyền
Android 1.0–5.xTấ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)

Các loại quyền tồn tại

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 (install-time)

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 (runtime)

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.

Quyền Signature và Special

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.

Runtime Permission: làm việc với quyền dangerous

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.

Kiểm tra và yêu cầu quyền

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.

kotlin
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
                )
            }
        }
    }
}

Xử lý từ chối “Không hỏi lại”

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

kotlin
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()
}

Khai báo quyền trong AndroidManifest.xml

Tệp AndroidManifest.xml chứa phần tử cho mỗi quyền mà ứng dụng sử dụng. Quyền được khai báo ở cấp trước phần tử .

Cú pháp khai báo

Mỗi quyền được khai báo bằng một phần tử riêng với thuộc tính android:name chỉ định tên đầy đủ của quyền. Đối với quyền được giới thiệu trong các phiên bản Android cụ thể, hãy sử dụng thuộc tính maxSdkVersion để giới hạn khai báo chỉ cho các phiên bản cần thiết — điều này cải thiện khả năng tương thích.

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.

xml
<!-- 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>

Sử dụng để lọc

Phần tử chỉ ra rằng ứng dụng yêu cầu phần cứng cụ thể (máy ảnh, GPS, NFC). Thuộc tính android:required="false" cho phép cài đặt ứng dụng trên thiết bị không có phần cứng đó — khả năng khả dụng được kiểm tra trong mã. Nếu required="true", Google Play lọc ứng dụng, khiến ứng dụng không khả dụng cho các thiết bị không phù hợp.

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

Thực hành tốt nhất và lỗi

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.

Giảm thiểu quyền được yêu cầu

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.

Hiển thị giải thích trước khi yêu cầu

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ả kịch bản quyền

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.

Lỗi điển hình

  • Yêu cầu quyền mà không kiểm tra checkSelfPermission trước — gây ra hộp thoại không cần thiết
  • Bỏ qua shouldShowRequestPermissionRationale — làm xấu trải nghiệm người dùng sau lần từ chối đầu tiên
  • Yêu cầu quyền không có ngữ cảnh (chỉ “Cho phép truy cập?”) — giảm sự đồng ý
  • Sử dụng WRITE_EXTERNAL_STORAGE trên Android 10+ không có maxSdkVersion — yêu cầu không cần thiết
  • Thiếu kiểm tra quyền trong onResume — bỏ lỡ việc thu hồi quyền trong cài đặt

Câu hỏi thường gặp

Tôi có cần khai báo quyền nếu SDK yêu cầu nó không?

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.

Điều gì xảy ra nếu tôi không xử lý từ chối quyền?

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.

Làm cách nào để đặt lại quyền trong quá trình phát triển?

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.

Tôi có thể yêu cầu quyền mà không có Activity không?

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.

Tại sao cần maxSdkVersion cho quyền?

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

  • AndroidManifest Permissions — khai báo bắt buộc để truy cập tài nguyên hệ thống trong Android
  • 4 cấp độ bảo vệ — normal, dangerous, signature, special với cơ chế cấp khác nhau
  • Runtime Permissions — quyền dangerous yêu cầu yêu cầu trong thời gian chạy (Android 6+)
  • Nhóm quyền — đồng ý một quyền trong nhóm cho phép truy cập tất cả trong nhóm
  • Giải thích — hiển thị giải thích trước khi yêu cầu tăng sự đồng ý lên 20–30%
  • Giảm thiểu — chỉ yêu cầu quyền cần thiết và sử dụng maxSdkVersion
  • Luôn kiểm tra trạng thái quyền trước khi gọi API và xử lý tất cả kịch bản từ chối

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.

Thảo luận dự án

Đọc thêm