一、前言相信最近很多Google Play开发者都收到了,关于APP需要兼容Android 15的政策警告。

Google Play老开发者都知道,Android系统版本适配,一直是影响App上架Google Play非常重要的因素。
适配不佳有哪些影响?
- 功能异常被拒若 App 对 Android 版本适配不佳,在某些版本系统上出现如无法安装、安装后无法加载、加载后无响应、频繁崩溃等功能异常情况,根据 Google Play “最基本的功能” 政策,这类应用是不得上架的。
- 用户体验差被拒不同的 Android 版本在系统特性、界面风格、操作逻辑等方面可能存在差异。如果 App 没有做好适配,可能在新系统上出现界面显示错乱、操作不流畅等问题,无法提供稳定、响应迅速、引人入胜的用户体验,也会导致上架被拒。
我们的适配建议:
- 及时关注政策更新Google Play 会不定期更新开发者政策,在政策更新后会给予一定的缓冲时间让开发者进行应用适配,但开发者需及时关注政策变化,以便提前规划适配工作。
- 全面测试在提交上架前,要在多种不同 Android 版本的设备上进行充分测试,覆盖低版本到高版本,尽可能模拟用户的真实使用场景,检查应用在不同系统版本上的功能完整性、稳定性和兼容性等。
- 遵循官方文档和指南Google 提供了丰富的官方文档和开发指南,如关于不同 Android 版本的特性介绍、适配建议、API 使用说明等,开发者应仔细阅读并按照要求进行应用开发和适配。
按照Google Play最新政策要求,2025年8月31日起,新上架或者更新APP必须以 Android 15(API 级别 35)为目标平台,才能提交到Google Play。
所以Android 15应用适配,对每个出海人来说都迫在眉睫。
目前市场上只有极少量有关Android 15适配文章,但是此类文章要么不专业,要么不全面,所以本人特开此Android 15应用适配指南系列,以帮助更多开发者适配好Android 15,从而更顺利的上架到Google Play。
Android 15适配有2大核心要点:
- 针对所有APP的行为变更。
- Target SDK为Android 15的行为变更。
那么本篇就围绕这2大核心适配要点开讲。
二、影响Android 15上所有应用的行为变更
1、最低可安装TargetSDK级别为24
1.1、特性背景
Android 15进一步提升了最低可安装TargetSDK级别。
1.2、适用范围
Android 15上的所有App。
1.3、特性内容
Android 15在Android 14所做的更改的基础上进一步加强了安全性。在Android 15中,目标SDK版本低于24的应用程序无法安装。要求应用程序满足现代API级别有助于确保更好的安全性和隐私保护。
恶意软件通常针对较低的API级别,以绕过在较高Android版本中引入的安全性和隐私保护。例如,一些恶意软件应用程序使用目标SDK版本22,以避免受到Android 6.0 Marshmallow(API级别23)在2015年引入的运行时权限模型的限制。这个Android 15的变化使得恶意软件更难避开安全和隐私的改进。
尝试安装一个针对较低API级别的应用程序会导致安装失败,并在Logcat中出现以下消息:
INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 24, but found 7
请确保应用的targetSDK至少为24。
1.4、应用适配
2、软件包停止状态变更
2.1、特性背景
针对应用的PendingIntent,Android 15进一步增强了forcestop机制的作用。
2.2、适用范围
Android 15上的所有App。
2.3、特性内容
当应用在 Android 15 上进入停止状态时,系统会取消这个应用的所有PendingIntent。当用户的操作将应用从停止状态中移除时,系统会向应用传递 ACTION_BOOT_COMPLETED 广播,使应用可以重新注册PendingIntent。具体情况还需参考各家厂商对ACTION_BOOT_COMPLETED 广播的管控。
如果应用进入停止状态,则所有这些待处理的 intent 都会被取消,系统会停用该应用的 widget。这些 widget 呈灰显状态,用户无法与其互动。系统会在用户下次启动应用时重新启用这些 widget,目前的测试结果显示用户点击一次widget也能启用。
Demo演示
我们分别在Android 14和15上执行PendingIntent.getActivity方法,然后使用adb shell dumpsys activity intents命令来dump AMS中mIntentSenderRecords字段的内容并观察。测试代码:
Intent intent = new Intent(mContext, MainActivity.class); PendingIntent pi = PendingIntent.getActivity(mContext, 5, intent, PendingIntent.FLAG_IMMUTABLE);
测试应用的包名为com.example.alarmlab。
Android 14上现象:
在运行测试代码之前,在终端运行adb shell dumpsys activity intents | grep -i “alarmlab”,终端没有给出任何输出,说明mIntentSenderRecords中没有com.example.alarmlab创建的PendingIntent。
运行测试代码,运行adb shell dumpsys activity intents | grep -i “alarmlab”,终端给出了我们创建的PendingIntent的dump信息,可见这个PendingIntent已被AMS记录。
forcestop掉我们的测试应用com.example.alarmlab,运行adb shell dumpsys activity intents | grep -i “alarmlab”,终端给出了我们创建的PendingIntent的dump信息,可见这个PendingIntent在AMS中没有被删除。

