大家好,我是拭心。
Android 17(API level 37,代号 CinnamonBun)的 Beta 2 已经发布,目前正快速推进到 Platform Stability 阶段,预计 Q2 正式发版,Q4 还会有一个 Minor SDK 更新。
这篇文章我们来看看 Android 17 带来了哪些新东西,以及哪些地方需要提前适配。
一、UI 体验与屏幕适配
1.1 大屏自适应:这次是真的强制了
这是 Android 17 对开发者影响最大的变更,必须重点关注。
Android 16 引入了大屏方向和多窗口限制,但还保留了开发者的「退出选项」。到了 Android 17(targetSdk 37),这个退出选项没有了。
具体来说,当你的 App 运行在大屏设备上(sw > 600 dp,即折叠屏展开态、平板等)时,以下 Manifest 属性和 API 会被系统直接忽略:
| 属性 / API | 被忽略的值 |
|---|---|
screenOrientation | portrait、reversePortrait、sensorPortrait、userPortrait、landscape、reverseLandscape、sensorLandscape、userLandscape |
setRequestedOrientation() | 同上 |
resizeableActivity | 所有值 |
minAspectRatio | 所有值 |
maxAspectRatio | 所有值 |
简单说:在大屏上,你无法再通过代码或配置锁定横竖屏、限制宽高比。 系统会让你的 App 随窗口大小自由伸缩。
注意:sw ≤ 600 dp 的小屏手机不受影响;被标记为游戏类别(
android:appCategory="game")的应用也不受影响。用户可以在系统「宽高比设置」中手动选择 App 的显示方式。
适配时间节点:2027 年 8 月,Google Play 将要求所有新应用和更新强制 targetSdk 37。
适配建议一:修复相机预览
大屏设备上最常见的问题之一是相机预览变形——预览内容被拉伸、旋转或裁剪。这通常是因为代码里硬编码了屏幕方向与传感器方向的关系。
Google 推荐四种方案(按优先级排列):
方案 1:Jetpack CameraX(首选)
直接用 PreviewView,它会自动处理传感器方向、设备旋转、缩放等所有问题,默认使用 FILL_CENTER 模式保持宽高比,也可以切换为 FIT_CENTER 做 letterbox 处理。
方案 2:CameraViewfinder(适合已有 Camera2 代码的项目)
兼容到 API level 21,基于 TextureView 或 SurfaceView,自动处理所有变换逻辑。
方案 3:手动 Camera2 实现
如果不能引入新库,就必须自行计算。关键点是:
- 从
CameraCharacteristics获取传感器方向(0/90/180/270 度) - 获取当前显示旋转值
- 结合两者计算
SurfaceView/TextureView的变换矩阵
另外特别注意:不要用屏幕尺寸来确定相机预览的尺寸,要用 window metrics,因为 App 可能运行在分屏或桌面窗口模式下。
方案 4:用 Intent 调起系统相机
如果只需要拍照/录像功能,直接发 Intent 调系统相机是最省事的方案,可维护性也最好。
适配建议二:避免 UI 被拉伸或按钮超出屏幕
如果你的布局里有大量 fillMaxWidth 或 match_parent,在手机上好看,在横屏平板上可能被拉伸成很难看的样子。
在 Jetpack Compose 里,用 widthIn 给组件设置最大宽度:
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
Column(
modifier = Modifier
.widthIn(max = 300.dp) // 防止超过 300dp 后继续拉伸
.fillMaxWidth() // 在 300dp 范围内填满
.padding(16.dp)
) {
// Your content
}
}
如果页面底部有「保存」「登录」等操作按钮,在横屏平板上可能直接超出屏幕被遮住,用户根本点不到。加一个 verticalScroll 就能解决:
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(16.dp)
)
适配建议三:处理好配置变更时的状态保存
不允许锁定方向之后,配置变更会发生得更加频繁——用户旋转设备、折叠/展开手机、调整分屏比例,每次都会触发。如果你的 Activity 没有妥善处理,用户会遇到滚动位置重置、表单内容丢失等糟糕体验。
Jetpack Compose 支持在窗口大小变化时只触发重组而不销毁 Activity,配合 rememberSaveable 保存状态,能提供丝滑的自适应体验。参考官方文档:保存 UI 状态。
如何测试?
- 下载 Android 17 Beta,配合 Pixel Tablet / Pixel Fold 模拟器测试
- 将
targetSdkPreview = "CinnamonBun"设置到项目里 - 如果暂时没升到 targetSdk 36,也可以通过应用兼容性框架开启
UNIVERSAL_RESIZABLE_BY_DEFAULT标志提前测试 - Jetpack Compose 用户可以用 Compose UI Check 自动审查布局适配情况
1.2 Bubbles 浮窗模式
Android 17 引入了新的 Bubbles 窗口模式(区别于之前的消息气泡通知 API)。
用户可以长按桌面上的 App 图标,将其作为浮动气泡打开。在大屏设备上,任务栏区域会有一个 Bubble 栏,用户可以自由管理、切换、拖拽这些气泡窗口。
这是系统行为,开发者目前无需主动适配。如果你的 App 有多任务或浮窗相关场景,可以持续关注后续的开发者 API 文档。
1.3 EyeDropper 颜色拾取 API
设计类、创作类 App 的好消息——系统级颜色拾取器来了。
新的
EyeDropper API 允许你的 App 从屏幕上任意位置拾取颜色,不需要截屏权限。使用方式很简单:
val eyeDropperLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result -> if (result.resultCode == Activity.RESULT_OK) {
val color = result.data?.getIntExtra(Intent.EXTRA_COLOR, Color.BLACK)
// 拿到颜色值,在 App 里使用
}
}
fun launchColorPicker() {
val intent = Intent(Intent.ACTION_OPEN_EYE_DROPPER)
eyeDropperLauncher.launch(intent)
}
1.4 联系人选择器(隐私增强)
以前读取联系人需要申请 READ_CONTACTS 权限,这是一个比较重的权限,用户往往会有所顾虑。
Android 17 提供了新的系统级联系人选择器 ACTION_PICK_CONTACTS,只授予 App 本次 Session 内对用户主动选择的特定字段的临时读取权限,不需要申请 READ_CONTACTS 的完整权限。还支持从工作账号档案中选择联系人。
val contactPicker = rememberLauncherForActivityResult(StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val uri = it.data?.data ?: return@rememberLauncherForActivityResult
// 处理联系人结果
processContactPickerResults(uri)
}
}
val dataFields = arrayListOf(Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE)
val intent = Intent(ACTION_PICK_CONTACTS).apply {
putStringArrayListExtra(EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS, dataFields)
putExtra(EXTRA_ALLOW_MULTIPLE, true)
putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
}
contactPicker.launch(intent)
如果你的 App 有读取联系人的场景,可以考虑迁移到这个 API,对用户更友好,审核风险也更低。
1.5 触控板指针捕获优化
对于游戏类或需要捕获鼠标指针的 App,Android 17 改善了触控板的兼容性。
之前触控板捕获后上报的是手指在触控板上的绝对坐标,和鼠标上报的相对位移完全不同,开发者需要写大量兼容代码。现在,系统默认将触控板的手势识别为鼠标事件上报,处理起来简单多了。如果你确实需要原始的手指坐标数据,可以显式请求旧模式:
// 默认:相对移动模式(像鼠标一样)
// 等同于 View.POINTER_CAPTURE_MODE_RELATIVE
view.requestPointerCapture()
// 显式请求旧的绝对坐标模式(原始触点数据)
view.requestPointerCapture(View.POINTER_CAPTURE_MODE_ABSOLUTE)
二、连接与跨设备
2.1 跨设备 Handoff API
新的 Handoff API 让 App 可以将当前的应用状态同步到另一台设备(比如手机正在看的内容,切换到平板继续看)。
使用方式是在 Activity 中调用 setHandoffEnabled(true) 开启,系统会通过 CompanionDeviceManager 同步状态,并在附近设备的启动器上展示「继续」入口。
值得一提的是,Handoff 支持两种路径:
- 原生 App 之间的直接跳转
- App 到 Web 的兜底(如果对方设备没装 App,可以跳转到网页版继续)
这个 API 特别适合阅读、视频、笔记这类有多设备接力使用场景的 App。
2.2 高级测距 API
Android 17 新增了两种测距技术的支持:
- UWB DL-TDOA:用于室内导航,符合 FIRA 4.0 规范,支持隐私保护模式(防止锚点追踪设备位置)
- Proximity Detection:基于 WFA(WiFi 联盟)新规范,可靠性和精度有所提升
如果你在做室内导航、智能家居设备定位或近场交互类 App,可以重点关注这两个 API,具体使用方式参考官方文档。
2.3 获取运营商数据限速信息
如果你的 App 有视频流媒体场景,现在可以查询运营商为流媒体分配的最大上下行速率,从而动态调整媒体质量。通过 SubscriptionManager 获取 SubscriptionInfo 对象后调用:
subscriptionInfo.getStreamingAppMaxDownlinkKbps() // 最大下行速率(Kbps)
subscriptionInfo.getStreamingAppMaxUplinkKbps() // 最大上行速率(Kbps)
三、隐私与安全
3.1 本地网络访问权限
Android 17 新增了 ACCESS_LOCAL_NETWORK 运行时权限,用于保护用户免受未授权的局域网访问。
App 访问 LAN 设备(智能家居、投屏接收器等)现在有两种方式:
- 使用系统提供的设备选择器(隐私友好,无需额外权限)
- 在 Manifest 声明并运行时申请
ACCESS_LOCAL_NETWORK权限
由于该权限属于 NEARBY_DEVICES 权限组,如果用户已授权过蓝牙相关权限,不会再次弹框提醒。
如果你的 App 有连接局域网设备的功能,记得在 Manifest 里声明这个权限,否则在 Android 17 设备上会被拦截。
3.2 OTP 短信保护增强
Android 17 大幅收紧了对含有 OTP 的短信的访问限制,目标是防止恶意应用在用户不知情的情况下读取验证码。
核心规则:对于大多数 App,含有 OTP 的短信只有 3 小时后才能被读取到。 无论是 SMS_RECEIVED_ACTION 广播还是短信数据库查询,都会被延迟。
先看你的 App 是否在受影响范围:
| 场景 | 是否受影响 |
|---|---|
| 读取 WebOTP 格式短信,但 App 不是对应域名归属方 | 受影响,延迟 3 小时 |
| 读取普通 OTP 短信(非 WebOTP / 非 SMS Retriever 格式) | 受影响,延迟 3 小时(targetSdk 37 及以上) |
| 默认短信 App、语音助手、伴侣设备 App | 不受影响 |
WebOTP 场景的具体 targetSdk 生效范围官方文档尚未明确说明,建议参考最新官方文档。
适配建议:如果你的 App 需要读取 OTP,请迁移到 SMS Retriever API 或 SMS User Consent API,这是目前最符合规范的方式。
3.3 NPU 访问需要在 Manifest 声明
如果你的 App 需要直接访问 NPU(Neural Processing Unit,神经网络处理单元),targetSdk 37 后必须在 Manifest 中声明 FEATURE_NEURAL_PROCESSING_UNIT,否则访问会被拦截。
影响范围包括:使用 LiteRT NPU delegate 的 App、使用厂商 NPU SDK 的 App,以及使用已废弃 NNAPI 的 App。
3.4 时区偏移变更广播
Android 17 新增了 ACTION_TIMEZONE_OFFSET_CHANGED 广播,当系统时区偏移发生变化(比如夏令时切换)时触发。
以前的 ACTION_TIMEZONE_CHANGED 只在时区 ID 改变时触发,时区 ID 相同但偏移量变化的情况(比如夏令时)无法被捕获。现在通过这个新广播可以精确感知。
3.5 国际化:ICU 78 + Unicode 17
底层国际化库升级到 ICU 78,支持更多语言脚本、字符和 Emoji,同时支持直接格式化 java.time 时间对象。
四、总结
Android 17 的核心关键词是自适应和隐私。
主要需要适配的地方:
- 大屏自适应(最紧迫):targetSdk 37 后,锁定屏幕方向和宽高比在大屏上彻底失效,需要确保 App 在各种窗口尺寸下都能正常显示
- 相机预览:优先迁移到 CameraX,解决大屏/折叠屏上的预览变形问题
- OTP 短信读取:迁移到 SMS Retriever 或 SMS User Consent API
- 本地网络访问:有 LAN 设备连接功能的 App 需要声明新权限
- NPU 访问:用到端侧推理能力的 App 需要声明
FEATURE_NEURAL_PROCESSING_UNIT
同时,几个新 API 值得关注和使用:
- EyeDropper API:适合设计、调色、创作类 App,无需截屏权限即可拾取颜色
- 联系人选择器:有读取联系人需求的 App,可以用它替代
READ_CONTACTS整体权限,对用户更友好 - 跨设备 Handoff API:阅读、视频、笔记等有多设备接力场景的 App 值得尝鲜
时间节点:Platform Stability 计划在 2026 年 3 月达成,之后可以正式将 targetSdk 设为 37 并发布到 Google Play 收集反馈。Google Play 强制要求的截止日期是 2027 年 8 月。
建议现在就开始用 Android 17 Beta 测一下你的 App,特别是有相机、短信 OTP、局域网设备连接这些功能的,越早发现问题越好。
好了,这篇文章到这里就结束了,感谢你的阅读,愿你平安顺遂。
如果对你有帮助,欢迎评论点赞转发,你的支持是我最大的动力❤️
我转型 AI 工程师的实战笔记与心血结晶都总结到这里了:《转型 AI 工程师|提升竞争力》