Android14 新特性与适配指南

Android 14(API 34)带来了多项行为变更和新特性。

一、核心适配前提

  1. 升级开发环境:
    • Gradle Plugin ≥ 8.0
    • Compile SDK ≥ 34
    • Target SDK ≥ 34(建议,若暂不升级需兼容行为变更)
  2. 依赖库升级:确保 AppCompat、Material、Jetpack 等库至最新版本,避免兼容性问题。

二、关键行为变更适配

1. 权限适配

(1)前台服务类型(Foreground Service Type)强制校验

Android 14 要求所有前台服务必须声明具体的 foregroundServiceType,且仅能使用声明的类型,否则会抛出 SecurityException

适配步骤

  • 步骤1:Manifest 声明前台服务类型
xml 复制代码
<service
    android:name=".MyForegroundService"
    android:foregroundServiceType="location|mediaPlayback"> <!-- 根据业务选择类型 -->
    <intent-filter>
        <action android:name="android.intent.action.FOREGROUND_SERVICE" />
    </intent-filter>
</service>
  • 步骤2:Kotlin 代码中指定类型启动前台服务
kotlin 复制代码
class MyForegroundService : Service() {
    private val NOTIFICATION_ID = 1001
    private val CHANNEL_ID = "foreground_service_channel"

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        createNotificationChannel()
        // 构建前台服务通知
        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("前台服务标题")
            .setContentText("前台服务内容")
            .setSmallIcon(R.mipmap.ic_launcher)
            .build()
        
        // Android 14+ 必须指定前台服务类型
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            startForeground(
                NOTIFICATION_ID,
                notification,
                ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION // 与Manifest声明一致
            )
        } else {
            startForeground(NOTIFICATION_ID, notification)
        }
        return START_STICKY
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "前台服务通道",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            val notificationManager = getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(channel)
        }
    }

    override fun onBind(intent: Intent?): IBinder? = null
}
(2)新增权限:POST_NOTIFICATIONS 强制校验

Android 13 引入的通知权限,Android 14 强化了校验,未授权时无法发送通知(包括前台服务通知)。

适配代码

kotlin 复制代码
// 检查并请求通知权限
private fun requestNotificationPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        val notificationManager = getSystemService(NotificationManager::class.java)
        if (!notificationManager.areNotificationsEnabled()) {
            val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
                putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
            }
            startActivity(intent)
            // 或通过权限请求弹窗(Android 13+)
            /*
            ActivityResultContracts.RequestPermission().launch(Manifest.permission.POST_NOTIFICATIONS) { granted ->
                if (granted) {
                    // 权限已授予,启动前台服务
                } else {
                    // 引导用户手动开启
                }
            }
            */
        }
    }
}

2. 应用内安装权限适配

Android 14 要求安装 APK 时必须申请 REQUEST_INSTALL_PACKAGES 权限,且新增了 PackageInstaller 的安全校验。

适配代码

kotlin 复制代码
// 1. 检查安装权限
private fun checkInstallPermission(context: Context): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.packageManager.canRequestPackageInstalls()
    } else {
        true // 低版本无需校验
    }
}

// 2. 请求安装权限
private fun requestInstallPermission(activity: Activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !checkInstallPermission(activity)) {
        val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
            data = Uri.parse("package:${activity.packageName}")
        }
        activity.startActivityForResult(intent, REQUEST_INSTALL_PERMISSION)
    }
}

// 3. 使用PackageInstaller安装APK(Android 14推荐方式)
private fun installApkWithPackageInstaller(context: Context, apkPath: String) {
    val packageInstaller = context.packageManager.packageInstaller
    val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
    val sessionId = packageInstaller.createSession(params)
    val session = packageInstaller.openSession(sessionId)

    // 写入APK文件
    val inputStream = FileInputStream(apkPath)
    val outputStream = session.openWrite("apk_install", 0, -1)
    inputStream.copyTo(outputStream)
    session.fsync(outputStream)
    inputStream.close()
    outputStream.close()

    // 提交安装
    val intent = Intent(context, InstallResultReceiver::class.java)
    val pendingIntent = PendingIntent.getBroadcast(
        context,
        0,
        intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // Android 12+ 必须加FLAG_IMMUTABLE
    )
    session.commit(pendingIntent.intentSender)
    session.close()
}

// 接收安装结果的广播接收器
class InstallResultReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val status = intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE)
        val message = intent?.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
        when (status) {
            PackageInstaller.STATUS_SUCCESS -> {
                // 安装成功
            }
            else -> {
                // 安装失败
            }
        }
    }
}

3. 后台弹出窗口权限适配

Android 14 限制了后台应用弹出窗口,需申请 SYSTEM_ALERT_WINDOW 权限,且仅前台应用可弹出窗口。

适配代码

kotlin 复制代码
// 检查悬浮窗权限
private fun checkOverlayPermission(context: Context): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Settings.canDrawOverlays(context)
    } else {
        true
    }
}

