限制与其他应用的交互

权限不仅仅用于请求获取系统功能的使用权。您还可以限制其他应用与您的应用组件交互的方式。

本指南介绍了如何查看另一应用已声明的权限集,还介绍了如何配置 activity、服务、content provider 和广播接收器来限制其他应用与您的应用交互的方式,并提供了在应用之间强制实施各种交互模式的多种其他方式的相关指导。

查看另一应用的权限

如需查看另一应用声明的权限集,请使用设备或模拟器完成以下步骤:

  1. 打开应用的应用信息屏幕。
  2. 选择权限。系统会加载应用权限屏幕。

    此屏幕会显示一系列权限组。系统会将应用所声明的权限整理到这些权限组内。

限制与应用的 activity 的交互

使用 android:permission 属性应用于清单中 <activity> 标记的权限可限制谁能启动该 Activity。系统会在 Context.startActivity()Activity.startActivityForResult() 期间检查该权限。如果调用方没有所需的权限,将会发生 SecurityException

限制与应用的服务的交互

使用 android:permission 属性应用于清单中 <service> 标记的权限可限制谁能启动或绑定到关联的 Service。系统会在 Context.startService()Context.stopService()Context.bindService() 期间检查该权限。如果调用方没有所需的权限,将会发生 SecurityException

限制与应用的 content provider 的交互

使用 android:permission 属性应用于 <provider> 标记的权限可限制谁能访问 ContentProvider 中的数据。(content provider 有重要的附加安全工具可供其使用,称为 URI 权限,将在后面介绍。)与其他组件不同,您可以设置两个单独的权限属性:android:readPermission 限制谁可以读取提供程序,android:writePermission 限制谁可以写入提供程序。请注意,如果提供程序有读取和写入权限保护,仅拥有写入权限并不表示您可以读取提供程序。

第一次检索提供程序时将会检查该权限(如果您既没有读取权限也没有写入权限,则会发生 SecurityException),对提供程序执行操作时也会检查该权限。使用 ContentResolver.query() 需要拥有读取权限;使用 ContentResolver.insert()ContentResolver.update()ContentResolver.delete() 需要写入权限。在所有这些情况下,没有所需的权限将会导致 SecurityException

根据 URI 授予权限

您可以进一步对其他应用如何访问您应用的 content provider 进行精细控制。具体而言,您的 content provider 可以利用读取和写入权限保护自己,同时仍允许其直接客户端与其他应用共享特定 URI。如需声明您的应用支持此模式,请使用 android:grantUriPermissions 属性或 <grant-uri-permission 元素。

您还可以根据 URI 授予权限。在启动 activity 或将结果返回给 activity 时,请设置 Intent.FLAG_GRANT_READ_URI_PERMISSION intent 标志、Intent.FLAG_GRANT_WRITE_URI_PERMISSION intent 标志或者同时设置两者。这样便可针对 intent 中包含的数据 URI 分别向另一个应用授予读取权限、写入权限和读写权限。无论从更笼统的角度来说这另一个应用是否有权访问 content provider 中的数据,它都会获得针对该 URI 的上述权限。

例如,假设用户正在您的应用中查看电子邮件,并且此电子邮件包含一个图片附件。一般来说,其他应用本该无法访问电子邮件内容,但它们可能希望查看这张图片。您的应用可以结合使用 intent 和 Intent.FLAG_GRANT_READ_URI_PERMISSION intent 标志,以便图片查看应用能够查看这张图片。

另一个需要考虑的因素是应用可见性。如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,在默认情况下,系统会自动让部分应用对您的应用可见,但会隐藏其他应用。如果您的应用具有 content provider,并且已向另一应用授予 URI 权限,那么您的应用会自动对该应用可见

如需了解详情,请查看介绍 grantUriPermission()revokeUriPermission()checkUriPermission() 方法的参考资料。

限制与应用的广播接收器的交互

使用 android:permission 属性应用于 <receiver> 标记的权限可限制谁能向关联的 BroadcastReceiver 发送广播。系统会在 Context.sendBroadcast() 返回后检查该权限,此时系统会尝试将提交的广播传递到指定的接收器。因此,权限错误不会导致向调用方抛回异常;只是不会传递该 Intent

同样,您可以向 Context.registerReceiver() 提供权限,用于控制谁能向以编程方式注册的接收器发送广播。另一方面,可以在调用 Context.sendBroadcast() 时提供权限,以限制哪些广播接收器可以接收广播。

请注意,接收器和广播方可能都需要权限。发生这种情况时,两项权限检查都必须顺利通过,系统才会将 intent 传递到关联的目标。如需了解详情,请参阅通过权限限制广播

其他针对权限的检查

您还可以通过其他一些实用方式来检查权限:

  • 在调用某项服务期间,将权限字符串传入 Context.checkCallingPermission()。此方法会返回一个整数,指示当前调用进程是否已获授权限。请注意,仅在执行从另一个进程传入的调用(通常是通过从服务发布的 IDL 接口或提供给另一进程的某种其他方式来实现)时,才可使用此方法。
  • 如需检查另一进程是否已获得特定权限,请将该进程 (PID) 传入 Context.checkPermission()
  • 如需检查另一软件包是否已获得特定权限,请将该软件包的名称传入 PackageManager.checkPermission()