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

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

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

핵심 기능

Android 15는 Android 시스템의 다양한 핵심 기능을 수정하거나 확장합니다.

포그라운드 서비스 변경사항

我们将对 Android 15 中的前台服务做出以下更改。

新增媒体处理前台服务类型

Android 15에서는 새로운 포그라운드 서비스 유형인 mediaProcessing를 도입합니다. 이 서비스 유형은 미디어 파일 트랜스코딩과 같은 작업에 적합합니다. 예를 들어 미디어 앱은 오디오 파일을 다운로드하여 재생하기 전에 다른 형식으로 변환해야 할 수 있습니다. mediaProcessing 포그라운드 서비스를 사용하면 앱이 백그라운드에 있는 동안에도 전환이 계속되도록 할 수 있습니다.

mediaProcessing 서비스 유형에 관한 자세한 내용은 Android 15의 포그라운드 서비스 유형 변경사항을 참고하세요.

对启动前台服务的 BOOT_COMPLETED 广播接收器的限制

针对启动前台服务的 BOOT_COMPLETED 广播接收器存在新的限制。BOOT_COMPLETED 接收器不能启动以下类型的前台服务:

如果 BOOT_COMPLETED 接收器尝试启动任何此类前台服务,系统会抛出 ForegroundServiceStartNotAllowedException

앱이 방해 금지 모드의 전체 상태를 수정할 수 있는 경우에 대한 변경사항

Android 15를 타겟팅하는 앱은 사용자 설정을 수정하거나 DND 모드를 사용 중지하여 기기에서 방해 금지 모드(DND)의 전체 상태 또는 정책을 더 이상 변경할 수 없습니다. 대신 앱은 AutomaticZenRule를 제공해야 합니다. 시스템은 이 시스템에서 기존의 'most-restrictive-policy-wins' 체계가 적용된 전역 정책에 이를 결합합니다. 이전에 전역 상태 (setInterruptionFilter, setNotificationPolicy)에 영향을 미쳤던 기존 API를 호출하면 암시적 AutomaticZenRule이 생성되거나 업데이트됩니다. 이 AutomaticZenRule는 이러한 API 호출의 호출 주기에 따라 사용 설정되거나 사용 중지됩니다.

이 변경사항은 앱이 setInterruptionFilter(INTERRUPTION_FILTER_ALL)를 호출하고 소유자가 이전에 활성화한 AutomaticZenRule를 비활성화하기 위한 호출이 예상되는 경우에만 관찰 가능한 동작에만 영향을 미칩니다.

OpenJDK 17 변경사항

Android 15 会继续更新 Android 的核心库,以与最新 OpenJDK LTS 版本中的功能保持一致。

对于以 Android 15 为目标平台的应用,以下变更可能会影响应用兼容性:

  • 字符串格式设置 API 的变化:在使用以下 String.format()Formatter.format() API 时,现在对参数索引、标志、宽度和精度的验证更为严格:

    例如,使用参数索引 0 时(格式字符串中的 %0)会抛出以下异常:

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    在这种情况下,可以通过在格式字符串中使用 %1 的参数索引 1 来解决此问题。

  • 语言代码处理方面的变更:使用 Locale API 时,希伯来语、意第绪语和印度尼西亚语的语言代码不再转换为过时的形式(希伯来语:iw、意第绪语:ji 和印度尼西亚语:in)。在为其中一个语言区域指定语言代码时,请改用 ISO 639-1 中的代码:yi、Yid1(希伯来语):yiheid

  • 随机 int 序列变更:在 https://bugs.openjdk.org/browse/JDK-8301574 中做出更改后,以下 Random.ints() 方法现在返回的数字序列现在与 Random.nextInt() 方法不同:

    通常,此变更不会导致应用破坏行为,但您的代码不应期望从 Random.ints() 方法生成的序列与 Random.nextInt() 匹配。

보안

Android 15에는 앱과 사용자를 악성 앱으로부터 보호하기 위해 시스템 보안을 촉진하는 변경사항이 포함되어 있습니다.

