동작 변경사항: Android 14 이상을 타겟팅하는 앱

이전 버전과 마찬가지로 Android 14에는 앱에 영향을 미칠 수 있는 동작 변경사항이 포함되어 있습니다. 다음 동작 변경사항은 Android 14 (API 수준 34) 이상을 타겟팅하는 앱에만 적용됩니다. 앱이 Android 14 이상을 타겟팅한다면 이러한 동작을 올바르게 지원하도록 앱을 수정해야 합니다(적용되는 경우).

앱의 targetSdkVersion과 관계없이 Android 14에서 실행되는 모든 앱에 영향을 미치는 동작 변경사항 목록도 검토해야 합니다.

핵심 기능

포그라운드 서비스 유형은 필수 항목임

If your app targets Android 14 (API level 34) or higher, it must specify at least one foreground service type for each foreground service within your app. You should choose a foreground service type that represents your app's use case. The system expects foreground services that have a particular type to satisfy a particular use case.

If a use case in your app isn't associated with any of these types, it's strongly recommended that you migrate your logic to use WorkManager or user-initiated data transfer jobs.

BluetoothAdapter에서 BLUETOOTH_CONNECT 권한 시행

Android 14 enforces the BLUETOOTH_CONNECT permission when calling the BluetoothAdapter getProfileConnectionState() method for apps targeting Android 14 (API level 34) or higher.

This method already required the BLUETOOTH_CONNECT permission, but it was not enforced. Make sure your app declares BLUETOOTH_CONNECT in your app's AndroidManifest.xml file as shown in the following snippet and check that a user has granted the permission before calling getProfileConnectionState.

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

OpenJDK 17 업데이트

Android 14에서는 앱 및 플랫폼 개발자를 위한 라이브러리 업데이트와 Java 17 언어 지원을 비롯하여 최신 OpenJDK LTS 출시의 기능과 일치하도록 Android의 핵심 라이브러리를 새로고침하는 작업을 계속하고 있습니다.

다음과 같은 변경사항은 앱 호환성에 영향을 미칠 수 있습니다.

  • 정규 표현식 변경사항: OpenJDK의 시맨틱을 더 엄격하게 준수하도록 이제 잘못된 그룹 참조가 허용되지 않습니다. java.util.regex.Matcher 클래스에 의해 IllegalArgumentException이 발생하는 새로운 사례가 있을 수 있으므로 정규 표현식을 사용하는 영역에서 앱을 테스트해야 합니다. 테스트 중에 이 변경사항을 사용 설정하거나 사용 중지하려면 호환성 프레임워크 도구를 사용하여 DISALLOW_INVALID_GROUP_REFERENCE 플래그를 전환합니다.
  • UUID 처리: 이제 java.util.UUID.fromString() 메서드가 입력 인수를 확인할 때 더 엄격한 검사를 실행하므로 역직렬화 중에 IllegalArgumentException이 발생할 수 있습니다. 테스트 중에 이 변경사항을 사용 설정하거나 사용 중지하려면 호환성 프레임워크 도구를 사용하여 ENABLE_STRICT_VALIDATION 플래그를 전환합니다.
  • ProGuard 문제: 경우에 따라 java.lang.ClassValue 클래스를 추가하면 ProGuard를 사용하여 앱을 축소, 난독화, 최적화하려고 할 때 문제가 발생합니다. 이 문제는 Class.forName("java.lang.ClassValue")가 클래스를 반환하는지 여부에 따라 런타임 동작을 변경하는 Kotlin 라이브러리에서 발생합니다. 앱이 사용 가능한 java.lang.ClassValue 클래스가 없는 이전 버전의 런타임을 대상으로 개발된 경우 이러한 최적화로 인해 java.lang.ClassValue에서 파생된 클래스에서 computeValue 메서드가 삭제될 수 있습니다.

JobScheduler가 콜백 및 네트워크 동작을 강화합니다.

Since its introduction, JobScheduler expects your app to return from onStartJob or onStopJob within a few seconds. Prior to Android 14, if a job runs too long, the job is stopped and fails silently. If your app targets Android 14 (API level 34) or higher and exceeds the granted time on the main thread, the app triggers an ANR with the error message "No response to onStartJob" or "No response to onStopJob".

This ANR may be a result of 2 scenarios: 1. There is work blocking the main thread, preventing the callbacks onStartJob or onStopJob from executing and completing within the expected time limit. 2. The developer is running blocking work within the JobScheduler callback onStartJob or onStopJob, preventing the callback from completing within the expected time limit.

To address #1, you will need to further debug what is blocking the main thread when the ANR occurs, you can do this using ApplicationExitInfo#getTraceInputStream() to get the tombstone trace when the ANR occurs. If you're able to manually reproduce the ANR, you can record a system trace and inspect the trace using either Android Studio or Perfetto to better understand what is running on the main thread when the ANR occurs. Note that this can happen when using JobScheduler API directly or using the androidx library WorkManager.

