Android 14 适配指南

时间:2024-10-08 10:03:03

在这里插入图片描述

Google2月按时发布了第一个开发者预览版本,正式版会在8-9月份发布。
Android 版本里程碑

按照惯例,Android更新了可以刷机的手机型号,Pixel 4仅支持4a(5G)版本:

Pixel 4a (5G)

Pixel 5 and 5a

Pixel 6 and 6 Pro

Pixel 6a

Pixel 7 and 7 Pro

开发者可以参考Android官网(/about/versions/14/get)进行刷机,普通用户刷机请慎重。

Behavior changes: all apps:

a. 核心功能-SCHEDULE_EXACT_ALARM 权限将默认关闭

为了减少耗电,以Android 13或更高版本为目标开发的应用,将会默认关闭SCHEDULE_EXACT_ALARM 权限。该权限用于精确闹钟,从Android 12开始引入,主要影响新安装的应用(会有权限弹窗,需要用户手动选择),旧系统上已经安装并授权过该权限的应用,系统升级后,将继续保持允许状态,用户可以进设置中手动关闭。
在这里插入图片描述

受影响的主要是下面三个接口,如果授权前调用,会抛出SecurityException崩溃信息

  • setExact()

  • setExactAndAllowWhileIdle()

  • setAlarmClock()

日历和闹钟类应用虽然不受该改动影响,但是最好使用USE_EXACT_ALARM( /reference/android/#USE_EXACT_ALARM )(不需要弹窗)来替换。
在这里插入图片描述

b. 核心功能-Context 注册的广播将会放入队列

当应用进入缓存状态后(比如退到后台),系统会将context注册的广播统一放到队列,等应用退出缓存状态后,系统会发送队列里的广播,可能会出现多个广播合并为一个广播的情况。

c. 安全和隐私—最低SDK版本限制

从Android 14开始,目标sdk版本小于23(Android 6.0)的应用,将不能安装。这项比较好理解,Android 6.0之后引入了运行时权限,需要弹窗让用户选择是否允许权限。大部分长期维护的应用,早已经做过这方面的适配,一些老旧应用,会受一些影响。当然,已经安装在系统中的应用,在升级完成后,还是可以继续使用的。

d. 辅助功能

从Android 14开始,系统支持字号放大200%,以方便低视力人群更好的使用,字号使用sp作单位,将不受影响,否则界面可能会比较凌乱,没有按规范开发的应用,赶紧着手改进吧。

在这里插入图片描述

Behavior changes: Apps targeting Android 14 or higher:

a. 核心功能-前台service必须设置type

可以在manifest中使用android:foregroundServiceType 设置前台service类型:

<manifest ...>
  <uses-permission android:name=".FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK" />
    <application ...>
      <service
          android:name=".MyMediaPlaybackService"
          android:foregroundServiceType="mediaPlayback"  <---here
          android:exported="false">
      </service>
    </application>
</manifest>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

也可以在代码中设置:

(0, notification, FOREGROUND_SERVICE_TYPE_LOCATION)
  • 1

Android 14后,不设置Type的话,调用startForeground()会抛出MissingForegroundServiceTypeException异常
使用相应的Type,需要申请对应的权限,没有权限的话,调用startForeground()会抛出SecurityException异常,下面是所有的service类型,以及对应的权限:

Foreground service type declared Permission that must be declared
camera FOREGROUND_SERVICE_CAMERA
connectedDevice FOREGROUND_SERVICE_CONNECTED_DEVICES
dataSync FOREGROUND_SERVICE_DATA_SYNC
health(Android 14 support) FOREGROUND_SERVICE_HEALTH
location FOREGROUND_SERVICE_LOCATION
mediaPlayback FOREGROUND_SERVICE_MEDIA_PLAYBACK
mediaProjection FOREGROUND_SERVICE_MEDIA_PROJECTION
microphone FOREGROUND_SERVICE_MICROPHONE
phoneCall FOREGROUND_SERVICE_PHONE_CALL
remoteMessaging(Android 14 support) FOREGROUND_SERVICE_REMOTE_MESSAGING
shortService(Android 14 support) No additional permission requirements
specialUse(Android 14 support) FOREGROUND_SERVICE_SPECIAL_USE
systemExempted(Android 14 support) FOREGROUND_SERVICE_SYSTEM_EXEMPTED

b. 安全性 – implicit and pending intents 限制

只有exported=true的组件,才能使用隐性intent调用:

  • Implicit intents are only delivered to exported components. Apps must either use an explicit intent to deliver to unexported components, or mark the component as exported.
  • If an app creates a mutable pending intent with an intent that doesn’t specify a component or package, the system now throws an exception.

以下面的manifest定义为例:

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name=".APP_ACTION" />
        <category android:name="" />
    </intent-filter>
</activity>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

定义了action(.APP_ACTION)并且定义android:exported=“false”,如果执行下面的代码,会抛出异常:

// Throws an exception when targeting Android 14.
(Intent(".APP_ACTION"))
  • 1
  • 2

上面代码只能在android:exported=**“true”**时正常执行
或者使用显示调用(指定package或component):

// This makes the intent explicit.
val explicitIntent = Intent(".APP_ACTION")
 {
    package = 
}
(explicitIntent)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

安全性 – 运行时注册的广播接收器,必须指定RECEIVER_EXPORTED 或 RECEIVER_NOT_EXPORTED

动态注册的Receiver,需要通过RECEIVER_EXPORTED 或 RECEIVER_NOT_EXPORTED指明是否对外部应用可见:

//类似exported true
(sharedBroadcastReceiver, intentFilter,RECEIVER_EXPORTED)
//类似exported false
(privateBroadcastReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
  • 1
  • 2
  • 3
  • 4

如果receiver只是用来接收系统广播,则不用指定

安全性 – 更安全的动态加载代码(Dynamic Code Loading)

虽然Android 不建议动态加载外部资源(DEX, JAR, or APK),但鉴于某些使用场景,目前还没有禁止使用,Andoid 14上面,所有动态加载的代码,必须设置为只读的,以降低代码注入风险:

val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
 {
    // Set the file to read-only first to prevent race conditions
    ()
    // Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

不设置的话,系统会抛出异常
对于已经存在的file,建议先删除,再重新创建(或下载)

c. non-SDK interface restrictions

Android 14 继续更新api限制,详见文件

更多原创文章,欢迎关注

头条号 程序员明哥
微信公众号 程序员明哥