보안 백그라운드 활동 시작

Android 15 通过添加变更来防止恶意后台应用将其他应用带到前台、提升其权限和滥用用户互动,从而保护用户免受恶意应用的侵害,并使用户能够更好地控制其设备。从 Android 10(API 级别 29)开始,后台 activity 启动已受到限制。

阻止与堆栈中顶部 UID 不匹配的应用启动 activity

恶意应用可以在同一任务内启动另一个应用的 activity,然后叠加在上面,制造出作为该应用的错觉。这种“任务劫持”攻击绕过了当前的后台启动限制,因为它都发生在同一可见任务内。为了降低这种风险,Android 15 添加了一个标志,用于阻止与堆栈上的顶级 UID 不匹配的应用启动 activity。如需选择启用应用的所有 activity,请更新应用的 AndroidManifest.xml 文件中的 allowCrossUidActivitySwitchFromBelow 属性:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

其他变更

除了 UID 匹配的限制之外,还包含以下其他更改:

  • PendingIntent 创建者更改为默认阻止后台 activity 启动。这有助于防止应用意外创建可能会被恶意操作者滥用的 PendingIntent
  • 请勿将应用置于前台,除非 PendingIntent 发送者允许该应用。此变更旨在防止恶意应用滥用在后台启动 activity 的功能。默认情况下,不允许应用将任务堆栈置于前台,除非创建者允许后台 activity 启动特权或发送者具有后台 activity 启动特权。
  • 控制任务堆栈的顶层 activity 完成其任务的方式。如果顶层 activity 完成某项任务,Android 会返回到上次处于活动状态的任务。此外,如果非顶层 activity 完成其任务,Android 将返回主屏幕;它不会阻止此非顶部 activity 的完成。
  • 防止将其他应用中的任意 activity 启动到您自己的任务中。这项变更会通过创建看似来自其他应用的活动,防止恶意应用向用户进行钓鱼式攻击。
  • 阻止系统考虑将不可见窗口用于后台 activity 启动。这有助于防止恶意应用滥用后台 activity 启动来向用户显示不受欢迎或恶意内容。

더 안전한 인텐트

Android 15 introduces new security measures to make intents safer and more robust. These changes are aimed at preventing potential vulnerabilities and misuse of intents that can be exploited by malicious apps. There are two main improvements to the security of intents in Android 15:

  • Match target intent-filters: Intents that target specific components must accurately match the target's intent-filter specifications. If you send an intent to launch another app's activity, the target intent component needs to align with the receiving activity's declared intent-filters.
  • Intents must have actions: Intents without an action will no longer match any intent-filters. This means that intents used to start activities or services must have a clearly defined action.

Kotlin


fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        .detectUnsafeIntentLaunch()
        .build()
    )
}

Java


public void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
            .detectUnsafeIntentLaunch()
            .build());
}

사용자 환경 및 시스템 UI

Android 15에는 더 일관되고 직관적인 사용자 환경을 만들기 위한 몇 가지 변경사항이 포함되어 있습니다.

창 인셋 변경사항

Android 15에서는 창 인셋과 관련된 두 가지 변경사항이 있습니다. 베타 1에서는 더 넓은 화면 범위가 적용됩니다. 시스템 표시줄의 기본 구성을 비롯한 향후 구성 변경사항도 있습니다.

더 넓은 화면 적용

默认情况下,如果应用以 Android 15 为目标平台,则在搭载 Android 15 的设备上会无边框。

应用以 Android 14 为目标平台且在 Android 15 设备上并非全屏显示的应用。


一个以 Android 15 为目标平台且在 Android 15 设备上实现无边框的应用。此应用主要使用可自动应用边衬区的 Material 3 Compose 组件。此屏幕不会受到 Android 15 无边框强制执行的影响。