To address #2, consider migrating to WorkManager, which provides support for wrapping any processing in onStartJob or onStopJob in an asynchronous thread.

JobScheduler also introduces a requirement to declare the ACCESS_NETWORK_STATE permission if using setRequiredNetworkType or setRequiredNetwork constraint. If your app does not declare the ACCESS_NETWORK_STATE permission when scheduling the job and is targeting Android 14 or higher, it will result in a SecurityException.

Tiles launch API

14 이상을 타겟팅하는 앱의 경우 TileService#startActivityAndCollapse(Intent)가 지원 중단되었으며 다음 오류가 발생합니다. 예외가 발생할 수 있습니다. 앱이 카드에서 활동을 실행하는 경우 다음을 사용합니다. 대신 TileService#startActivityAndCollapse(PendingIntent)를 사용하세요.

개인정보 보호

사진 및 동영상에 대한 일부 액세스

Android 14 引入了所选照片访问权限,可让用户授权应用访问其媒体库中的特定图片和视频,而不是授予对指定类型的所有媒体的访问权限。

仅当您的应用以 Android 14(API 级别 34)或更高版本为目标平台时,才会启用此变更。如果您还没有使用照片选择器,建议您在应用中实现该选择器,以便在选择图片和视频时提供一致的体验,同时还可以加强用户隐私保护,而无需请求任何存储权限。

如果您使用存储权限维护自己的图库选择器,并且需要完全控制您的实现,请调整您的实现,以使用新的 READ_MEDIA_VISUAL_USER_SELECTED 权限。如果您的应用不使用新权限,系统会在兼容模式下运行应用。

사용자 환경

전체 화면 인텐트 보안 알림

在 Android 11(API 级别 30)中,任何应用都可以在手机处于锁定状态时使用 Notification.Builder.setFullScreenIntent 发送全屏 intent。您可以通过在 AndroidManifest 中声明 USE_FULL_SCREEN_INTENT 权限,在应用安装时自动授予此权限。

全屏 intent 通知适用于需要用户立即注意的极高优先级通知,例如用户来电或用户配置的闹钟设置。对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,获准使用此权限的应用仅限于提供通话和闹钟的应用。对于不适合此资料的任何应用,Google Play 商店会撤消其默认的 USE_FULL_SCREEN_INTENT 权限。这些政策变更的截止日期为 2024 年 5 月 31 日

在用户更新到 Android 14 之前,在手机上安装的应用仍拥有此权限。用户可以开启和关闭此权限。

您可以使用新 API NotificationManager.canUseFullScreenIntent 检查应用是否具有该权限;如果没有,应用可以使用新 intent ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT 启动设置页面,在该页面中,用户可以授予权限。

보안

암시적 인텐트와 대기 중인 인텐트 제한사항

Android 14(API 수준 34) 이상을 타겟팅하는 앱의 경우 Android는 다음과 같은 방법으로 앱이 암시적 인텐트를 내부 앱 구성요소로 전송하지 못하도록 제한합니다.

  • 암시적 인텐트는 내보낸 구성요소로만 전송됩니다. 앱은 내보내지 않은 구성요소로 전송하기 위해 명시적 인텐트를 사용하거나 구성요소를 내보낸 것으로 표시해야 합니다.
  • 앱이 구성요소나 패키지를 지정하지 않는 인텐트로 변경 가능한 대기 중인 인텐트를 만들면 시스템에서 예외가 발생합니다.

이러한 변경사항으로 인해 악성 앱이 앱의 내부 구성요소에서 사용할 암시적 인텐트를 가로채지 못하게 됩니다.

예를 들어 다음은 앱의 매니페스트 파일에서 선언할 수 있는 인텐트 필터입니다.

<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>

앱에서 암시적 인텐트를 사용하여 이 활동을 시작하려고 하면 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"));

내보내지 않은 활동을 실행하려면 앱에서 명시적 인텐트를 대신 사용해야 합니다.

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);

런타임 등록 broadcast receiver는 내보내기 동작을 지정해야 함

以 Android 14(API 级别 34)或更高版本为目标平台并使用上下文注册的接收器的应用和服务必须指定一个标志,以指明接收器是否应导出到设备上的所有其他应用:分别为 RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED。此要求有助于利用 Android 13 中引入的这些接收器的功能,保护应用免受安全漏洞的影响。

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

如果您的应用仅通过 Context#registerReceiver 方法(例如 Context#registerReceiver())为系统广播注册接收器,那么在注册接收器时不应指定标志。

더 안전한 동적 코드 로드

앱이 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);

이미 있는 동적으로 로드된 파일 처리

