Google 致力于为黑人社区推动种族平等。查看具体举措

请求应用权限

每款 Android 应用都在访问受限的沙盒中运行。如果应用需要使用自己的沙盒外的资源或信息,就必须请求相应权限。您可以通过以下方式声明应用需要某项权限:在应用清单中列出该权限,然后在运行时请求用户批准每项权限(适用于 Android 6.0 及更高版本)。

基本原则如下:

  • 视情况在用户开始与需要相关权限的功能进行互动时请求权限。
  • 不要阻止用户使用应用。始终提供选项供用户取消与权限相关的指导界面流程。
  • 如果用户拒绝或撤消某项功能所需的权限,请适当降级您的应用以便让用户可以继续使用您的应用(可能通过停用需要该权限的功能来实现)。
  • 不要假设任何系统行为。

本页面详细介绍向应用添加权限以及在运行时根据需要请求这些权限的分步流程。

向清单添加权限

对于所有 Android 版本,如需声明应用需要某项权限,请在应用清单中添加 <uses-permission> 元素,作为顶级 <manifest> 元素的子级。

例如,需要访问互联网的应用会在清单中添加以下代码行:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- other permissions go here -->

    <application ...>
        ...
    </application>
</manifest>

系统在您声明权限之后的行为取决于权限的敏感程度。有些权限被视为“普通”权限,因此系统会在安装应用后立即授予这些权限。还有些权限则被视为“危险”权限,因此必须由用户向应用明确授予相应访问权限。如需详细了解不同类型的权限,请参阅保护级别

检查权限

如果应用需要一项危险权限,那么每次执行需要该权限的操作时,您都必须检查是否具有该权限。在 Android 6.0(API 级别 23)及更高版本中,用户可以随时从任何应用撤消危险权限。

确定应用是否已获得权限

如需检查用户是否已向您的应用授予特定权限,请将该权限传入 ContextCompat.checkSelfPermission() 方法。根据您的应用是否具有相应权限,此方法会返回 PERMISSION_GRANTEDPERMISSION_DENIED

说明您的应用为何需要获取权限

如果 ContextCompat.checkSelfPermission() 方法返回 PERMISSION_DENIED,请调用 shouldShowRequestPermissionRationale()。如果此方法返回 true,请向用户显示指导界面。请在此界面中说明用户希望启用的功能为何需要特定权限。

请求权限

用户查看指导界面后或者 shouldShowRequestPermissionRationale() 的返回值表明您这次不需要显示指导界面后,您可以请求权限。用户会看到系统权限对话框,并可在其中选择是否向您的应用授予特定权限。

按照历来的做法,您可以在权限请求过程中自行管理请求代码,并将此请求代码包含在您的权限回调逻辑中。另一种选择是使用 AndroidX 库中包含的 RequestPermission 协定类,您可在其中允许系统代为管理权限请求代码。由于使用 RequestPermission 协定类可简化逻辑,因此,建议您尽可能使用该方法。

允许系统管理权限请求代码

如需允许系统管理与权限请求相关联的请求代码,请在您模块的 build.gradle 文件中添加 androidx.activity 库的依赖项。请使用该库的 1.2.0 版或更高版本。

然后,您可以使用以下某个类:

以下步骤显示了如何使用 RequestPermission 协定类。使用 RequestMultiplePermissions 协定类的流程几乎与此相同。

  1. 在 Activity 或 Fragment 的初始化逻辑中,将 ActivityResultCallback 的实现传入对 registerForActivityResult() 的调用。ActivityResultCallback 定义应用如何处理用户对权限请求的响应。

    保留对 registerForActivityResult()(类型为 ActivityResultLauncher)的返回值的引用。

  2. 如需在必要时显示系统权限对话框,请对您在上一步中保存的 ActivityResultLauncher 实例调用 launch() 方法。

    调用 launch() 之后,系统会显示系统权限对话框。当用户做出选择后,系统会异步调用您在上一步中定义的 ActivityResultCallback 实现。

    注意:应用无法自定义调用 launch() 时显示的对话框。如需为用户提供更多信息或上下文,请更改应用的界面,以便让用户更容易了解应用中的功能为何需要特定权限。例如,您可以更改用于启用该功能的按钮中的文本。

    此外,系统权限对话框中的文本会提及与您请求的权限关联的权限组。此权限分组是为了让系统易于使用,您的应用不应依赖于特定权限组之内或之外的权限。

以下代码段展示了如何处理权限响应:

Kotlin

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher. You can use either a val, as shown in this snippet,
// or a lateinit var in your onAttach() or onCreate() method.
val requestPermissionLauncher =
    registerForActivityResult(RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // features requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    }

Java

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher, as an instance variable.
private ActivityResultLauncher<String> requestPermissionLauncher =
    registerForActivityResult(new RequestPermission(), isGranted -> {
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // features requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    });

以下代码段演示了检查权限并根据需要向用户请求权限的建议流程:

Kotlin

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
    }
    shouldShowRequestPermissionRationale(...) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected. In this UI,
        // include a "cancel" or "no thanks" button that allows the user to
        // continue using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        // The registered ActivityResultCallback gets the result of this request.
        requestPermissionLauncher.launch(
                Manifest.permission.REQUESTED_PERMISSION)
    }
}

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected. In this UI,
    // include a "cancel" or "no thanks" button that allows the user to
    // continue using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    // The registered ActivityResultCallback gets the result of this request.
    requestPermissionLauncher.launch(
            Manifest.permission.REQUESTED_PERMISSION);
}