这是一项重大变更,可能会对应用的界面产生负面影响。变更如下:

  • 手势手柄导航栏
    • 默认为透明。
    • 由于底部偏移已停用,因此内容绘制在系统导航栏后面,除非应用边衬区。
    • setNavigationBarColorR.attr#navigationBarColor 已废弃,不会影响手势导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 仍然对手势导航没有影响。
  • “三按钮”导航
    • 不透明度默认设置为 80%,颜色可能与窗口背景匹配。
    • 已停用底部偏移,因此内容绘制在系统导航栏后面,除非应用边衬区。
    • 默认情况下,setNavigationBarColorR.attr#navigationBarColor 设置为与窗口背景匹配。窗口背景必须是彩色可绘制对象,才能应用此默认设置。此 API 已废弃,但会继续影响三按钮导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 默认情况下为 true,这会在“三按钮”导航中添加 80% 的不透明背景。
  • 状态栏
    • 默认为透明。
    • 顶部偏移量已停用,因此,除非应用边衬区,否则内容将绘制在状态栏后面。
    • setStatusBarColorR.attr#statusBarColor 已废弃,对 Android 15 没有任何影响。
    • setStatusBarContrastEnforcedR.attr#statusBarContrastEnforced 已废弃,但在 Android 15 上仍产生影响。
  • 刘海屏
    • 非浮动窗口的 layoutInDisplayCutoutMode 必须为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS。在 Android 15 Beta 1 中,如果使用 SHORT_EDGESNEVERDEFAULT(例如 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT),应用将会崩溃并出现 IllegalArgumentException。在 Android 15 Beta 版 2 中,SHORT_EDGESNEVERDEFAULT 将被解释为 ALWAYS,这样用户就不会看到由刘海屏导致的黑色条形,而无边框。

以下示例展示了以 Android 15 为目标平台之前和之后以及应用边衬区前后的应用。

应用以 Android 14 为目标平台且在 Android 15 设备上并非全屏显示的应用。
一个以 Android 15 为目标平台且在 Android 15 设备上实现无边框的应用。不过,由于 Android 15 的无边框强制措施,许多元素现在被状态栏、“三按钮”导航栏或刘海屏遮挡。被遮盖的界面包括 Material 2 TopAppBar、FAB 和列表项。
如果应用以 Android 15 为目标平台,则可以在 Android 15 设备上全屏显示,并会应用边衬区来避免界面被遮挡。

如果您的应用:

  • 无边框并应用了边衬区,那么除了以下几种场景外,您基本上不受影响。不过,即使您认为自己不受影响,我们也建议您测试自己的应用。
    • 您有一个非浮动窗口,例如使用 SHORT_EDGES, NEVERDEFAULT(而非 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS)的 Activity。如果您的应用在启动时崩溃,这可能是由于启动画面所致。您可以将 core splashscreen 依赖项升级到 1.2.0-alpha01 或更高版本,设置 window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always,或使用 Android 15 Beta 版 2(而不是 Beta 版 1)进行测试。
    • 在流量较低的屏幕上,可能会出现界面被遮挡的屏幕。验证这些访问较少的屏幕没有被遮挡的界面。流量较低的屏幕包括:
      • 初始配置或登录屏幕
      • “设置”页面
  • 非无边际,那么您很有可能受到影响。除了无边框应用出现的情况之外,您还需要考虑以下因素:
    • 如果您的应用使用 Material 3 组件(Compose 中的 androidx.compose.material3,例如 TopAppBar, BottomAppBarNavigationBar),这些组件可能不受影响,因为它们会自动处理边衬区。
    • 如果您的应用使用的是 Material 2 组件(Compose 中的 androidx.compose.material),则这些组件不会自动处理边衬区。不过,您可以访问边衬区并手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,请使用 windowInsets 参数,为 BottomAppBarTopAppBarBottomNavigationNavigationRail 手动应用边衬区。同样,对 Scaffold 使用 contentWindowInsets 参数。
    • 如果您的应用使用 View 和 Material 组件 (com.google.android.material),则大多数基于 View 的 Material 组件(例如 BottomNavigationViewBottomAppBarNavigationRailViewNavigationView)会处理边衬区,无需执行额外的操作。不过,如果使用 AppBarLayout,则需要添加 android:fitsSystemWindows="true"
    • 对于自定义可组合项,请手动应用边衬区作为内边距。如果您的内容位于 Scaffold 内,您可以使用 Scaffold 的内边距值使用边衬区。否则,请使用 WindowInsets 之一应用内边距。
    • 如果您的应用使用的是 View 和 BottomSheet、SideSheet 或自定义容器,请使用 ViewCompat.setOnApplyWindowInsetsListener 应用内边距。对于 RecyclerView,请使用此监听器应用内边距,并添加 clipToPadding="false"
  • 必须为三按钮导航或状态栏提供自定义背景保护,那么您的应用应使用 WindowInsets.Type#tappableElement() 获取三按钮导航栏高度或 WindowInsets.Type#statusBars,将可组合项或视图放置在系统栏后面。

