Como nas versões anteriores, o Android 14 inclui mudanças de comportamento que podem afetar seu app. As mudanças a seguir se aplicam exclusivamente a apps destinados ao Android 14 (nível 34 da API) ou mais recente. Caso seu app seja direcionado ao Android 14 ou a versões mais recentes, faça modificações para oferecer suporte a esses comportamentos de forma adequada, quando aplicável.
Consulte também a lista de mudanças de comportamento que afetam todos os apps
executados no Android 14, independente da
targetSdkVersion do app.
Principal recurso
Os tipos de serviço em primeiro plano são obrigatórios
Se o app for destinado ao Android 14 (nível 34 da API) ou mais recente, ele precisará especificar pelo menos um tipo de serviço em primeiro plano para cada serviço em primeiro plano. Escolha um tipo que represente o caso de uso do app. O sistema espera que serviços em primeiro plano com um tipo específico satisfaça um caso de uso específico.
Se um caso de uso no app não estiver associado a nenhum desses tipos, é recomendável migrar a lógica para usar o WorkManager ou jobs de transferência de dados iniciados pelo usuário.
Aplicação da permissão BLUETOOTH_CONNECT em BluetoothAdapter
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,在调用 BluetoothAdapter getProfileConnectionState() 方法时,Android 14 会强制执行 BLUETOOTH_CONNECT 权限。
此方法已需要 BLUETOOTH_CONNECT 权限,但未强制执行。确保您的应用在应用的 AndroidManifest.xml 文件中声明 BLUETOOTH_CONNECT,如以下代码段所示,并在调用 getProfileConnectionState 之前检查用户是否已授予相应权限。
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Atualizações do OpenJDK 17
O Android 14 continua o trabalho de atualizar as principais bibliotecas do Android para se alinhar aos recursos das versões mais recentes do LTS do OpenJDK, incluindo atualizações de bibliotecas e suporte à linguagem Java 17 para desenvolvedores de apps e plataformas.
Algumas dessas mudanças podem afetar a compatibilidade do app:
- Mudanças em expressões regulares: referências inválidas a grupos agora não são
permitidas para seguir mais de perto a semântica do OpenJDK. Será possível conferir
novos casos em que uma
IllegalArgumentExceptioné gerada pela classejava.util.regex.Matcher. Portanto, teste o app para áreas que usam expressões regulares. Para ativar ou desativar essa mudança durante os testes, configure a flagDISALLOW_INVALID_GROUP_REFERENCEusando as ferramentas do framework de compatibilidade. - Processamento de UUID: o método
java.util.UUID.fromString()agora faz verificações mais rigorosas ao validar o argumento de entrada. Por isso, talvez umaIllegalArgumentExceptionapareça durante desserialização. Para ativar ou desativar essa mudança durante os testes, configure a flagENABLE_STRICT_VALIDATIONusando as ferramentas do framework de compatibilidade. - Problemas com o ProGuard: em alguns casos, a adição da classe
java.lang.ClassValuecausará um problema se você tentar reduzir, ofuscar e otimizar o app usando o ProGuard. O problema se origina em uma biblioteca Kotlin que muda o comportamento no momento de execução, dependendo seClass.forName("java.lang.ClassValue")retorna uma classe ou não. Se o app tiver sido desenvolvido em uma versão mais antiga do ambiente de execução sem a classejava.lang.ClassValuedisponível, essas otimizações poderão remover o métodocomputeValuedas classes derivadas dejava.lang.ClassValue.
O JobScheduler reforça o comportamento de callback e de rede
自从引入后,JobScheduler 期望您的应用从
onStartJob 或 onStopJob。在 Android 14 之前,如果作业运行时间过长,系统会停止作业并静默失败。如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台,
超过在主线程上授予的时间,应用会触发 ANR
显示“没有响应 onStartJob”错误消息或
“onStopJob没有回复”。
此 ANR 可能是由以下 2 种情况造成的:
1.有工作阻塞主线程,阻止回调 onStartJob
或者onStopJob在预期时间内执行并完成。
2. 开发者在 JobScheduler 中运行阻塞工作
回调 onStartJob 或 onStopJob,阻止从
在预期的时限内完成
要解决第 1 个问题,您需要进一步调试阻塞主线程的因素
您可以使用以下代码
ApplicationExitInfo#getTraceInputStream(),用于获取 Tombstone
ANR 发生时的跟踪信息如果您能够手动重现 ANR 问题
您可以录制系统轨迹,并使用
Android Studio 或 Perfetto,以便更好地了解应用上运行的
在发生 ANR 时调用主线程
请注意,直接使用 JobScheduler API 或使用 androidx 库 WorkManager 时可能会发生这种情况。
如需解决问题 2,请考虑迁移到 WorkManager,它支持将 onStartJob 或 onStopJob 中的任何处理封装在异步线程中。
JobScheduler 还引入了一项要求,即如果使用 setRequiredNetworkType 或 setRequiredNetwork 约束条件,则必须声明 ACCESS_NETWORK_STATE 权限。如果您的应用未声明
ACCESS_NETWORK_STATE 权限
Android 14 或更高版本,则会导致 SecurityException。
API de lançamento de blocos
Para apps destinados ao Android 14 ou mais recente,
O TileService#startActivityAndCollapse(Intent) foi descontinuado e agora gera
uma exceção quando chamado. Se o app iniciar atividades de blocos, use
TileService#startActivityAndCollapse(PendingIntent).
Privacidade
Acesso parcial a fotos e vídeos
Android 14 引入了“已选照片访问权限”,让用户可以向应用授予对其媒体库中特定图片和视频的访问权限,而不是授予对给定类型的所有媒体的访问权限。
只有当您的应用以 Android 14(API 级别 34)或更高版本为目标平台时,此更改才会启用。如果您尚未使用照片选择器,我们建议您在应用中实现照片选择器,以提供一致的图片和视频选择体验,同时增强用户隐私保护,而无需请求任何存储权限。
如果您使用存储权限维护自己的图库选择器,并且需要对实现保持完全控制,请调整实现以使用新的 READ_MEDIA_VISUAL_USER_SELECTED 权限。如果您的应用不使用新权限,系统会以兼容模式运行您的应用。
Experiência do usuário
Notificações seguras de intent de tela cheia
Com o Android 11 (nível 30 da API), era possível que qualquer app usasse
Notification.Builder.setFullScreenIntent para enviar intents de tela cheia
enquanto o smartphone estava bloqueado. Era possível conceder essa permissão automaticamente na instalação do app
declarando a permissão USE_FULL_SCREEN_INTENT no
AndroidManifest.
As notificações de intent de tela cheia são projetadas para notificações de altíssima prioridade
que exigem a atenção imediata do usuário, como uma ligação recebida
ou configurações de despertador definidas pelo usuário. Em apps destinados ao
Android 14 (nível 34 da API) ou mais recente, essa permissão é limitada
a apps que fornecem apenas chamadas e alarmes. A Google
Play Store revoga as permissões USE_FULL_SCREEN_INTENT padrão para todos os apps
que não se encaixam nesse perfil. O prazo para essas mudanças na política é 31 de maio
de 2024.
Essa permissão continua ativada para apps instalados no smartphone antes da atualização para o Android 14. Os usuários podem ativar ou desativar essa permissão.
Você pode usar a nova API
NotificationManager.canUseFullScreenIntent para conferir se o app
tem a permissão. Caso ele não tenha, é possível usar a nova intent
ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT para abrir a página de configurações
em que os usuários podem conceder a permissão.
Segurança
Restrições a intents implícitas e pendentes
对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式限制应用向内部应用组件发送隐式 intent:
- 隐式 intent 只能传送到导出的组件。应用必须使用显式 intent 传送到未导出的组件,或将该组件标记为已导出。
- 如果应用通过未指定组件或软件包的 intent 创建可变待处理 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,则系统会抛出 ActivityNotFoundException 异常:
Kotlin
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(Intent("com.example.action.APP_ACTION"))
Java
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(new Intent("com.example.action.APP_ACTION"));
如需启动非导出的 activity,应用应改用显式 intent:
Kotlin
// This makes the intent explicit. val explicitIntent = Intent("com.example.action.APP_ACTION") explicitIntent.apply { package = context.packageName } context.startActivity(explicitIntent)
Java
// This makes the intent explicit. Intent explicitIntent = new Intent("com.example.action.APP_ACTION") explicitIntent.setPackage(context.getPackageName()); context.startActivity(explicitIntent);
Os broadcast receivers registrados no ambiente de execução precisam especificar o comportamento de exportação
Os apps e serviços direcionados ao Android 14 (nível 34 da API) ou mais recente e que usam
receptores registrados pelo contexto precisam especificar uma flag
para indicar se o receptor precisa ou não ser exportado para todos os outros apps no
dispositivo: RECEIVER_EXPORTED ou RECEIVER_NOT_EXPORTED, respectivamente.
Esse requisito ajuda a proteger os apps contra vulnerabilidades de segurança usando
os recursos desses receptores lançados no Android 13.
Exceção para receptores que recebem apenas transmissões do sistema
Se o app estiver registrando um receptor apenas para
transmissões do sistema usando métodos Context#registerReceiver, como Context#registerReceiver(), ele
não precisará especificar uma flag ao registrar o receptor.
Carregamento mais seguro de código dinâmico
如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台并使用动态代码 正在加载 (DCL),所有动态加载的文件都必须标记为只读。 否则,系统会抛出异常。我们建议应用尽可能避免动态加载代码,因为这样做会大大增加应用因代码注入或代码篡改而遭到入侵的风险。
如果必须动态加载代码,请使用以下方法,在动态文件(例如 DEX、JAR 或 APK 文件)打开并写入任何内容之前立即将其设为只读:
Kotlin
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)
Java
File jar = new File("DYNAMICALLY_LOADED_FILE.jar"); try (FileOutputStream os = new FileOutputStream(jar)) { // Set the file to read-only first to prevent race conditions jar.setReadOnly(); // Then write the actual file content } catch (IOException e) { ... } PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);
处理已存在的动态加载文件
为防止系统对现有动态加载的文件抛出异常,我们建议您先删除并重新创建文件,然后再尝试在应用中重新动态加载这些文件。重新创建文件时,请按照上述指南在写入时将文件标记为只读。或者,您可以将现有文件重新标记为只读,但在这种情况下,我们强烈建议您先验证文件的完整性(例如,对照可信值检查文件的签名)以保护应用免遭恶意操作的影响。
Mais restrições para o início de atividades em segundo plano
Em apps destinados ao Android 14 (nível 34 da API) ou mais recente, o sistema restringe ainda mais a permissão para que os apps iniciem atividades em segundo plano:
- Quando um app envia uma
PendingIntentusandoPendingIntent#send()ou métodos semelhantes, ele precisa ativar um recurso para conceder à própria atividade em segundo plano os privilégios de inicialização para iniciar a intent pendente. Para ativar o recurso, o app precisa transmitir um pacoteActivityOptionscomsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED). - Quando um app visível vincula um serviço de outro app que está em segundo plano
usando o método
bindService(), ele precisa ativar um recurso para conceder às próprias atividades em segundo plano os privilégios de inicialização do serviço vinculado. Para isso, o app precisa incluir a flagBIND_ALLOW_ACTIVITY_STARTSao chamar o métodobindService().
Essas mudanças ampliam o conjunto existente de restrições para proteger os usuários. Elas impedem que apps maliciosos usem APIs para iniciar atividades que causam interrupções em segundo plano.
Travessia de caminhos de arquivo ZIP
Em apps destinados ao Android 14 (nível 34 da API) ou mais recente, o Android evita a vulnerabilidade
da travessia de caminhos de arquivo ZIP da seguinte forma:
ZipFile(String) e
ZipInputStream.getNextEntry() geram uma
ZipException quando os nomes dos arquivos ZIP têm ".." ou começam
com "/".
Os apps podem desativar essa validação chamando
dalvik.system.ZipPathValidator.clearCallback().
É necessário ter consentimento do usuário para cada sessão de captura do MediaProjection
Para apps destinados ao Android 14 (nível 34 da API) ou mais recente, uma SecurityException é
gerada por MediaProjection#createVirtualDisplay em um dos seguintes
cenários:
- O app armazena em cache o
Intentretornado peloMediaProjectionManager#createScreenCaptureIntente o transmite várias vezes paraMediaProjectionManager#getMediaProjection. - O app invoca
MediaProjection#createVirtualDisplayvárias vezes na mesma instância deMediaProjection.
O app precisa pedir o consentimento do usuário antes de cada sessão de captura. Uma única
sessão de captura é uma única invocação em
MediaProjection#createVirtualDisplay, e cada instância de MediaProjection precisa
ser usada apenas uma vez.
Gerenciar mudanças de configuração
Se o app precisar invocar MediaProjection#createVirtualDisplay para processar
mudanças de configuração, como a orientação ou o tamanho da tela,
siga estas etapas para atualizar o VirtualDisplay da instância
MediaProjection atual:
- Invoque
VirtualDisplay#resizecom a nova largura e altura. - Forneça um novo
Surfacecom a nova largura e altura paraVirtualDisplay#setSurface.
Registrar um callback
Seu app precisa registrar um callback para processar casos em que o usuário não concede
consentimento para continuar uma sessão de captura. Para fazer isso, implemente
Callback#onStop e faça o app liberar todos os recursos relacionados, como
VirtualDisplay e Surface.
Se o app não registrar esse callback,
MediaProjection#createVirtualDisplay vai gerar uma IllegalStateException
quando o app o invocar.
Atualização das restrições não SDK
Android 14 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。
如果您的应用并非以 Android 14 为目标平台,其中一些变更可能不会立即对您产生影响。然而,虽然您目前仍可以使用一些非 SDK 接口(具体取决于应用的目标 API 级别),但只要您使用任何非 SDK 方法或字段,终归存在导致应用出问题的显著风险。
如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试您的应用来进行确认。如果您的应用依赖于非 SDK 接口,您应该开始计划迁移到 SDK 替代方案。然而,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,应请求新的公共 API。
Para saber mais sobre as mudanças dessa versão do Android, consulte Atualizações para restrições de interfaces não SDK no Android 14. Para saber mais sobre interfaces não SDK em geral, consulte Restrições para interfaces não SDK.