Android 14 快速适配要点

news2024/12/23 13:25:41

随着 Google I/O 2023 发布的 Android beta2 ,预计 Android 14 将在2023年第三季度发布,目前看整体需要适配的内容已经趋向稳定,那就根据官方文档简单做个适配要点总结吧。

如何做到最优雅的版本适配?那就是尽可能提高 minitSdkVersion ,说服老板相信低版本用户无价值论,低版本用户更多是羊毛党~

针对 Android 14 或更高版本的应用

这部分主要是影响 targetSdkVersion 34 的情况 ,目前 Google Play 已经开始要求 33 了,相信未来 34 也不远了。

前台服务类型

targetSdkVersion 34 的情况下,必须为应用内的每个前台服务(foreground-services) 指定至少一种前台服务类型。

前台服务类型是在 Android 10 引入的,通过 android:foregroundServiceType 可以指定 <service> 的服务类型,可供选择的前台服务类型有:

  • camera
  • connectedDevice
  • dataSync
  • health
  • location
  • mediaPlayback
  • mediaProjection
  • microphone
  • phoneCall
  • remoteMessaging
  • shortService
  • specialUse
  • systemExempted

例如:

<manifest ...>
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
    <application ...>
      <service
          android:name=".MyMediaPlaybackService"
          android:foregroundServiceType="mediaPlayback"
          android:exported="false">
      </service>
    </application>
</manifest>

如果你 App 中的用例与这些类型中的任何一种都不相关,那么建议还是将服务迁移成 WorkManager 或 jobs 。

更多详细可见:https://developer.android.com/about/versions/14/changes/fgs-types-required

安全

对 pending/implicit intent 的限制

对于面向 Android 14 的应用,Android 通过以下方式限制应用向内部应用组件发送隐式 intent:

  • 隐式 intent 仅传递给导出的组件,应用必须使用明确的 intent 来交付给未导出的组件,或者将组件标记为已导出(exported) 。
  • 如果应用创建一个 mutable pending intent ,但 intent 未指定组件或包,系统现在会抛出异常。

这些更改可防止恶意应用拦截只供给用内部组件使用的隐式 intent,例如:

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

如果应用尝试使用隐式 intent 启动该 activity,则会抛出异常:

// Throws an exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))

要启动未导出的 Activity,应用应改用显式 Intent:

// This makes the intent explicit.
val explicitIntent =
        Intent("com.example.action.APP_ACTION")
explicitIntent.apply {
    package = context.packageName
}
context.startActivity(explicitIntent)

运行时注册的广播接收器必须指定导出行为

以 Android 14 为目标,并使用 context-registered receivers (ContextCompat.registerReceiver)应用和服务的需要指定一个标志,以指示接收器是否应导出到设备上的所有其他应用:分别为 RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED

val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
val listenToBroadcastsFromOtherApps = false
val receiverFlags = if (listenToBroadcastsFromOtherApps) {
    ContextCompat.RECEIVER_EXPORTED
} else {
    ContextCompat.RECEIVER_NOT_EXPORTED
}
ContextCompat.registerReceiver(context, br, filter, receiverFlags)

仅接收系统广播的接收器例外

如果应用仅通过 Context#registerReceiver 方法为系统广播注册接收器时,那么它可以不在注册接收器时指定标志, 例如 android.intent.action.AIRPLANE_MODE

更安全的动态代码加载

如果应用以 Android 14 为目标平台并使用动态代码加载 (DCL),则所有动态加载的文件都必须标记为只读,否则,系统会抛出异常。

我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而受到危害的风险。

如果必须动态加载代码,请使用以下方法将动态加载的文件(例如 DEX、JAR 或 APK 文件)在文件打开后和写入任何内容之前立即设置为只读:

val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
os.use {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly()
    // Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)

处理已存在的动态加载文件

为防止现有动态加载文件抛出异常,我们建议可以尝试在应用中再次动态加载文件之前,删除并重新创建这些文件。

重新创建文件时,请按照前面的指导在写入时将文件标记为只读,或者将现有文件重新标记为只读,但在这种情况下,强烈建议首先验证文件的完整性(例如,通过根据可信值检查文件的签名),以帮助保护应用免受恶意操作。

Zip path traversal

对于针对 Android 14 的应用,Android 通过以下方式防止 Zip 路径遍历漏洞:如果 zip 文件条目名称包含 “…” 或以 “/” 开头,则 ZipFile(String)ZipInputStream.getNextEntry() 会抛出一个 ZipException

应用可以通过调用 dalvik.system.ZipPathValidator.clearCallback() 选择退出验证。

从后台启动活动的附加限制

针对 Android 14 的应用,系统进一步限制了应用在后台启动 Activity 的时间:

  • 当应用使用 [PendingIntent#send()](https://developer.android.com/reference/android/app/PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String, android.os.Bundle)) 发送 PendingIntent 以及类似行为时,如果应用想要授予其自己的后台 service 启动权限以启动 pending intent,则该应用现在必须选择加入一个 ActivityOptions ,具体为带有 setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)

  • 当一个可见应用使用 [bindService()](https://developer.android.com/reference/android/content/Context#bindService(android.content.Intent, android.content.Context.BindServiceFlags, java.util.concurrent.Executor, android.content.ServiceConnection)) 绑定另一个在后台运行的应用的服务时,如果该可见应用想要将其自己的后台 activity 启动权限授予绑定服务,则它现在必须选择加入 BIND_ALLOW_ACTIVITY_STARTS 标志。

这些更改扩展了现有的一组限制 ,通过防止恶意应用滥用 API 从后台启动破坏性活动来保护用户。

具体可见:https://developer.android.com/guide/components/activities/background-starts

OpenJDK 17

Android 14 会要求的 OpenJDK 17 的支持,这对一些语法上可以会有一定影响,例如:

  • 对正则表达式的更改:现在不允许无效的组引用
  • UUID 处理java.util.UUID.fromString() 方法现在在验证输入参数时会进行更严格的检查
  • ProGuard 问题:在某些情况下,如果使用 ProGuard 缩小、混淆和优化应用,添加 java.lang.ClassValue 会导致出现问题,问题源于 Kotlin 库,库会根据是否 Class.forName("java.lang.ClassValue") 返回类来更改运行时行为。

反正适配 OpenJDK 17 就对了,新版 Android Studio Flamingo 也默认内置 OpenJDK 17 了。

针对所有版本的 Android 14 变更

以下行为主要针对在 Android 14 上运行的所有应用,可以看到从 Android 10 开始, Androd Team 针对这些变动越来越强势。

核心功能

默认情况下拒绝计划精确提醒

精确提醒(Exact alarms)用于用户有目的的通知,或用于需要在精确时间发生的操作情况,从 Android 14 开始,该 SCHEDULE_EXACT_ALARM 权限不再预先授予大多数新安装的针对 Android 13 及更高版本的应用,默认情况下该权限会被拒绝。

如果用户通过备份还原操作将应用数据传输到运行Android 14 的设备上,权限仍然会被拒绝。如果现有的应用已经拥有该权限,它将在设备升级到 Android 14 时预先授予。

而现在需要权限 SCHEDULE_EXACT_ALARM 才能通过以下 API 启动确切的提醒,否则将抛出 SecurityException

  • [setExact()](https://developer.android.com/reference/android/app/AlarmManager#setExact(int, long, android.app.PendingIntent))
  • [setExactAndAllowWhileIdle()](https://developer.android.com/reference/android/app/AlarmManager#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent))
  • [setAlarmClock()](https://developer.android.com/reference/android/app/AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent))

**注意:**如果确切的 alarms 是使用 OnAlarmListener 对象设置的,例如在 [setExact](https://developer.android.com/reference/android/app/AlarmManager#setExact(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler)) API 中,SCHEDULE_EXACT_ALARM 则不需要权限。

现有的权限最佳实践 SCHEDULE_EXACT_ALARM 仍然适用,包括以下内容:

  • 在安排确切的提醒之前检查权限 canScheduleExactAlarms()
  • 设置应用以 AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 监听前台广播并对其做出正确反应 ,系统会在用户授予权限时发送该广播。

详细可见:https://developer.android.com/about/versions/14/changes/schedule-exact-alarms

Context-registered 广播在缓存应用时排队

在 Android 14 上,当应用处于缓存状态时,系统可能会将上下文注册的广播放入队列中。

这类似于 Android 12(API 级别 31)为异步活页夹事务引入的排队行为,清单声明的广播不会排队,并且应用会从缓存状态中删除以进行广播传输。

当应用离开缓存状态时,例如返回前台,系统会传送任何排队中的广播,某些广播的多个实例可以合并为一个广播。

根据其他因素(例如系统运行状况),应用可能会从缓存状态中删除,并且先前排队的所有广播都会被传送。

应用只能杀死自己的后台进程

从 Android 14 开始,应用调用 killBackgroundProcesses() 时,该 API 只能杀死自己应用的后台进程。

如果传入其他应用的包名,该方法对该应用的后台进程没有影响,Logcat中会出现如下信息:

Invalid packageName: com.example.anotherapp

应用不应该使用 killBackgroundProcesses() API ,或以其他方式尝试影响其他应用的进程生命周期,即使是在较旧的操作系统版本上。

Android 旨在将缓存的应用保留在后台,并在系统需要内存时自动终止它们,如果应用出现不必要地杀死其他应用,它会降低系统性能并增加电池消耗,因为稍后需要完全重启这些应用,比恢复现有的缓存应用占用的资源要多得多。

安全

最低可安装目标 API 级别

从 Android 14 开始,无法安装 targetSdkVersion 低于 23 的应用 ,要求应用必须满足这些最低目标 API 级别,这样可以提高用户的安全性和隐私性。

恶意软件通常以较旧的 API 级别为 target,以绕过较新 Android 版本中引入的安全和隐私保护,例如一些恶意软件应用使用 targetSdkVersion 22 的来避免受到 Android 6.0 的运行时权限模型的约束。

Android 14 的这一变化使恶意软件更难避开安全和隐私管理,尝试安装针对较低 API 级别的应用将导致安装失败,并在 Logcat 中显示以下消息:

INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 23, but found 7

在升级到 Android 14 的设备上,任何低于targetSdkVersion 23 的应用都将保持安装状态,如果你需要针对较旧 API 级别的应用进行测试,请使用以下 ADB 命令:

adb install --bypass-low-target-sdk-block FILENAME.apk

用户体验

授予对照片和视频的部分访问权限

**注意:**如果你的应用已经使用了系统照片选择器(photopicker),那么无需进行任何改动。

在 Android 14 上,当应用请求 Android 13(API 级别 33)中引入的任何 READ_MEDIA_IMAGES READ_MEDIA_VIDEO 媒体权限时,用户可以授予对其照片和视频的部分访问权限。

新对话框显示以下权限选项:

  • 选择照片和视频: Android 14 中的新功能,用户选择他们想要提供给应用的特定照片和视频。
  • 全部允许:用户授予对设备上所有照片和视频的完整库访问权限。
  • 不允许:用户拒绝所有访问。

要在应用中出现改逻辑,可以声明新的 READ_MEDIA_VISUAL_USER_SELECTED 权限。

详细可见:https://developer.android.com/about/versions/14/changes/partial-photo-video-access

安全的全屏 Intent 通知

在 Android 11(API 级别 30)中,任何应用都可以通过 [Notification.Builder.setFullScreenIntent ](https://developer.android.com/reference/android/app/Notification.Builder#setFullScreenIntent(android.app.PendingIntent, boolean)) 在手机锁定时发送全屏 intent。

一般可以通过在 AndroidManifest 中声明 USE_FULL_SCREEN_INTENT 权限来在应用安装时自动授予该权限 ,全屏 intent 通知专为需要用户立即关注的极高优先级通知而设计,例如来电或用户配置的闹钟设置。

从 Android 14 开始,允许使用该权限的应用仅限于提供通话和闹钟的应用,Google Play 商店会撤销任何不符合该配置文件的应用的默认权限。

在用户更新到 Android 14 之前,该权限对安装在手机上的应用保持启用状态,用户可以打开和关闭该权限。

开发者可以使用新的API NotificationManager.canUseFullScreenIntent 来检查应用是否具有权限;如果没有,应用可以使用新的 ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT 来启动跳转到可以授予权限的设置页面。

改变用户体验不可关闭通知的方式

如果你的应用向用户显示不可关闭的前台通知,Android 14 已更改行为以允许用户关闭此类通知。

此次更改适用于通过 Notification.Builder#setOngoing(true) 或者 NotificationCompat.Builder#setOngoing(true) 来设置 Notification.FLAG_ONGOING_EVENT 从而阻止用户关闭前台通知的应用 的行为。

现在 FLAG_ONGOING_EVENT 的行为已经改变,用户实际上可以关闭此类通知。

在以下情况下,该类通知仍然不可关闭:

  • 当手机被锁定时
  • 如果用户选择清除所有通知操作(这有助于防止意外)

此外,新行为不适用于以下用例中的不可关闭通知:

  • 使用 CallStyle与真实通话相关的通知
  • 使用 MediaStyle 创建的通知
  • 设备策略控制器 (DPC) 和企业支持包

辅助功能

非线性字体缩放至 200%

从 Android 14 开始,系统支持高达 200% 的字体缩放,为弱视用户提供符合 Web 内容无障碍指南 (WCAG) 的额外无障碍选项。

如果已经使用缩放像素 (sp) 单位来定义文本大小,那么此次更改可能不会对应用产生重大影响。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详细版易学版TypeScript - 类型声明:字符串数字null布尔undefined数组any对象void类型推断联合类型

根据官方 TypeScript 的注意事项&#xff0c;建议不要使用 Number、String、Boolean、Symbol 或 Object。 ts各类型声明的代码如下&#xff1a; 一、字符串类型 let str: string hello; str ts; 二、数字类型 let num: number 123; num 456; 三、布尔类型 let flag: boolea…

C语言实现队列--数据结构

&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️ &#x1f4a5;个人主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王&#x1f525;&#x1f525;&#x1f525; &#x1f4a5;代码仓库&#xff1a;&#x1f525;&#x1f525;魔…

No.065<软考>《(高项)备考大全》【专项3】《论文》

《论文》 1 论文部分相关1.1 考试相关1.2 考试核心相关1.3 历年考试分析1.4 复习建议1.5 评分标准1.5.1 评分的几个方面1.5.2 不及格的几种类型1.5.3 扣分项1.5.4 加分项 1.6 时间进度安排1.7 如何准备 2 必背核心知识 - 10大领域47个过程3 论文写作技巧3.1 论文架构3.2 论文题…

SpringBoot——引导类的简单介绍

简单介绍&#xff1a; 之前我们就说到过引导类&#xff0c;之不过当时就是简单的说了一下这个名字&#xff0c;让大家记住我们运行的程序的学名叫做引导类&#xff0c;但是我们并没有进入看过&#xff0c;介绍过它的作用&#xff0c;这次我们就来简单的介绍一下这个类的作用。…

[NLP] SentenceTransformers使用介绍

SentenceTransformers 是一个可以用于句子、文本和图像嵌入的Python库。 可以为 100 多种语言计算文本的嵌入并且可以轻松地将它们用于语义文本相似性、语义搜索和同义词挖掘等常见任务。 该框架基于 PyTorch 和 Transformers&#xff0c;并提供了大量针对各种任务的预训练模型…

STEP7-MicroWin SMART中修改变量注释的具体方法(绝对寻址+符号寻址)

STEP7-MicroWin SMART中修改变量注释的具体方法(绝对寻址+符号寻址) 如下图所示,我们可以在符号表中定义变量的符号名称以及注释信息, 使用时需注意以下事项: 1.在 STEP 7-Micro/WIN SMART 软件中,可以建立多个符号表,但不允许将相同的符号名多次用作全局符号赋值,在单…

1707_Python中的多成员处理

全部学习汇总&#xff1a; GreyZhang/python_basic: My learning notes about python. (github.com) 欢迎路过的YUAN类朋友们&#xff0c;希望我们能够相互交流共同成长。如有错误或者不足希望及时指点指出&#xff0c;不胜感激&#xff01;以下是我的联系方式&#xff1a; E…

Kali-linux识别活跃的主机

尝试渗透测试之前&#xff0c;必须先识别在这个目标网络内活跃的主机。在一个目标网络内&#xff0c;最简单的方法将是执行ping命令。当然&#xff0c;它可能被一个主机拒绝&#xff0c;也可能被接收。本节将介绍使用Nmap工具识别活跃的主机。 网络映射器工具Nmap Nmap是一个…

JavaScript经典教程(七)-- JavaScript中级

197&#xff1a;in、预解析、变量提升、对象引用、Date对象 1、预解析 即&#xff0c;把var的变量在&#xff0c;作用域下&#xff0c;提前&#xff1b; &#xff08;1&#xff09;JS代码运行原理 预先解析&#xff0c;JS第一次解析代码叫预解析。 JS本身会解析两次代码&a…

vue非单文件组件

非单文件组件指的是&#xff1a;一个文件中包含了多个组件。 Vue 中使用组件的三大步骤&#xff1a;1. 创建组件、2. 注册组件、3. 使用组件。 组件使用流程【第一步&#xff1a;创建组件】 利用 Vue.extend() 方法创建组件: // 第一步&#xff1a;创建 frameHead 组件 cons…

前端015_标签模块_删除功能

标签模块_删除功能 1、需求分析2、EasyMock 添加模拟接口3、Api 调用接口4、测试1、需求分析 当点击删除按钮后, 弹出提示框。点击确定后,执行删除并刷新列表数据 确认消息弹框参考:https://element.eleme.cn/#/zh-CN/component/message-box#que-ren-xiao-xi 2、EasyMock …

【AUTOSAR】【以太网】TCPIP

目录 一、概述 二、约束和假设 三、依赖模块 3.1 EthIf 3.2 EthSM 3.3 SoAd 3.4 KeyM 3.5 CSM 四、功能说明 4.1 系统扩展性 4.2 IPv4 4.2.1 IPv4 4.2.2 ARP 4.2.3 Auto-IP 4.2.4 ICMP 4.3 IPv6 4.4 IPSec 4.5 基于IP的协议 4.5.1 本地地址表 4.5.2 UDP 4…

音视频八股文(12)-- ffmpeg 音频重采样

1重采样 1.1 什么是重采样 所谓的重采样&#xff0c;就是改变⾳频的采样率、sample format、声道数等参数&#xff0c;使之按照我们期望的参数输出。 1.2 为什么要重采样 为什么要重采样&#xff1f;当然是原有的⾳频参数不满⾜我们的需求&#xff0c;⽐如在FFmpeg解码⾳频…

【C++初阶】类和对象(四)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C初阶】…

(二)zookeeper实战——zookeeper集群搭建

前言 本节内容我们主要介绍一下如何在centos系统下搭建一套高可用的zookeeper集群&#xff0c;zookeeper是我们常用的中间键之一&#xff0c;例如使用zookeeper实现分布式锁、Hadoop集群高可用、kafka集群高可用等等。我们以以下三台服务器为例&#xff1a; zookeeper服务器 I…

R语言tidyverse教程:ggplot2绘图初步

文章目录 基本流程渲染美化坐标轴设置 R语言系列&#xff1a; 编程基础&#x1f48e;循环语句&#x1f48e;向量、矩阵和数组&#x1f48e;列表、数据帧排序函数&#x1f48e;apply系列函数tidyverse&#xff1a;readr&#x1f48e;tibble 基本流程 ggplot2有其独特的绘图语…

【算法题】LCP 74. 最强祝福力场

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 题目&#xff1a; 小扣在探索丛林的过程中&#xff0…

MPLS格式和802.1q帧格式

一.MPLS IETF开发的多协议标记交换&#xff08;MPLS)把第2层的链路状态信息&#xff08;带宽、延迟、利用率等&#xff09;集成到第3层的协议数据单元中&#xff0c;从而简化和改进了第3层分组的交换过程 。理论上&#xff0c;MPLS支持任何第2层和第3层协议。MPLS包头的位置界…

web集群第一次作业

目录 一. 简述静态网页和动态网页的区别 二. 简述 Web1.0 和 Web2.0 的区别 三. 安装tomcat8&#xff0c;配置服务启动脚本&#xff0c;部署jpress应用。 一. 简述静态网页和动态网页的区别 1. 首先&#xff0c;两者的页面资源特征不同&#xff1a; 静态网页处理文件类型有…

【Linux】进程信号(完整版) --- 信号产生 信号保存 信号捕捉 可重入函数 volatile SIGCHLD信号等

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 文章目录 一、预备知识二、信号产生1. 通过终端按键产生信号1.1 signal()1.2 core dump标志位、核心存储文件 2.通过系统调用向进程发送信号3.由软件条件产生信号3.1 alarm函数和SIGALRM信号…