Android 15上现象:
在运行测试代码之前,在终端运行adb shell dumpsys activity intents | grep -i “alarmlab”,终端没有给出任何输出,说明mIntentSenderRecords中没有com.example.alarmlab创建的PendingIntent。
运行测试代码,运行adb shell dumpsys activity intents | grep -i “alarmlab”,终端给出了我们创建的PendingIntent的dump信息,可见这个PendingIntent已被AMS记录。
forcestop掉我们的测试应用com.example.alarmlab,运行adb shell dumpsys activity intents | grep -i “alarmlab”,终端没有给出任何输出,说明mIntentSenderRecords中com.example.alarmlab创建的PendingIntent被删除了。

2.4、应用适配
建议应用结合自身对PendingIntent的使用场景,考虑应用被force-stop之后AMS中的PendingIntentRecord会被删除的情况,按需做出调整。可以结合ApplicationStartInfo API中的wasForceStopped()接口做出判断。
3、在达到资源限制时,直接和分流音频播放会使之前打开的直接或分流音轨失效
3.1、特性背景
Android 15之前,如果应用请求使用 direct playback 或者 offload playback 播放模式时,另一个应用正在播放音频并且资源达到限制,则请求的应用无法创建新的 AudioTrack。
3.2、适用范围
Android 15上的所有App。
3.3、特性内容
Android 15中当应用请求使用 direct playback 或者 offload playback 播放模式时资源达到限制后,系统会让已经创建使用的 AudioTrack 对象也失效。
3.4、应用适配
使用 offload playback 播放模式的音频类App需要适配这个特性。
4、支持16KB Page Size
4.1、特性背景
一直以来,Android 仅支持 4 KB 的内存页面大小,针对 Android 设备通常拥有的平均总内存量,系统内存性能进行了优化。从 Android 15 开始,Android 支持配置为使用 16 KB 页面大小的设备(即 16 KB 设备)。
4.2、适用范围
Google计划明年开始把兼容16KB页面作为上架Google Play的必要条件。今年携带Android 15的设备可能尚不会使用16KB页面,但国内厂商最终将跟随Google,因此建议应用适配。
4.3、特性内容
随着设备制造商不断打造具有更大物理内存 (RAM) 的设备,这些设备中的许多可能会配置 16 KB(最终更大)的页面大小,以优化设备的性能。添加对 16 KB 设备的支持可让应用在这些设备上运行,并帮助应用从相关性能改进中受益。
性能提升:
- 在系统面临内存压力时缩短应用启动时间:平均降低了 3.16%
- 降低应用启动时的功耗:平均降低 4.56%
- 相机启动速度更快:平均热启动速度加快 4.48%,冷启动速度平均加快 6.60%
- 缩短了系统启动时间:平均缩短了 1.5%(约 0.8 秒)
兼容性影响:
- 含有so库的应用需要重新构建支持 16KB 设备的应用,否则在16KB设备上很可能会crash。
4.4、应用适配
建议应用适配该特性。检查应用是否受到影响:
- 含有so库的应用都会受到影响。
- 如果不确定应用是否含有so库,可以使用Apk Analyzer分析。
构建支持 16KB 设备的应用:
- 升级到 AGP 版本 8.3 或更高版本,并使用未压缩的共享库,或在AGP 版本 8.2 或更低版本上使用压缩共享库。
- 使用 16 KB ELF 对齐编译应用。
- 检查引用特定页面大小的代码。
在 16 KB 的环境中测试您的应用:
使用基于 16 KB 的 Android 15 系统映像设置 Android 模拟器。
适配细节可参考官方文档:https://developer.android.com/guide/practices/page-sizes?hl=zh-cn。
5、默认开启预测性返回动画
5.1、特性背景
已经迭代多个版本的预测性返回动画在Android 15上全面开放。
5.2、适用范围
Android 15上的所有App。
5.3、特性内容
从 Android 15 开始,移除了预测性返回动画的开发者选项。现在,对于已完全或在 activity 级别选择启用预测性返回手势的应用,系统现在会显示“返回主屏幕”“跨任务”和“跨 activity”等系统动画。
5.4、应用适配
现在,对于已完全或在 activity 级别选择启用预测性返回手势的应用,系统现在会显示“返回主屏幕”“跨任务”和“跨 activity”等系统动画。如果应用受到影响,请执行以下操作:
- 确保应用已正确迁移,以使用预测性返回手势。
- 确保 fragment 转换支持预测性返回导航。
- 停止使用动画和框架转换,并改用 Animator 和 AndroidX 转换。
- 从FragmentManager 不知道的返回堆栈中迁出。请改用由 FragmentManager 或 Navigation 组件管理的返回堆栈。
如果想要从零开始适配预测性返回动画,请参考官方文档:
https://developer.android.google.cn/guide/navigation/custom-back/predictive-back-gesture?hl=zh-cn
三、影响以Android 15为目标平台应用的行为变更
1、新的媒体处理前台服务类型
1.1、特性背景
Android 15继续完善前台服务的类型机制。
1.2、适用范围
targetSDK≥Android 15
1.3、特性内容
Android 15引入了一种新的前台服务类型,即mediaProcessing。这种服务类型适用于像转码媒体文件这样的操作。例如,媒体应用程序可能会下载音频文件并需要在播放之前将其转换为不同的格式。您可以使用mediaProcessing前台服务来确保即使应用程序在后台运行,转换也可以继续进行。
该系统允许一个应用的媒体处理服务在24小时内运行总共6个小时,之后系统会调用正在运行的服务的Service.onTimeout(int, int)方法(在Android 15中引入)。此时,服务有几秒钟的时间来调用Service.stopSelf()。如果服务没有调用Service.stopSelf(),则会出现以下错误消息的故障:”A foreground service of <fgs_type> did not stop within its timeout: <component_name>”。在Beta 2中,故障消息显示为ANR,但在未来的Beta版本中,此故障消息将抛出自定义异常。
ontext: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { // 在这里执行后台任务 Log.w("BackgroundWorker", "Doing work...")
val audioManager = applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager val result = audioManager.requestAudioFocus( null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN )
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { Log.w( "BackgroundWorker", "requestAudioFocus success, AudioManager.AUDIOFOCUS_REQUEST_GRANTED " ) } else { Log.w("BackgroundWorker", "requestAudioFocus failure,result:$result") } return Result.success() }}
运行代码查看相关日志,可以发现由Demo运行结果可知,当应用不在前台,且无音频相关的前台服务时,音频焦点申请会失败,系统输出类似“I Focus request DENIED for uid:10301 clientId:android.media.AudioManager@c71a082 req:1 procState:8”的日志,即告知开发者音频焦点申请被拒绝。
2025-01-11 18:44:19.641 30567-30567 AudioFocusActivity com.example.myapplication I onPause2025-01-11 18:44:20.537 30567-30567 VRI[AudioFocusActivity] com.example.myapplication D visibilityChanged oldVisibility=true newVisibility=false2025-01-11 18:44:29.680 30567-30657 BackgroundWorker com.example.myapplication W Doing work...2025-01-11 18:44:29.691 2201-5135 AS.HardeningEnforcer system_process I Focus request DENIED for uid:10301 clientId:android.media.AudioManager@c71a082 req:1 procState:82025-01-11 18:44:29.693 30567-30657 BackgroundWorker com.example.myapplication W requestAudioFocus failure,result:0
3.4、应用适配
如果需要播放音频或者录制音频,那么必须考虑当前是否为前台应用(在前台或者有和音频相关的前台服务)。
4、elegantTextHeight属性默认为 true
4.1、特性背景
ElegantTextHeight:优雅的文本高度。某些语言的字体较高,如果该值为false会选用紧凑字体,设置为true就会比较宽松的字体。这个特性对中文没有影响。
4.2、适用范围
targetSDK≥Android 15
4.3、特性内容
对于targetSDK大于Android 15的应用来说,TextView中的elegantTextHeight属性默认值将是true。用更易读的字体替换了默认使用的紧凑字体,该紧凑字体是为了防止布局出现问题而引入的;Android13(API级别33)通过允许文本布局拉伸垂直高度,使用fallbackLinewSpacing属性来防止许多这些问题。
在Android15中,紧凑字体仍然存在于系统中,因此应用可以将elegantTextHeight设置为false,以获得与以前相同的行为,但是在未来版本可能不再支持。因此,应用支持以下脚本:阿拉伯语、老挝语,缅甸语、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥迪亚语、泰卢固语或泰语,请将elegantTextHeight设置为true进行测试。

