📚前言
跟着trae规划的学习开发安卓手机app的教程,一步一步学习实践,总规划见下面文档
【Trae+AI】和Trae学习搭建App_00:总项目规划_trae 封装apk-CSDN博客
下面开始规划的第四章,开始之前还有点事要说。
🌍战略调整
在进行核心API实现之前,现把前后端连起来,现了解整体运行机制,这样会更有成就感。
实践方式,尽量手搓,即Android Studio+文本编辑器+CMD+AI教程指导【豆包】
✍️AI提示语:
我要学习安卓手机app的开发,我已经完成第一章规划,第二章:开发环境配置(包括Android Studio、node.js、MongoDB、Git),以及第三章,后端基础框架 Express框架搭建 数据库模型设计(用户、任务、分类) 中间件配置(日志、跨域、认证)。请为我规划第四章的教学内容,安卓APP调用后端Express的详细教程,可以分多次输出,一定要有详细的操作过程,和对应原理,指导初学的我逐步掌握。
第二部分:后端API开发
第四章 安卓APP调用Express后端实战
一、第四章整体教学规划(语言Kotlin)
本章核心目标:基于Kotlin语言(Android官方首选开发语言),从零基础到完整调用后端所有核心接口(登录、任务CRUD、分类管理),兼顾「手把手操作步骤」和「底层原理」,整体分为6个部分,适配初学者节奏:
| 模块 | 核心内容 | 学习目标 |
|---|---|---|
| 第一部分 | 安卓端网络通信基础准备(Kotlin项目创建+权限+核心依赖) | 搭建Kotlin版安卓基础项目,解决"安卓能访问后端"的前提问题(权限、依赖) |
| 第二部分 | 安卓网络请求工具封装(OkHttp3 + Kotlin协程) | 掌握Kotlin环境下的主流网络库封装,用协程替代传统子线程,简化异步逻辑 |
| 第三部分 | 登录接口调用(获取JWT令牌)+ 令牌本地存储(Kotlin版) | 实现"账号密码→后端验证→获取令牌"全流程,理解JWT在Kotlin端的使用逻辑 |
| 第四部分 | 带令牌调用认证接口(任务/分类查询) | 掌握"请求头携带JWT"的Kotlin实现,适配后端auth中间件验证逻辑 |
| 第五部分 | 业务接口CRUD(任务/分类的增、删、改、查) | 覆盖完整业务场景,掌握不同请求方式(GET/POST/PUT/DELETE)的Kotlin实现 |
| 第六部分 | 网络异常处理+调试技巧(Kotlin端+后端联调) | 解决实战中常见问题,掌握Kotlin环境下的调试方法 |
二、第四章(第一部分):安卓端网络通信基础准备(Kotlin版)
学习目标
- 用Android Studio创建Kotlin版安卓项目(适配后端业务);
- 配置安卓网络通信必备的「权限」和「核心依赖」;
- 理解Kotlin环境下安卓网络通信的核心原理(协程、空安全等);
- 验证安卓端与后端Express的网络连通性(Kotlin代码实现)。
之前教程参考
前置知识回顾
- 后端已启动:
http://localhost:3000(安卓模拟器访问本地后端需用http://10.0.2.2:3000,原理后文讲); - 后端已有核心接口:
/api/login(登录)、/api/tasks(任务查询)、/test(测试接口)。
步骤1:创建Kotlin版安卓项目(详细操作)
操作流程(手把手)
- 打开Android Studio,点击「New Project」→ 选择「Empty ViewsActivity」→ 点击「Next」;
- 配置项目信息:
- Name:
AndroidExpressDemo(项目名,自定义,英文); - Package name:
com.example.androidexpressdemo(包名,默认即可,安卓唯一标识); - Save location:选择本地存储路径(如
E:\AndroidProjects); - Language:
Kotlin(Android官方首选,初学者易上手,语法更简洁); - Minimum SDK:选择
API 24: Android 7.0 (Nougat)(覆盖95%以上设备);
- Name:
- 点击「Finish」,等待Android Studio自动构建项目(首次构建需下载gradle,耐心等待);
- Kotlin项目结构说明(初学者重点关注):
app/src/main/AndroidManifest.xml:安卓核心配置文件(权限、组件声明);app/src/main/java/com/example/androidexpressdemo/MainActivity.kt:主界面逻辑(Kotlin代码编写处);app/src/main/res/layout/activity_main.xml:主界面布局(UI控件);app/build.gradle:依赖配置文件(添加网络库、协程等依赖)。
说明
- Kotlin是Android官方2017年宣布的首选开发语言,相比Java:
- 语法更简洁(少样板代码,如无需写
findViewById); - 天然支持空安全(避免空指针异常,初学者踩坑少);
- 内置协程(优雅处理异步操作,替代Java的
Thread);
- 语法更简洁(少样板代码,如无需写
- Minimum SDK选7.0:既保证兼容性,又能使用Kotlin协程、OkHttp3等现代API。
步骤2:配置安卓网络权限(必做)
操作流程
-
打开
app/src/main/AndroidManifest.xml文件; -
在
<manifest>标签内、<application>标签外 添加网络权限:<!-- 网络访问权限(安卓访问后端必须) --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 允许访问网络状态(可选,用于判断网络是否可用) --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -
解除安卓9.0+的"明文网络限制"(后端是
http://协议):
在<application>标签内添加android:usesCleartextTraffic="true":<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.AndroidExpressDemo" android:usesCleartextTraffic="true"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
原理说明(和Java版一致,补充Kotlin无影响)
- 安卓权限机制:所有敏感操作(如网络访问)需在
AndroidManifest.xml声明,否则APP崩溃; - 明文网络限制:安卓9.0+默认禁止
http://,需usesCleartextTraffic="true"解除; - 权限类型:
INTERNET是普通权限,安卓自动授予,无需运行时申请。
📌Android应用中的权限声明
Android 应用清单文件(
AndroidManifest.xml)中的权限声明是应用向系统申请访问设备资源 / 功能的核心方式,Android 官方将权限分为 普通权限(Normal) 、危险权限(Dangerous) 、特殊权限(Special) 三类,普通权限只需清单声明,危险权限需动态申请,特殊权限需引导用户到系统设置授权,且所有权限需适配对应 Android 版本的行为变更。➡️更详细内容见附录部分。
步骤3:添加核心依赖(OkHttp3 + Gson + Kotlin协程)
操作流程
-
打开
app/build.gradle文件(注意是app模块下的,不是项目根目录的); -
在
dependencies代码块中添加依赖(Kotlin需额外添加协程依赖):dependencies { // 基础Kotlin依赖(默认已有) implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // 新增:OkHttp3网络请求库(核心) implementation 'com.squareup.okhttp3:okhttp:4.12.0' // 新增:Gson(JSON解析,后端返回JSON→Kotlin对象) implementation 'com.google.code.gson:gson:2.10.1' // 新增:Kotlin协程(处理异步网络请求,替代Java的Thread) implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' } -
点击右上角「Sync Now」按钮,等待Gradle同步依赖(首次同步需下载包,耐心等待);
-
同步成功后,查看「External Libraries」,能看到
okhttp-4.12.0、gson-2.10.1、kotlinx-coroutines-android-1.7.3即配置完成。
🧩实际操作界面参考:
添加依赖后,同步前的界面:
同步后,成功界面如下:
📖原理说明(Kotlin专属补充)
- OkHttp3:Android官方推荐的网络库,Kotlin/Java调用方式一致,优点是自动处理连接池、超时;
- Gson:Google JSON解析库,Kotlin中可快速将JSON转为数据类(Data Class),比Java更简洁;
- Kotlin协程:替代Java的
Thread,是Kotlin处理异步任务的标准方式------- 避免"回调地狱",用同步写法实现异步逻辑;
- 适配Android主线程规则,自动切换线程(网络请求在子线程,UI更新在主线程)。
📌
app/build.gradle文件中依赖的两种书写格式:
写法形式 核心特点 implementation(libs.androidx.core.ktx)基于 Gradle 版本目录(Version Catalog),依赖版本集中管理,工程级统一维护;这是 Gradle 7.0+ 引入的 Version Catalog 特性 (Android Gradle Plugin 7.0+ 适配),版本号不在 build.gradle 中 ,而是集中写在工程根目录的 libs.versions.toml文件里implementation 'androidx.core:core-ktx:1.9.0'传统直接声明,版本号硬编码在 build.gradle 中,分散管理 💡建议:两种写法都能正确引入依赖,推荐新建项目(AGP 7.0+)优先使用版本目录写法。
步骤4:基础测试------Kotlin版安卓访问Express后端(验证连通性)
前置准备:确保后端正常运行
-
启动Express后端(
node app.js),确认http://localhost:3000可访问; -
后端添加测试接口(临时):在
app.js中添加无需认证的/test接口:// 后端app.js app.get('/test', (req, res) => { res.json({ code: 200, message: '安卓(Kotlin)端连通测试成功', data: { time: new Date().toString() } }); });
🧩实际操作参考:
修改
app.js后,通过浏览器,访问测试地址:localhost:3000/test,显示如下信息:
步骤4.1:修改布局文件(显示请求结果)
打开app/src/main/res/layout/activity_main.xml,添加TextView用于显示请求结果:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="等待请求..."
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
🧩界面设置参考:
步骤4.2:编写Kotlin网络请求代码(协程版)
打开MainActivity.kt,编写核心代码(Kotlin+协程,适配Android最佳实践):
package com.example.androidexpressdemo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException
class MainActivity : AppCompatActivity() {
// 日志标签(调试用)
private val TAG = "NetworkTest"
// 后端地址:安卓模拟器中localhost映射为10.0.2.2(关键!)
private val BASE_URL = "http://10.0.2.2:3000"
// 延迟初始化TextView(Kotlin空安全特性,避免空指针)
private lateinit var tvResult: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 绑定UI控件(Kotlin无需findViewById,直接用id引用,需开启视图绑定或直接引用)
tvResult = findViewById(R.id.tvResult)
// 1. 创建OkHttp客户端(全局单例更佳,此处简化)
val okHttpClient = OkHttpClient()
// 2. 构建GET请求(访问后端/test接口)
val request = Request.Builder()
.url("$BASE_URL/test") // 拼接测试接口地址
.get() // 指定GET请求(可省略,默认GET)
.build()
// 3. 启动协程处理网络请求(Kotlin核心,替代Java的Thread)
GlobalScope.launch(Dispatchers.Main) {
// 子线程执行网络请求(Dispatchers.IO:IO密集型任务)
val responseResult = withContext(Dispatchers.IO) {
try {
// 执行同步请求(OkHttp同步调用,协程中无阻塞问题)
val response = okHttpClient.newCall(request).execute()
// 获取响应体字符串
val responseBody = response.body?.string()
// 返回成功结果
"请求成功:$responseBody"
} catch (e: IOException) {
// 捕获网络异常
e.printStackTrace()
"请求失败:${e.message}"
}
}
// 4. 主线程更新UI(Dispatchers.Main:自动切换到主线程)
tvResult.text = responseResult
// 日志打印结果(调试用)
Log.d(TAG, "后端返回:$responseResult")
}
}
}
📌相关说明
GlobalScope的提示
如下图
警告说明
GlobalScope的定义:它是一个全局协程作用域,不绑定任何任务,用于启动 "全应用生命周期" 的协程,但不会保持进程存活(类似守护线程)。风险点:
GlobalScope是 "敏感 API",易引发资源 / 内存泄漏解决方案
Activity/Fragment 中 :使用
lifecycleScope(自动绑定页面生命周期,页面销毁时协程自动取消)
lifecycleScope.launch(Dispatchers.Main) { // 网络请求等操作 }实际代码示例:
ViewModel 中 :使用
viewModelScope(绑定 ViewModel 生命周期,ViewModel 销毁时协程自动取消)
viewModelScope.launch(Dispatchers.Main) { // 网络请求等操作 }语法知识点
val:Kotlin 关键字,声明不可变变量 (类似 Java 的final)
OkHttpClient:OkHttp 库的核心客户端类,负责管理网络请求的所有配置(如超时时间、拦截器、连接池等)、发起请求、处理响应;
- OkHttpClient():调用
OkHttpClient的无参构造函数 ,创建一个默认配置的客户端实例。
通过无参构造创建的
OkHttpClient会使用 OkHttp 的默认配置,核心默认值如下:
配置项 默认值 作用 连接超时时间 10 秒 客户端与服务器建立连接的最大等待时间 读取超时时间 10 秒 连接建立后,读取服务器响应数据的最大等待时间 写入超时时间 10 秒 向服务器写入请求数据的最大等待时间 连接池 5 个并发连接,5 分钟空闲超时 复用 HTTP 连接(避免重复创建连接,提升性能) 拦截器 空 无自定义拦截器(可后续通过 newBuilder()添加,如日志、请求头拦截)重定向策略 允许自动重定向 遇到 3xx 状态码时,自动跳转至新地址 Request.Builder().url("$BASE_URL/test") .get() .build()
Request:OkHttp 中封装 HTTP 请求的核心类,包含请求的 URL、方法、头信息、请求体等所有参数;Builder():调用Request的构建器构造函数;.url():Request.Builder的核心方法,用于设置请求的目标 URL;.get():显式指定该请求为 HTTP GET 方法;.build():Request.Builder的最终方法,根据前面配置的参数(URL、请求方法等),生成不可变的Request实例;
- 调用后,构建器的配置会固化到
Request对象中,无法再修改(如需调整,需重新创建 Builder)。启动协程处理网络请求
lifecycleScope:绑定Activity/Fragment生命周期的协程作用域(替代危险的GlobalScope),页面销毁(onDestroy)时,该作用域下的所有协程会自动取消;
launch(Dispatchers.Main):
launch:启动一个新的协程(协程构建器);Dispatchers.Main:指定协程的默认调度器为 "主线程(UI 线程)"------ 即协程的代码块默认在主线程执行,且最终结果会回到主线程(方便更新 UI)
withContext(Dispatchers.IO)
withContext:协程的 "挂起函数",作用是切换到指定线程执行代码块,执行完成后切回原线程 ,并将代码块的返回值赋值给responseResult。Dispatchers.IO:协程的 IO 调度器,专门用于处理 IO 密集型任务(网络请求、文件读写、数据库操作等),底层是线程池,自动管理线程复用,避免手动创建 Thread 的繁琐。- 核心逻辑:把耗时的网络请求 "丢到 IO 线程执行",执行完后自动切回
launch指定的主线程。
okHttpClient.newCall(request).execute()
okHttpClient.newCall(request):将之前构建的Request对象包装为 OkHttp 的Call对象(表示一次可执行的请求);execute():OkHttp 的同步请求方法 (区别于enqueue异步回调):
- 同步请求会 "阻塞当前线程",但这里运行在
Dispatchers.IO线程,因此不会阻塞主线程;response.body?.string()
response.body:OkHttp 的响应体对象(ResponseBody),封装服务器返回的数据;?.string():安全调用响应体的string()方法(避免空指针),将响应体转为字符串(如 JSON 字符串);
- ⚠️ 注意:
string()只能调用一次(调用后响应体流会关闭),如需多次使用需先保存为变量。
"请求成功:$responseBody",在 Kotlin 中,不需要显式写return就能返回结果
- 在 Kotlin 中,带有代码块的 lambda 表达式、匿名函数、普通函数 ,如果没有显式写
return,会默认将代码块的「最后一行语句的结果」作为返回值(前提是代码块有返回类型约束)。
Log.d(TAG, "后端返回:$responseResult"):在Logcat窗口查看输出的日志信息
步骤4.3:运行测试(验证连通性)
-
点击Android Studio顶部「Run」按钮(绿色三角形),选择自带模拟器或真机;
-
程序部署到模拟器或真机中,有相关部署提示,如图:

-
如果链接出现错误,会提示相关错误,如下图示例,提示失败:
-
修正错误:
10.0.2.2仅适用于「安卓自带模拟器(AVD)」
第三方模拟器(如夜神、雷电),
##### 第三方模拟器不支持`10.0.2.2`,需替换为**模拟器的「桥接 IP」**:-
打开模拟器的「设置→网络→WLAN」,查看模拟器的 IP(如
192.168.1.101); -
打开电脑的命令提示符(Win+R 输入
cmd),输入ipconfig,找到电脑的「局域网 IP」(如192.168.1.100); -
将url地址更换为本机真实地址(可先在浏览器上测试地址是否正常)
BASE_URL = "http://192.168.1.100:3000" -
连接「真机」
- 确保手机和电脑连接同一 WiFi(同一局域网)
- 查看电脑的「局域网 IP」,修改BASE_URL地址,步骤和第三方模拟器的方式相同
-
检查确保后端Express服务器启动
-
成功会提示:
服务器端相应的访问信息如下:
第一部分学习总结(Kotlin版)
完成Kotlin版安卓项目搭建,解决"安卓访问后端"的3个核心问题:
- 权限:配置
INTERNET和明文HTTP允许; - 依赖:引入OkHttp3(网络)、Gson(JSON)、协程(异步);
- 地址:模拟器访问电脑后端;
验证了Kotlin端与Express后端的连通性,为后续接口调用打下基础。
附录
Android权限划分
Android 官方将权限分为 普通权限(Normal) 、危险权限(Dangerous) 、特殊权限(Special) 三类,以下是按功能分类的常用权限及核心说明:
一、权限分类基础
| 类型 | 特点 | 申请方式 |
|---|---|---|
| 普通权限 | 低风险,不涉及用户隐私,系统自动授予 | 仅清单声明即可 |
| 危险权限 | 高风险,涉及用户隐私 / 设备安全,需动态申请(Android 6.0+ / API 23+) | 清单声明 + 运行时动态申请 |
| 特殊权限 | 极高风险(如悬浮窗、后台定位),需通过系统设置单独申请 | 清单声明 + 引导用户到系统设置页授权 |
二、常用权限按功能分类详解
1. 网络相关权限(普通权限为主)
| 权限名称 | 类型 | 核心作用 |
|---|---|---|
android.permission.INTERNET |
普通 | 允许应用访问互联网(HTTP/HTTPS/WS 等),访问后端必备 |
android.permission.ACCESS_NETWORK_STATE |
普通 | 获取设备当前网络状态(是否联网、Wi-Fi / 移动数据) |
android.permission.ACCESS_WIFI_STATE |
普通 | 获取 Wi-Fi 详细信息(如 SSID、Wi-Fi 连接状态) |
android.permission.CHANGE_NETWORK_STATE |
普通 | 修改网络状态(如开启 / 关闭移动数据,部分设备需系统级权限) |
android.permission.CHANGE_WIFI_STATE |
普通 | 修改 Wi-Fi 状态(如开启 / 关闭 Wi-Fi、连接指定 Wi-Fi) |
android.permission.ACCESS_NETWORK_INFO |
普通 | 兼容旧版本,等效于 ACCESS_NETWORK_STATE(API 1 后废弃,建议用后者) |
2. 存储相关权限(危险权限,Android 10+ 有特殊适配)
| 权限名称 | 类型 | 核心作用 | 适配说明 |
|---|---|---|---|
android.permission.READ_EXTERNAL_STORAGE |
危险 | 读取外部存储(SD 卡 / 共享目录)文件 | Android 10+(API 29+)需声明 android:requestLegacyExternalStorage="true" 兼容旧逻辑;Android 13+ 拆分为更细粒度权限 |
android.permission.WRITE_EXTERNAL_STORAGE |
危险 | 写入文件到外部存储 | Android 11+(API 30+)被废弃,推荐用 MediaStore/SAF 替代 |
android.permission.MANAGE_EXTERNAL_STORAGE |
特殊 | 管理所有外部存储文件(仅系统应用 / 合规应用可申请,需谷歌审核) | 需引导用户到系统设置页授权,普通应用不建议使用 |
android.permission.READ_MEDIA_IMAGES |
危险 | Android 13+ 读取图片 / 照片(替代 READ_EXTERNAL_STORAGE) |
仅需动态申请此权限,无需申请旧存储权限 |
android.permission.READ_MEDIA_VIDEO |
危险 | Android 13+ 读取视频文件 | 同上 |
android.permission.READ_MEDIA_AUDIO |
危险 | Android 13+ 读取音频文件 | 同上 |
3. 位置相关权限(危险 / 特殊权限)
| 权限名称 | 类型 | 核心作用 | |
|---|---|---|---|
android.permission.ACCESS_FINE_LOCATION |
危险 | 获取精确位置(GPS / 北斗,精度米级) | |
android.permission.ACCESS_COARSE_LOCATION |
危险 | 获取粗略位置(基站 / Wi-Fi,精度千米级) | |
android.permission.ACCESS_BACKGROUND_LOCATION |
特殊 | 应用在后台(非前台)时获取位置 | Android 10+ 需单独申请,引导用户授权 |
android.permission.ACCESS_MOCK_LOCATION |
特殊 | 模拟位置数据(仅调试 / 系统应用可用) | 需在开发者选项中开启 "允许模拟位置" |
4. 相机 / 媒体相关权限(危险权限)
| 权限名称 | 类型 | 核心作用 | |
|---|---|---|---|
android.permission.CAMERA |
危险 | 访问相机硬件(拍照 / 录像) | |
android.permission.RECORD_AUDIO |
危险 | 录制音频(麦克风访问) | |
android.permission.USE_FINGERPRINT |
普通 | 访问指纹传感器(指纹识别) | Android 9+ 推荐用 USE_BIOMETRIC |
android.permission.USE_BIOMETRIC |
普通 | 访问生物识别(指纹 / 人脸 / 虹膜) |
5. 电话 / 通讯相关权限(危险 / 普通)
| 权限名称 | 类型 | 核心作用 | |
|---|---|---|---|
android.permission.READ_PHONE_STATE |
危险 | 读取手机状态(IMEI / 手机号 / 网络类型 / 通话状态) | Android 10+ 需申请 READ_PHONE_NUMBERS 单独读取手机号 |
android.permission.CALL_PHONE |
危险 | 直接拨打电话(无需用户确认) | |
android.permission.READ_CALL_LOG |
危险 | 读取通话记录 | |
android.permission.WRITE_CALL_LOG |
危险 | 写入 / 修改通话记录 | |
android.permission.ANSWER_PHONE_CALLS |
危险 | 接听来电(Android 8.0+) | |
android.permission.SEND_SMS |
危险 | 发送短信 | |
android.permission.READ_SMS |
危险 | 读取短信内容 | |
android.permission.RECEIVE_SMS |
危险 | 接收短信(监听短信广播) |
6. 系统 / 设备控制相关权限(普通 / 特殊)
| 权限名称 | 类型 | 核心作用 | |
|---|---|---|---|
android.permission.SYSTEM_ALERT_WINDOW |
特殊 | 显示悬浮窗(覆盖其他应用) | 需引导用户到 "设置 - 应用 - 权限 - 悬浮窗" 授权 |
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS |
特殊 | 忽略电池优化(应用后台不被杀死) | 需动态申请,用户确认后生效 |
android.permission.WAKE_LOCK |
普通 | 唤醒屏幕 / 保持 CPU 运行(防止应用休眠) | 如音乐播放、后台下载时使用 |
android.permission.VIBRATE |
普通 | 控制设备振动 | |
android.permission.SET_WALLPAPER |
普通 | 设置系统壁纸 |
7. 日历 / 联系人 / 日程(危险权限)
| 权限名称 | 类型 | 核心作用 | |
|---|---|---|---|
android.permission.READ_CONTACTS |
危险 | 读取联系人列表 | |
android.permission.WRITE_CONTACTS |
危险 | 添加 / 修改 / 删除联系人 | |
android.permission.READ_CALENDAR |
危险 | 读取日历事件 | |
android.permission.WRITE_CALENDAR |
危险 | 添加 / 修改 / 删除日历事件 |
8. 传感器 / 硬件相关(普通权限为主)
| 权限名称 | 类型 | 核心作用 | |
|---|---|---|---|
android.permission.BODY_SENSORS |
危险 | 访问身体传感器(心率、步数、体温等) | |
android.permission.ACCESS_ACCELEROMETER |
普通 | 访问加速度传感器 | |
android.permission.ACCESS_GYROSCOPE |
普通 | 访问陀螺仪传感器 | |
android.permission.ACCESS_MAGNETIC_FIELD |
普通 | 访问磁力计传感器 |
三、特殊权限声明注意事项
- 权限组机制 :危险权限按 "组" 管理,申请组内任一权限时,用户授权后组内所有权限均被授予(如申请
READ_CONTACTS,则WRITE_CONTACTS也会被授权); - 权限声明位置 :所有
<uses-permission>必须放在<manifest>根节点下、<application>节点外; - 版本适配 :
- Android 6.0+(API 23):危险权限需动态申请,普通权限仍自动授予;
- Android 13+(API 33):存储权限拆分为图片 / 视频 / 音频细粒度权限,无需申请旧存储权限;
- 声明高版本权限时,可通过
android:maxSdkVersion限制仅在指定版本生效(如<uses-permission android:name="xxx" android:maxSdkVersion="32"/>);
- 权限优先级 :
<uses-permission-sdk-23>仅在 API 23+ 生效,优先级高于普通<uses-permission>; - 权限拒绝处理:需处理用户拒绝权限的场景,避免应用崩溃,核心权限建议引导用户重新授权。
四、如何快速查询所有官方权限
- 安卓官方文档:Android 权限列表;
- 开发工具:Android Studio 中输入
android.permission.会自动提示所有系统权限; - 设备层面:
/system/etc/permissions/platform.xml文件可查看设备支持的所有权限。
总结
清单文件中的权限声明需遵循 "最小权限原则"------ 仅声明应用必需的权限,避免过度申请隐私权限(否则会被应用商店审核拒绝,或降低用户信任)。普通权限只需清单声明,危险权限需动态申请,特殊权限需引导用户到系统设置授权,且所有权限需适配对应 Android 版本的行为变更。