如需了解应用边衬区的其他注意事项,请参阅边缘视图Edge to Edge Compose 指南。

已废弃和已停用的 API 列表如下:

  • R.attr#statusBarColor
  • R.attr#navigationBarColor
  • R.attr#navigationBarDividerColor
  • 窗口#setDecorFitsSystemWindows
  • 窗口#setStatusBarColor
  • 窗口#setStatusBarContrastEnforced
  • 窗口#setNavigationBarColor
  • Window#setNavigationBarDividerColor
  • 窗口#getStatusBarColor
  • Window#getStatusBarContrastEnforced
  • 窗口#getNavigationBarColor
  • Window#getNavigationBarDividerColor

안정적인 구성

이 변경사항은 베타 1에서 테스트할 수 없지만 곧 제공될 예정입니다.

앱이 Android 15 이상을 타겟팅하면 Configuration에서 더 이상 시스템 표시줄을 제외하지 않습니다. 레이아웃 계산을 위해 Configuration 클래스에서 화면 크기를 사용하는 경우 필요에 따라 적절한 ViewGroup, WindowInsets 또는 WindowMetricsCalculator와 같은 더 나은 대안으로 대체해야 합니다.

Configuration는 API 1부터 사용할 수 있었습니다. 일반적으로 Activity.onConfigurationChanged에서 가져옵니다. 창 밀도, 방향, 크기와 같은 정보를 제공합니다. Configuration에서 반환되는 창 크기에 관한 한 가지 중요한 특징은 이전에 시스템 표시줄을 제외했다는 것입니다.

구성 크기는 일반적으로 리소스 선택(예: /res/layout-h500dp)에 사용되며 여전히 유효한 사용 사례입니다. 그러나 레이아웃 계산에 사용하는 것은 항상 권장되지 않습니다. 그렇게 한다면 이제 그만두어야 합니다. Configuration 사용을 사용 사례에 따라 더 적합한 값으로 바꿔야 합니다.

이 메서드를 사용하여 레이아웃을 계산하는 경우 CoordinatorLayout 또는 ConstraintLayout와 같은 적절한 ViewGroup를 사용하세요. 이 메서드를 사용하여 시스템 탐색 메뉴의 높이를 결정한다면 WindowInsets를 사용하세요. 앱 창의 현재 크기를 알아보려면 computeCurrentWindowMetrics를 사용하세요.

다음 목록에서는 이 변경사항의 영향을 받는 필드를 설명합니다.

  • Configuration.screenWidthDpscreenHeightDp 크기에서 더 이상 시스템 표시줄을 제외하지 않습니다.
  • Configuration.smallestScreenWidthDpscreenWidthDpscreenHeightDp의 변경사항의 간접적인 영향을 받습니다.
  • Configuration.orientation는 정사각형에 가까운 기기에서 screenWidthDpscreenHeightDp의 변경사항으로 간접적인 영향을 받습니다.
  • Display.getSize(Point)는 구성 변경사항의 간접적인 영향을 받습니다. 이 기능은 API 수준 30부터 지원 중단되었습니다.
  • Display.getMetrics()는 API 수준 33부터 이미 이와 같이 작동했습니다.