// 请求悬浮窗权限
private fun requestOverlayPermission(activity: Activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkOverlayPermission(activity)) {
        val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply {
            data = Uri.parse("package:${activity.packageName}")
        }
        activity.startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION)
    }
}

4. PendingIntent 兼容性适配

Android 14 要求 PendingIntent 必须指定 FLAG_IMMUTABLEFLAG_MUTABLE,否则会抛出异常。

适配代码

kotlin 复制代码
// 正确创建PendingIntent(Android 12+ 适配)
private fun createPendingIntent(context: Context): PendingIntent {
    val intent = Intent(context, MyReceiver::class.java)
    val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    } else {
        PendingIntent.FLAG_UPDATE_CURRENT
    }
    return PendingIntent.getBroadcast(context, 0, intent, flags)
}

三、Android 14 新特性接入

1. 实时文本(Live Text)支持

Android 14 新增实时文本 API,可提取图片中的文本,支持中文等多语言。

适配代码

kotlin 复制代码
// 提取图片中的文本
private suspend fun extractTextFromImage(context: Context, bitmap: Bitmap): String {
    return withContext(Dispatchers.IO) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            val liveTextManager = context.getSystemService(LiveTextManager::class.java)
            val result = liveTextManager.processImage(bitmap)
            result.text ?: ""
        } else {
            "" // 低版本降级处理
        }
    }
}

2. 锁屏小组件(Lock Screen Widgets)

Android 14 支持锁屏添加小组件,需适配小组件的尺寸和交互。

适配代码

kotlin 复制代码
// 定义锁屏小组件(继承AppWidgetProvider)
class LockScreenWidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        appWidgetIds.forEach { widgetId ->
            val views = RemoteViews(context.packageName, R.layout.widget_lock_screen)
            // 设置小组件内容
            views.setTextViewText(R.id.widget_text, "锁屏小组件示例")
            // 适配锁屏尺寸(Android 14新增尺寸)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
                views.setInt(R.id.widget_root, "setMinimumWidth", 300)
                views.setInt(R.id.widget_root, "setMinimumHeight", 150)
            }
            appWidgetManager.updateAppWidget(widgetId, views)
        }
    }
}

// Manifest声明锁屏小组件
<receiver
    android:name=".LockScreenWidget"
    android:label="锁屏小组件">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/widget_lock_screen_info" />
</receiver>

3. 拍照/录像 API 增强

Android 14 新增 CameraManager.AvailabilityCallback 回调,优化相机设备状态监听。

适配代码

kotlin 复制代码
// 监听相机可用性
private fun monitorCameraAvailability(context: Context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        val cameraManager = context.getSystemService(CameraManager::class.java)
        cameraManager.registerAvailabilityCallback(object : CameraManager.AvailabilityCallback() {
            override fun onCameraAvailable(cameraId: String) {
                // 相机可用
            }

            override fun onCameraUnavailable(cameraId: String) {
                // 相机不可用
            }
        }, Handler(Looper.getMainLooper()))
    }
}

四、适配注意事项

  1. 分区适配 :使用 Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE 做版本判断,避免低版本崩溃。
  2. 权限申请时机:权限申请需在用户交互时触发(如点击按钮),否则系统会拒绝。
  3. FLAG_IMMUTABLE :所有 PendingIntent 必须指定 FLAG_IMMUTABLE(非交互场景)或 FLAG_MUTABLE(交互场景)。
  4. 测试覆盖
    • 测试 Target SDK 34 下的行为;
    • 测试未授予权限时的降级逻辑;
    • 测试后台启动、弹窗、安装等场景的权限校验。
  5. 隐私合规:新增权限需在隐私政策中说明用途,符合应用商店审核要求。

五、参考资源

六、总结

Android 14 的适配核心围绕权限强化安全校验新 API 接入展开,重点关注前台服务、安装权限、PendingIntent 等关键变更。通过版本判断做分区适配,确保低版本兼容,同时接入实时文本、锁屏小组件等新特性,提升应用体验。

所有代码均基于 Kotlin 编写,适配了 Android 14 的核心变更,可直接集成到项目中,建议根据业务场景调整细节。

相关推荐
有位神秘人1 天前
Android中Notification的使用详解
android·java·javascript
·云扬·1 天前
MySQL Binlog落盘机制深度解析:性能与安全性的平衡艺术
android·mysql·adb
独自破碎E1 天前
【BISHI9】田忌赛马
android·java·开发语言
代码s贝多芬的音符1 天前
android 两个人脸对比 mlkit
android
darkb1rd1 天前
五、PHP类型转换与类型安全
android·安全·php
gjxDaniel1 天前
Kotlin编程语言入门与常见问题
android·开发语言·kotlin
csj501 天前
安卓基础之《(22)—高级控件(4)碎片Fragment》
android
峥嵘life1 天前
Android16 【CTS】CtsMediaCodecTestCases等一些列Media测试存在Failed项
android·linux·学习
stevenzqzq1 天前
Compose 中的状态可变性体系
android·compose
似霰1 天前
Linux timerfd 的基本使用
android·linux·c++