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 的核心变更,可直接集成到项目中,建议根据业务场景调整细节。

相关推荐
技术摆渡人2 小时前
Android系统技术探索(1)启动流程
android
介一安全5 小时前
【Frida Android】实战篇12:企业常用对称加密场景 Hook 教程
android·网络安全·逆向·安全性测试·frida
モンキー・D・小菜鸡儿5 小时前
Android15 新特性与适配指南
android·kotlin·安卓新特性
星环处相逢5 小时前
MySQL数据库索引与事务:从基础到实践的全面解析
android
Kin__Zhang5 小时前
随手记录 UE4/CARLA 仿真器 segmentation fault
android·java·ue4
明君879975 小时前
Flutter横向树形选择器实现方案
android·ios
儿歌八万首6 小时前
Jetpack Compose 实战:实现手势缩放图片 (Zoomable Image) 组件
kotlin·android jetpack
CrazyQ16 小时前
flutter_easy_refresh在3.38.3配合NestedScrollView的注意要点。
android·flutter·dart
モンキー・D・小菜鸡儿6 小时前
Android13 新特性与适配指南
gitee·kotlin·安卓新特性