elegantTextHeight behavior for apps targeting Android 14 (API level 34) and lower.
elegantTextHeight behavior for apps targeting Android 15.

注:从左到右的语言分别为缅甸语、缅甸语、汉语和汉语
黄色背景:elegantTextHeight的值为false
绿色背景:elegantTextHeight的值为true
4.4、应用适配
该特性对某些字体有影响,对汉语无影响。如果想保持之前的状态,可将该值设置为false。但是在未来有可能谷歌会要求必须为true。所以三方应用需要提前做好适配准备。
5、Edge-to-edge(边到边)强制执行
5.1、特性背景
在Android 15设备上,targetSDK>=Android15的应用将强制进行全屏展示,并且状态和导航栏将保持透明化。targetSDK<Android 15的应用程序默认不会允许边到边的特性,即仍然保持用户层的View在状态栏和导航栏之间。当在Android15平台上之前使用的设置系统栏颜色的API将被弃用,包括setNavigationBarColor
,setNavigationBarColor
,即便使用这些方法设置了,系统也将默认保持沉浸式的体验。
5.2、适用范围
targetSDK≥Android 15
5.3、特性内容
在Android15之前系统会在DecorView 中添加两个背景View用来控制systembar的背景色,同时也把ContentView的大小范围控制在这两个view的之间,如下图:
在Android15上系统默认去掉上述两个背景View,所以ContentView的范围和DecorView 一样,全屏展示:

