第六篇:系统篇 —— 深入Android核心
第11章 权限与通知:与系统安全共舞
在前十章,我们构建了精美的UI、稳健的架构和强大的数据层。但一个App如果无法与手机系统本身交互,它就是一座孤岛。打电话、发通知、读取文件、后台播放音乐——这些都需要权限(Permission)。
在2026年,Android的权限系统已经进化到了一个极其严格的阶段。**隐私沙盒(Privacy Sandbox)**的全面落地意味着应用再也无法随意窥探用户数据。如果你不理解这套规则,你的App将在启动时崩溃,或者在后台被系统无情杀死。
这一章,我们将深入Android权限的底层逻辑,从Linux内核的UID机制讲到最新的隐私沙盒实现;从最简单的权限请求讲到复杂的健康数据加密;从简单的Toast通知讲到跨进程的通知监听。我们将结合最新的Accompanist Permissions库、NotificationCompat以及Health Connect进行实战,确保你不仅能写代码,还能读懂系统的每一个安全决策。
11.1 Android 16 权限模型:从“一刀切”到“精细化”
Android的权限系统不是一天建成的。它经历了从“安装即授权”到“运行时授权”,再到“临时授权”的漫长演变。
11.1.1 权限的四个等级(深度解析)
| Normal | 低风险,安装时自动授予 | 网络访问 (INTERNET) | 无需代码处理 | 系统自动赋予 |
| Dangerous | 高风险,涉及隐私 | 相机、定位、通讯录 | 必须运行时请求 | Binder IPC + SELinux |
| Signature | 同签名应用共享 | 系统应用间通信 | 无需代码处理 | UID 相同 |
| Special | 特殊权限,用户手动开启 | 悬浮窗、管理所有文件 | 跳转系统设置页 | 系统设置数据库 |
Normal 权限的深度解析: 这些权限被认为对用户隐私没有直接影响。例如 INTERNET,系统认为应用访问互联网是正常行为,不需要用户确认。但值得注意的是,在2026年,即使是 INTERNET 权限,也受到 隐私沙盒 的限制。你不能直接追踪用户的IP地址,也不能进行跨站追踪。
Dangerous 权限的深度解析: 这些权限会直接触及用户的隐私数据。系统会强制弹窗询问用户。在Android 16中,这些弹窗经过了重新设计,更加突出“允许”和“拒绝”的后果。
11.1.2 2026年的重大变化(你必须知道的细节)
11.1.3 权限组(Permission Groups)的底层逻辑
Android将危险的权限分组,当你请求组中的一个权限时,系统会提示整个组的权限。这不是为了便利,而是为了安全。
| CALENDAR | READ_CALENDAR, WRITE_CALENDAR | 系统日历数据库 |
| CAMERA | CAMERA | Camera HAL 层 |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | 联系人数据库 |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION | GPS/NLP 服务 |
| MICROPHONE | RECORD_AUDIO | Audio HAL 层 |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | 电话服务 |
| SENSORS | BODY_SENSORS | Sensor Hub |
| SMS | SEND_SMS, RECEIVE_SMS, READ_SMS | SMS 服务 |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE | Vold 服务 |
为什么需要权限组? 因为权限组对应着系统资源的访问权限。例如,CONTACTS 组对应着联系人数据库的读写权限。当你申请 READ_CONTACTS 权限时,系统实际上是在 /data/data/com.android.providers.contacts/databases/contacts2.db 数据库上为你打开了读权限。
11.2 运行时权限请求:Accompanist Permissions(深度实战)
在Compose中,处理权限最优雅的方式是使用 Accompanist Permissions 库。它用状态机的方式管理权限,避免了传统 onRequestPermissionsResult 的回调地狱。
11.2.1 添加依赖(详细步骤)
// build.gradle.kts (App)
dependencies {
// Accompanist Permissions 是 Google 官方维护的库
implementation(\”com.google.accompanist:accompanist-permissions:0.37.0\”)
}
11.2.2 请求单个权限(完整代码与解释)
import androidx.compose.runtime.Composable
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CameraScreen() {
// 1. 创建权限状态
// rememberPermissionState 会记住这个权限的状态,即使 Composable 重组也不会丢失
val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA)
when {
// 2. 已授权
cameraPermissionState.status.isGranted -> {
// 这里可以安全地使用相机
CameraPreview()
}
// 3. 未授权,且需要解释原因
cameraPermissionState.status.shouldShowRationale -> {
// shouldShowRationale 为 true 表示用户之前拒绝了权限,但没有选择“不再询问”
// 这时你应该解释为什么需要这个权限
Column {
Text(\”我们需要相机权限来拍照,请授予权限。\”)
Button(onClick = {
cameraPermissionState.launchPermissionRequest() }) {
Text(\”请求权限\”)
}
}
}
// 4. 未授权,且用户选择了“不再询问”
else -> {
// shouldShowRationale 为 false 表示用户选择了“不再询问”
// 这时你不能再请求权限,必须引导用户去设置页
Column {
Text(\”权限被永久拒绝,请手动开启。\”)
Button(onClick = {
openAppSettings





