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

怎么做到最优雅的版别适配?那就是尽可能进步 minitSdkVersion ,说服老板信任低版别用户无价值论,低版别用户更多是羊毛党~

针对 Android 14 或更高版别的运用

这部分主要是影响 targetSdkVersion 34 的情况 ,现在 Google Play 现已开端要求 33 了,信任未来 34 也不远了。

Android 14 快速适配要点

前台服务类型

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

前台服务类型是在 Android 10 引进的,经过 android:foregroundServiceType 能够指定 <service> 的服务类型,可供挑选的前台服务类型有:

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

例如:

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

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

更多具体可见:developer.android.com/about/versi…

安全

对 pending/implicit intent 的束缚

关于面向 Android 14 的运用,Android 经过以下办法束缚运用向内部运用组件发送隐式 intent:

  • 隐式 intent 仅传递给导出的组件,运用有必要运用明确的 intent 来交付给未导出的组件,或许将组件标记为已导出(exported) 。
  • 假如运用创立一个 mutable pending intent ,但 intent 未指定组件或包,体系现在会抛出异常。

这些更改可避免歹意运用拦截只供运用内部组件运用的隐式 intent,例如:

<activity
 android:name=".AppActivity"
 android:exported="false">
 <intent-filter>
   <actionandroid:name="com.example.action.APP_ACTION"/>
   <categoryandroid: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.
valexplicitIntent=
   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

valfilter=IntentFilter(APP_SPECIFIC_BROADCAST)
vallistenToBroadcastsFromOtherApps=false
valreceiverFlags=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 文件)在文件打开后和写入任何内容之前当即设置为只读:

valjar=File("DYNAMICALLY_LOADED_FILE.jar")
valos=FileOutputStream(jar)
os.use{
 // Set the file to read-only first to prevent race conditions
 jar.setReadOnly()
 // Then write the actual file content
}
valcl=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() 发送 PendingIntent 以及类似行为时,假如运用想要颁发其自己的后台 service 发动权限以发动 pending intent,则该运用现在有必要挑选参加一个 ActivityOptions,具体为带有 setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
  • 当一个可见运用运用 bindService() 绑定另一个在后台运转的运用的服务时,假如该可见运用想要将其自己的后台 activity 发动权限颁发绑定服务,则它现在有必要挑选参加 BIND_ALLOW_ACTIVITY_STARTS 标志。

这些更改扩展了现有的一组束缚 ,经过避免歹意运用乱用 API 从后台发动破坏性活动来维护用户。

具体可见:developer.android.com/guide/compo…

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()
  • setExactAndAllowWhileIdle()
  • setAlarmClock()

注意: 假如切当的 alarms 是运用 OnAlarmListener 对象设置的,例如在 setExact API 中,SCHEDULE_EXACT_ALARM 则不需求权限。

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

  • 在组织切当的提示之前查看权限 canScheduleExactAlarms()
  • 设置运用以 AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 监听前台播送并对其做出正确反应 ,体系会在用户颁发权限时发送该播送。

具体可见:developer.android.com/about/versi…

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 的设备上,任何低于targetSdkVersion23 的运用都将保持装置状况,假如你需求针对较旧 API 等级的运用进行测试,请运用以下 ADB 指令:

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

用户体验

颁发对相片和视频的部分拜访权限

注意: 假如你的运用现已运用了体系相片挑选器(photopicker),那么无需进行任何改动。

在 Android 14 上,当运用请求 Android 13(API 等级 33)中引进的任何 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO 媒体权限时,用户能够颁发对其相片和视频的部分拜访权限。

Android 14 快速适配要点

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

  • 挑选相片和视频: Android 14 中的新功用,用户挑选他们想要提供应运用的特定相片和视频。
  • 悉数答应:用户颁发对设备上一切相片和视频的完好库拜访权限。
  • 不答应:用户回绝一切拜访。

要在运用中呈现改逻辑,能够声明新的 READ_MEDIA_VISUAL_USER_SELECTED 权限。

具体可见:developer.android.com/about/versi…

安全的全屏 Intent 告诉

在 Android 11(API 等级 30)中,任何运用都能够经过 Notification.Builder.setFullScreenIntent 在手机锁守时发送全屏 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) 单位来定义文本巨细,那么此次更改可能不会对运用产生严重影响。