这一系列的变化对应用产生的影响,如下图应用没有适配边到边的情况下,会发生应用层的内容布局控件会展示到statusbar的后面,这种情况开发者需要对非compose应用和compose应用进行区分处理:
非compose应用需要在应用布局中添加android:fitsSystemWindows=”true”,或者将用户View setFitsSystemWindows(true),否则就会出现如下图所示的,内容布局控件会展示到了statusbar的后面的异常现象:

compose 中material3一些组件默认是处理掉这个insets,因此不会有问题,能正常显示:

下图展示了material2系列组件没有添加padding导致的显示异常:
material2添加padding后,显示效果恢复正常:

5.4、应用适配
如果应用targetSdk>=Android 15,那么针对布局需要设置android:fitsSystemWindows=”true” :
针对compose:

使用material3 的组件作为头布局和底布局如TopAppBar,BottomAppBar或者NavigationBar,如需要使用material2的组件作为头布局和底布局,需要自己处理padding 或者contentWindowInsets
来处理。并且在Android15版本应用使用setStatusBarColor
将不再生效,而setNavigationBarColor
只针对三键导航栏有效果。
6、稳定的configuration
6.1、特性背景
Configuration类专门用于描述手机设备上的配置信息:
public int densityDpi; //得到设备的密度public float fontScale; //获取当前用户设置的字体的缩放因子public int KeyboardHidden;//该属性会返回一个boolean值用于表示当前的键盘是否可用,该属性不仅会判断系统的硬件键盘,也会判断系统位于屏幕上的软键盘,如果该系统的硬件键盘不可用但软键盘可用该属性会返回KEYBOARDHIDDEN_NO,只有当两个键盘都不可用的时候才返回KEYBOARDHIDDEN_YESpublic int keyboard;//获取当前设备所关联的键盘的类型public Locale locale;//获取用于当前的Localepublic int mcc;//得到移动信号的国家码public int mnc;//得到移动信号的网络码public int navigation;//判断系统上方向导航设备的类型。该属性的返回值:NAVIGATION_NONAV(无导航)、NAVIGATION_DPAD(DPAD导航)、NAVIGATION_TRACKBALL(轨迹球导航)、NAVIGATION_WHEEL(滚轮导航)public int orientation;//得到系统屏幕的方向,该属性将会返回ORIENTATION_LANDSCAPE(横向屏幕),ORIENTATION_PORTRAIT(竖向屏幕),ORIENTATION_SQUARE(方形屏幕)三个属性值之一public int touchscreen;//获取系统触摸屏的触摸方式。该属性的返回值:TOUCHSCREEN_NOTOUCH(无触摸屏)、TOUCHSCREEN_STYLUS(触摸笔式触摸屏)、TOUCHSCREEN_FINGER(接收手指的触摸屏)等属性值
如果应用程序的targetSDK版本是Android15或更高版本,则Configuration不再排除系统栏。如果在布局计算中使用Configuration类中的屏幕大小,开发者应该使用更好的替代方案,如适当的ViewGroup、WindowInsets或WindowMetricsCalculator,具体取决于您的需求。
Configuration自API1来就可用,通常从Activity.onConfigurationChanged中获取它。它提供了密度、方向和大小等信息。Configuration返回的窗口大小的一个重要特征是它排除了系统栏。
Configuration大小通常用于资源选择,例如res/layout-h500dp仍然有效。但是不鼓励使用它来进行布局的计算。如果进行布局计算,应该寻找更合适的方案来代替它。
如果用Configuration来计算布局,请使用适当的ViewGroup,如CoordinatorLayout或ConstraintLayout。如果你用它来确定系统导航栏的高度,使用WindowInsets。如果想确定当前应用窗口的大小,请使用computeCurrentWindowMetrics。
6.2、适用范围
targetSDK≥Android 15
6.3、特性内容
Android15上screenWidthDp和screenHeightDp将包含系统条等内容的尺寸。但是当应用使用Window#setDecorFitSystemWindowWindows(boolean)进行边到边显示的时候,系统条尺寸不被包含。
6.4、应用适配
应用需要适配使用到Configuration中的screenHeightDp和screenWeightDp的地方以及所间接影响到的相关值:
Configuration.smallestScreenWidthDp
Configuration.orientation
Display.getSize(Point) (该接口已在API level30废弃)
Display.getMetrics()(和API30及其以后的接口等级一致)