동적으로 로드된 기존 파일에 예외가 발생하지 않도록 하려면 앱에서 파일을 다시 동적으로 로드하기 전에 파일을 삭제하고 다시 만드는 것이 좋습니다. 파일을 다시 만들 때 앞의 안내에 따라 쓰기 시간에 파일을 읽기 전용으로 표시하세요. 또는 기존 파일의 라벨을 읽기 전용으로 다시 지정할 수 있지만 이 경우에는 앱을 악의적인 행위로부터 보호할 수 있도록 먼저 파일의 무결성을 확인하는 것이 좋습니다(예: 신뢰할 수 있는 값을 기준으로 파일의 서명 확인).

백그라운드에서 활동 시작에 관한 추가 제한사항

Android 14(API 수준 34) 이상을 타겟팅하는 앱의 경우 시스템은 앱이 백그라운드에서 활동을 시작하도록 허용되는 시점을 추가로 제한합니다.

  • 앱이 PendingIntent#send() 또는 유사한 메서드를 사용하여 PendingIntent를 전송할 때 대기 중인 인텐트를 시작하기 위해 자체 백그라운드 활동 실행 권한을 부여할지 이제 앱이 선택해야 합니다. 선택하려면 앱에서 setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)가 포함된 ActivityOptions 번들을 전달해야 합니다.
  • 표시되는 앱이 bindService() 메서드를 사용하여 백그라운드에 있는 다른 앱의 서비스를 바인딩하는 경우 이제 표시되는 앱은 바운드된 서비스에 자체 백그라운드 활동 실행 권한을 부여할지 선택해야 합니다. 선택하려면 앱에 다음 항목이 포함되어야 합니다. BIND_ALLOW_ACTIVITY_STARTS 플래그 bindService() 메서드를 사용하여 지도 가장자리에 패딩을 추가할 수 있습니다.

이러한 변경사항으로 인해 기존 제한사항이 확대되어 악성 앱이 불편을 초래하는 API를 악용하지 못하도록 방지하여 사용자를 보호합니다. 할 수 있습니다.

압축 파일 경로 순회

Android 14 (API 수준 34) 이상을 타겟팅하는 앱의 경우 Android는 다음과 같은 방법으로 ZIP 경로 순회 취약점을 방지합니다. ZIP 파일 항목 이름에 '..'가 포함되거나 '/'로 시작하면 ZipFile(String)ZipInputStream.getNextEntry()에서 ZipException이 발생합니다.

앱은 dalvik.system.ZipPathValidator.clearCallback()를 호출하여 이 유효성 검사를 선택 해제할 수 있습니다.

Android 14 (API 수준 34) 이상을 타겟팅하는 앱의 경우 다음 시나리오 중 하나에서 MediaProjection#createVirtualDisplay에 의해 SecurityException이 발생합니다.

앱은 각 캡처 세션 전에 사용자에게 동의를 요청해야 합니다. 단일 캡처 세션은 MediaProjection#createVirtualDisplay의 단일 호출이며 각 MediaProjection 인스턴스는 한 번만 사용되어야 합니다.

구성 변경 처리

앱에서 MediaProjection#createVirtualDisplay를 호출하여 구성 변경 (예: 화면 방향 또는 화면 크기 변경)을 처리해야 한다면 다음 단계에 따라 기존 MediaProjection 인스턴스의 VirtualDisplay를 업데이트할 수 있습니다.

  1. 새 너비와 높이로 VirtualDisplay#resize를 호출합니다.
  2. VirtualDisplay#setSurface에 새 너비와 높이가 포함된 새 Surface를 제공합니다.

콜백 등록

사용자가 캡처 세션을 계속하는 데 동의하지 않는 경우를 처리하기 위해 앱에서 콜백을 등록해야 합니다. 이렇게 하려면 Callback#onStop를 구현하고 앱에서 관련 리소스 (예: VirtualDisplaySurface)를 해제하도록 합니다.

앱에서 이 콜백을 등록하지 않은 경우 앱에서 호출할 때 MediaProjection#createVirtualDisplay에서 IllegalStateException이 발생합니다.

업데이트된 비 SDK 제한사항

Android 14 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。

如果您的应用并非以 Android 14 为目标平台,其中一些变更可能不会立即对您产生影响。然而,虽然您目前仍可以使用一些非 SDK 接口(具体取决于应用的目标 API 级别),但只要您使用任何非 SDK 方法或字段,终归存在导致应用出问题的显著风险。

如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试您的应用来进行确认。如果您的应用依赖于非 SDK 接口,您应该开始计划迁移到 SDK 替代方案。然而,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,应请求新的公共 API

이 Android 버전의 변경사항을 자세히 알아보려면 Android 14의 비 SDK 인터페이스 제한사항 업데이트를 참고하세요. 비 SDK 인터페이스에 관해 전반적으로 알아보려면 비 SDK 인터페이스 제한사항을 참고하세요.