一、安卓15核心新特性
安卓15(API 35)聚焦隐私安全强化、性能优化、开发效率提升三大方向,以下是对开发者影响最大的核心特性:
1. 隐私与安全增强
(1)照片选择器增强(Photo Picker)
- 新增按日期/文件夹筛选能力,支持批量选择媒体文件时的精细化控制;
- 强制要求第三方应用通过系统照片选择器访问媒体文件,禁止直接访问存储目录(除非申请特殊权限)。
(2)权限精细化管控
- 位置权限 :新增
ACCESS_FINE_LOCATION_BACKGROUND,区分前台/后台精确定位权限; - 通知权限:禁止应用静默发送通知,必须通过系统弹窗让用户明确授权;
- 剪贴板权限:仅允许应用在前台时访问剪贴板,后台访问需用户临时授权。
(3)应用签名与验证强化
- 强制要求应用使用v4签名方案,旧版v1/v2签名在部分设备上受限;
- 新增APK完整性校验机制,篡改后的APK无法安装运行。
2. 性能与体验优化
(1)后台任务限制升级
- 严格限制后台服务的CPU/内存占用,非白名单应用后台运行时长缩短至10分钟;
- 新增
BackgroundTaskManagerAPI,可监控应用后台任务资源使用情况。
(2)UI渲染优化
- 支持动态刷新率自适应 (120Hz/60Hz自动切换),新增
DisplayRefreshRateCallback; - 优化Compose渲染性能,Compose 1.7与安卓15深度适配,减少重组耗时。
(3)电池续航优化
- 新增
BatterySaverManagerAPI,可监听省电模式状态并主动适配低功耗逻辑; - 后台唤醒锁(WakeLock)使用限制加强,滥用会触发系统警告。
3. 开发效率特性
(1)Kotlin优先支持
- 安卓15 SDK中90%以上的新API仅提供Kotlin版本,Java版本为兼容层(功能受限);
- 新增Kotlin协程适配的系统API(如
CoroutineScope绑定生命周期)。
(2)模块化与动态功能
- 动态功能模块(Dynamic Feature)支持按需加载资源,无需重启应用;
- 新增
ModuleInstallerAPI,简化动态模块安装流程。
(3)调试工具增强
- Logcat新增进程/线程过滤,支持自定义日志标签高亮;
- Profiler新增"后台资源占用"面板,可实时监控后台任务消耗。
4. 其他关键特性
- 折叠屏适配增强 :新增
FoldableDeviceInfoAPI,支持检测折叠状态、铰链角度; - 5G网络优化 :新增
5GNetworkCallback,监听5G网络切换/信号强度; - 无障碍升级:支持自定义无障碍焦点,优化屏幕阅读器对Compose组件的识别。
二、安卓15适配指南
适配核心原则:最小化适配(兼容低版本)+ 逐步迁移(利用新特性),以下是关键适配点及代码实现。
1. 环境准备
(1)升级开发工具
- Android Studio升级至Hedgehog | 2023.1.1及以上;
- 项目
build.gradle配置:
kotlin
android {
compileSdk = 35 // 编译版本升级至安卓15
defaultConfig {
minSdk = 21 // 按需设置最低版本,建议保留21+
targetSdk = 35 // 目标版本设为35
}
}
dependencies {
// 升级Kotlin版本至1.9.0+
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.20"
// 升级Compose(如需)
implementation "androidx.compose.ui:ui:1.7.0"
// 升级核心库
implementation "androidx.core:core-ktx:1.12.0"
}
2. 隐私权限适配
(1)照片选择器适配(替代READ_EXTERNAL_STORAGE)
kotlin
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun PhotoPickerAdapter() {
// 安卓15+照片选择器(支持按日期筛选)
val photoPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri: Uri? ->
uri?.let {
// 处理选中的图片
handleSelectedImage(it)
}
}
)
Column {
Button(
onClick = {
val request = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
// 安卓15+:按日期筛选(近30天)
PickVisualMediaRequest(
mediaType = ActivityResultContracts.PickVisualMedia.ImageOnly,
filter = MediaStore.Images.Media.DATE_TAKEN_GTE to System.currentTimeMillis() - 30 * 24 * 60 * 60 * 1000
)
} else {
// 低版本兼容
PickVisualMediaRequest(mediaType = ActivityResultContracts.PickVisualMedia.ImageOnly)
}
photoPickerLauncher.launch(request)
}
) {
Text("选择近30天的照片")
}
}
}
private fun handleSelectedImage(uri: Uri) {
// 处理图片逻辑(如显示、上传)
}
(2)后台位置权限适配
kotlin
import android.Manifest
import android.os.Build
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun LocationPermissionAdapter() {
// 安卓15+后台精确定位权限
val backgroundFineLocationPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
Manifest.permission.ACCESS_FINE_LOCATION_BACKGROUND
} else {
Manifest.permission.ACCESS_BACKGROUND_LOCATION
}
val backgroundLocationPermissionState = rememberPermissionState(backgroundFineLocationPermission)
Column {
Button(
onClick = {
if (backgroundLocationPermissionState.status.isGranted) {
// 权限已授予,执行后台定位逻辑
startBackgroundLocationTracking()
} else {
// 请求权限
backgroundLocationPermissionState.launchPermissionRequest()
}
}
) {
Text("申请后台定位权限")
}
}
}
private fun startBackgroundLocationTracking() {
// 后台定位逻辑(需结合WorkManager/Service)
}
3. 后台任务适配
(1)后台任务资源监控
kotlin
import android.os.Build
import android.os.PowerManager
import androidx.annotation.RequiresApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class BackgroundTaskManagerAdapter {
// 安卓15+后台任务资源监控
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
fun monitorBackgroundTask(powerManager: PowerManager) {
val backgroundTaskManager = powerManager.backgroundTaskManager
// 监听后台任务CPU占用
backgroundTaskManager.registerCallback(
CoroutineScope(Dispatchers.Main),
object : PowerManager.BackgroundTaskManager.Callback() {
override fun onTaskResourceOverLimit(taskId: Int, resourceType: Int) {
super.onTaskResourceOverLimit(taskId, resourceType)
// 后台任务资源超限,停止/优化任务
stopOverLimitBackgroundTask(taskId)
}
}
)
}
private fun stopOverLimitBackgroundTask(taskId: Int) {
// 停止超限的后台任务
}
}
4. 折叠屏/显示适配
kotlin
import android.os.Build
import android.view.Display
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@Composable
fun FoldableDeviceAdapter() {
val context = LocalContext.current
var foldState by remember { mutableStateOf("未知") }
LaunchedEffect(Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
// 安卓15+折叠屏状态检测
getFoldableDeviceState(context.display, onStateChanged = { state ->
foldState = state
})
}
}
Text(
text = "折叠屏状态:$foldState",
modifier = Modifier.fillMaxSize()
)
}
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private fun getFoldableDeviceState(
display: Display?,
onStateChanged: (String) -> Unit
) {
display?.let {
val foldableInfo = it.foldableDeviceInfo
// 监听折叠状态
foldableInfo.registerCallback(object : Display.FoldableDeviceInfo.Callback() {
override fun onFoldStateChanged(foldState: Int) {
super.onFoldStateChanged(foldState)
val state = when (foldState) {
Display.FoldableDeviceInfo.FOLD_STATE_FOLDED -> "折叠"
Display.FoldableDeviceInfo.FOLD_STATE_UNFOLDED -> "展开"
else -> "部分折叠"
}
onStateChanged(state)
}
override fun onHingeAngleChanged(hingeAngle: Float) {
super.onHingeAngleChanged(hingeAngle)
onStateChanged("铰链角度:$hingeAngle°")
}
})
}
}
5. 签名与安装适配
(1)升级APK签名方案
在build.gradle中配置v4签名:
kotlin
android {
signingConfigs {
release {
storeFile file("keystore.jks")
storePassword "your_store_password"
keyAlias "your_key_alias"
keyPassword "your_key_password"
// 启用v4签名(安卓15强制)
enableV4Signing = true
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
6. 低版本兼容最佳实践
kotlin
import android.os.Build
import androidx.annotation.RequiresApi
// 封装版本判断工具类
object AndroidVersionUtils {
val isAndroid15Plus: Boolean
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM
// 安卓15+特性封装
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
fun <T> runOnAndroid15(block: () -> T): T? {
return if (isAndroid15Plus) block() else null
}
// 低版本兼容逻辑
fun <T> runOnBelowAndroid15(block: () -> T): T? {
return if (!isAndroid15Plus) block() else null
}
}
// 使用示例
fun initAppFeatures() {
// 安卓15+初始化新特性
AndroidVersionUtils.runOnAndroid15 {
initBackgroundTaskMonitor()
initFoldableDeviceSupport()
}
// 低版本兼容逻辑
AndroidVersionUtils.runOnBelowAndroid15 {
initLegacyBackgroundTask()
initLegacyDisplaySupport()
}
}
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private fun initBackgroundTaskMonitor() {
// 安卓15+后台任务监控
}
private fun initLegacyBackgroundTask() {
// 低版本后台任务逻辑
}
三、适配注意事项
- 分阶段适配 :先将
targetSdk升级至35,修复权限/后台任务相关报错,再逐步接入安卓15新API; - 测试覆盖:使用Android Studio的"API 35模拟器"测试,重点验证隐私权限、后台任务、折叠屏适配;
- 性能监控:安卓15对应用卡顿/ANR的检测更严格,需通过Profiler优化UI渲染和后台任务;
- 权限说明:在应用隐私政策中明确说明安卓15新增权限的使用场景,避免审核驳回;
- 降级策略:所有新API调用必须加版本判断,确保低版本设备正常运行。