7、安全的后台Activity启动
7.1、特性背景
Android15继续加强对后台启动activity的管控,以提高安全性。
7.2、适用范围
targetSDK≥Android 15
7.3、特性内容
- 栈顶应用如果在AndroidManifest.xml 文件中设置allowCrossUidActivitySwitchFromBelow为false,可以阻止自己UID 不匹配的应用启动activity。
- PendingIntent的创建者可以通过ActivityOptions#setPendingIntentCreatorBackgroundActivityStartMode(int state)方法来赋予PendingIntent后台启动activity的权力。
- PendingIntent的发送者也可以通过ActivityOptions#setPendingIntentBackgroundActivityStartMode(int state)方法来赋予PendingIntent后台启动activity的权力。
- 防止其他应用的 activity 随意启动到您自己的task中。
- 防止不可见的窗口被用于后台启动。
7.4、应用适配
应用需要认真考察并测试需要后台启动的情况,防止后台启动被系统限制从而造成功能异常。
8、Android 15 中有关限制非 SDK 接口的更新
Android 15 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。
如果您的应用并非以 Android 15 为目标平台,其中一些变更可能不会立即对您产生影响。不过,虽然您的应用可以访问某些非 SDK 接口(具体取决于应用的目标 API 级别),但使用任何非 SDK 方法或字段始终存在导致应用出问题的显著风险。
如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试该应用进行确认。如果您的应用依赖于非 SDK 接口,则应开始计划迁移到 SDK 替代方案。不过,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的功能找到无需使用非 SDK 接口的替代方案,则应请求新的公共 API。
如需查看 Android 15 的所有非 SDK 接口的完整列表,可参考:
https://dl.google.com/developers/android/vic/non-sdk/hiddenapi-flags.csv
9、OpenJDK 17变更
Android 15继续更新Android核心库,以与最新的OpenJDK LTS版本的功能保持一致。其中一个更改可能会影响针对Android 15的应用程序兼容性:1. 字符串格式化API的更改在使用以下String.format()和Formatter.format() API时,参数索引、标志、宽度和精度的验证现在更加严格:String.format(String, Object[])String.format(Locale, String, Object[])Formatter.format(String, Object[])Formatter.format(Locale, String, Object[])
例如,当在格式字符串中使用参数索引为0(%0)时,将抛出以下异常:
IllegalFormatArgumentIndexException: Illegal format argument index = 0
在这种情况下,可以通过使用参数索引为1(%1)来解决问题。2. 语言代码处理的更改在使用Locale API时,希伯来语、意第绪语和印度尼西亚语的语言代码不再转换为其过时的形式(希伯来语:iw,意第绪语:ji,印度尼西亚语:in)。当指定其中一种语言环境的语言代码时,请改用ISO 639-1中的代码(希伯来语:he,意第绪语:yi,印度尼西亚语:id)。3. 随机整数序列的更改在https://bugs.openjdk.org/browse/JDK-8301574中所做的更改后,以下Random.ints()方法现在返回与Random.nextInt()方法不同的数字序列:Random.ints(long)Random.ints(long, int, int)Random.ints(int, int)Random.ints()
通常情况下,这种更改不应导致应用程序崩溃,但您的代码不应期望从Random.ints()方法生成的序列与Random.nextInt()匹配。
四、总结
以上就是Android 15应用适配指南全篇。当然在APP提交Google Play前,需要尽可能在多种不同 Android 版本的设备上进行充分测试,覆盖低版本到高版本,尽可能模拟用户的真实使用场景,检查应用在不同系统版本上的功能完整性、稳定性和兼容性等。
最后,希望Android 15应用适配指南对各位出海大佬们有所帮助,上架Google Play都能顺顺利利!