UltraTextHeight 속성의 기본값이 true로 설정됩니다.

对于以 Android 15 为目标平台的应用,elegantTextHeight TextView 属性默认变为 true,将默认使用的紧凑字体替换为一些具有较大垂直指标的脚本,并且这种字体更易于阅读。紧凑字体的引入是为了防止破坏布局;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing 属性拉伸垂直高度,以防止许多此类破坏。

在 Android 15 中,紧凑字体仍保留在系统中,因此您的应用可以将 elegantTextHeight 设置为 false,以获得与之前相同的行为,但即将在未来版本中提供支持。因此,如果您的应用支持以下文字:阿拉伯语、老挝语、缅甸、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语,请将 elegantTextHeight 设置为 true,以测试应用。

以 Android 14(API 级别 34)及更低版本为目标平台的应用的 elegantTextHeight 行为。
以 Android 15 为目标平台的应用的 elegantTextHeight 行为。

복잡한 문자 도형의 TextView 너비 변경

In previous versions of Android, some cursive fonts or languages that have complex shaping might draw the letters in the previous or next character's area. In some cases, such letters were clipped at the beginning or ending position. Starting in Android 15, a TextView allocates width for drawing enough space for such letters and allows apps to request extra paddings to the left to prevent clipping.

Because this change affects how a TextView decides the width, TextView allocates more width by default if the app targets Android 15 or higher. You can enable or disable this behavior by calling the setUseBoundsForWidth API on TextView.

Because adding left padding might cause a misalignment for existing layouts, the padding is not added by default even for apps that target Android 15 or higher. However, you can add extra padding to preventing clipping by calling setShiftDrawingOffsetForStartOverhang.

The following examples show how these changes can improve text layout for some fonts and languages.

Standard layout for English text in a cursive font. Some of the letters are clipped. Here is the corresponding XML:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
Layout for the same English text with additional width and padding. Here is the corresponding XML:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhan="true" />
Standard layout for Thai text. Some of the letters are clipped. Here is the corresponding XML:

<TextView
    android:text="คอมพิวเตอร์" />
Layout for the same Thai text with additional width and padding. Here is the corresponding XML:

<TextView
    android:text="คอมพิวเตอร์"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhan="true" />

EditText의 언어 인식 기본 줄 높이

In previous versions of Android, the text layout stretched the height of the text to meet the line height of the font that matched the current locale. For example, if the content was in Japanese, because the line height of the Japanese font is slightly larger than the one of a Latin font, the height of the text became slightly larger. However, despite these differences in line heights, the EditText element was sized uniformly, regardless of the locale being used, as illustrated in the following image:

Three boxes representing EditText elements that can contain text from English (en), Japanese (ja), and Burmese (my). The height of the EditText is the same, even though these languages have different line heights from each other.

For apps targeting Android 15, a minimum line height is now reserved for EditText to match the reference font for the specified Locale, as shown in the following image:

Three boxes representing EditText elements that can contain text from English (en), Japanese (ja), and Burmese (my). The height of the EditText now includes space to accommodate the default line height for these languages' fonts.

If needed, your app can restore the previous behavior by specifying the useLocalePreferredLineHeightForMinimum attribute to false, and your app can set custom minimum vertical metrics using the setMinimumFontMetrics API in Kotlin and Java.

카메라 및 미디어

Android 15에서는 Android 15 이상을 타겟팅하는 앱의 카메라 및 미디어 동작을 다음과 같이 변경합니다.

오디오 포커스 요청 제한사항

以 Android 15 为目标平台的应用必须是热门应用或运行与音频相关的前台服务,才能请求音频焦点。如果应用在不符合其中任何一项要求时尝试请求焦点,调用会返回 AUDIOFOCUS_REQUEST_FAILED

如果前台服务的类型为 mediaPlaybackcameramicrophonephoneCall,则会被视为与音频相关。

如需详细了解音频焦点,请参阅管理音频焦点

업데이트된 비 SDK 제한사항

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

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

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

<

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