自行管理权限请求代码

作为允许系统管理权限请求代码的替代方法,您可以自行管理权限请求代码。为此,请在对 requestPermissions() 的调用中添加请求代码。

以下代码段演示了如何使用请求代码来请求权限:

Kotlin

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
        performAction(...)
    }
    shouldShowRequestPermissionRationale(...) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected. In this UI,
        // include a "cancel" or "no thanks" button that allows the user to
        // continue using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        requestPermissions(CONTEXT,
                arrayOf(Manifest.permission.REQUESTED_PERMISSION),
                REQUEST_CODE)
    }
}

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected. In this UI,
    // include a "cancel" or "no thanks" button that allows the user to
    // continue using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    requestPermissions(CONTEXT,
            new String[] { Manifest.permission.REQUESTED_PERMISSION },
            REQUEST_CODE);
}

当用户响应系统权限对话框后,系统就会调用应用的 onRequestPermissionsResult() 实现。系统会传入用户对权限对话框的响应以及您定义的请求代码,如以下代码段所示:

Kotlin

override fun onRequestPermissionsResult(requestCode: Int,
        permissions: Array<String>, grantResults: IntArray) {
    when (requestCode) {
        PERMISSION_REQUEST_CODE -> {
            // If request is cancelled, the result arrays are empty.
            if ((grantResults.isNotEmpty() &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            } else {
                // Explain to the user that the feature is unavailable because
                // the features requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return
        }

        // Add other 'when' lines to check for other
        // permissions this app might request.
        else -> {
            // Ignore all other requests.
        }
    }
}

Java

@Override
public void onRequestPermissionsResults(int requestCode, String[] permissions,
        int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            }  else {
                // Explain to the user that the feature is unavailable because
                // the features requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return;
        }
        // Other 'case' lines to check for other
        // permissions this app might request.
    }
}

处理权限请求遭拒情况

如果用户拒绝了权限请求,应用应该帮助用户了解拒绝授予权限的影响。具体而言,应用应该让用户知道因缺少权限而无法使用的功能。在处理这种情况时,请牢记以下最佳做法:

  • 引导用户的注意力。在应用界面中突出显示因为应用没有必要的权限而受限的功能所在的具体部分。以下列举了几个例子说明您可以采取的做法:

    • 在该功能的结果或数据会出现的位置显示一条消息。
    • 显示一个包含错误图标并带有相应错误颜色的不同按钮。
  • 内容要具体。显示的消息不要空泛;而要指出因为应用没有必要的权限而无法使用的具体功能。

  • 不要阻止界面显示。换言之,不要显示全屏警告消息,让用户根本无法继续使用您的应用。

与此同时,您的应用还应尊重用户拒绝授予权限的决定。从 Android 11(API 级别 30)开始,在应用安装到设备上后,如果用户在使用过程中多次针对某项特定的权限点按拒绝,那么在您的应用再次请求该权限时,用户将不会看到系统权限对话框。该操作表示用户希望“不再询问”。在之前的版本中,除非用户先前已选中“不再询问”对话框或选项,否则每当您的应用请求权限时,用户都会看到系统权限对话框。

在某些情况下,系统可能会自动拒绝权限,而无需用户执行任何操作。(同样,系统也可能会自动授予权限。)请千万不要对系统的自动行为做出任何假设。每当应用需要使用的功能需要权限时,您都应该检查应用是否仍被授予该权限。

如需在请求应用权限时提供最佳用户体验,另请参阅应用权限最佳做法

在必要时请求成为默认处理程序

有些应用依赖于访问与通话记录和短信有关的敏感用户信息。如果您想请求特定于通话记录和短信的权限,并将应用发布到 Play 商店,您必须在请求这些运行时权限之前,提示用户将应用设置为核心系统功能的默认处理程序。

如需详细了解默认处理程序,包括有关如何向用户显示默认处理程序提示的指南,请参阅有关仅在默认处理程序中使用的权限的指南

按 API 级别声明权限

如需仅在支持运行时权限的设备(即,搭载 Android 6.0(API 级别 23)或更高版本的设备)上声明某项权限,请添加 uses-permission-sdk-23 标记,而不是 uses-permission 标记。

使用这些标记中的任意一个时,您都可以设置 maxSdkVersion 属性,用于指定在搭载更高版本的设备上不需要特定权限。

其他资源

如需详细了解权限,请阅读以下文章:

如需详细了解如何请求权限,请下载以下示例应用:

  • Android RuntimePermissionsBasic 示例 Java | Kotlin