Android 11 引入了一些工具,供您用于测试和调试自己的应用,检查其是否兼容最新版平台中的行为变更。这些工具属于新的兼容性框架的一部分,可让应用开发者单独开启和关闭各项变更。有了这种灵活性,您既可以关闭某一项变更,然后继续针对平台中的其他变更测试应用;也可以每次单独针对一项行为变更测试应用。
不管是影响所有应用的行为变更,还是只影响以 Android 11 为目标平台的应用的行为变更,您都可以随意开启或关闭。
如何识别已启用哪些变更
您可以使用开发者选项、logcat 或 ADB 命令查看当前已启用的行为变更。
使用开发者选项识别已启用的变更

图 1. 开发者选项中的“应用兼容性变更”屏幕
您可以在设备的开发者选项中查看当前已启用的变更,并且可以开启/关闭这些变更。如需访问这些选项,请按以下步骤操作:
- 如果开发者选项尚未启用,请启用开发者选项。
- 打开设备的“设置”应用,然后依次导航到系统 > 高级 > 开发者选项 > 应用兼容性变更。
- 从列表中选择您的应用。
每项行为变更通常属于以下两种类别之一:
影响在 Android 11 上运行的所有应用(无论应用的
targetSdkVersion
是什么)的变更。默认情况下,这些变更在兼容性框架中处于启用状态,并且会在界面的默认启用的应用兼容性变更部分列出。
只会影响以Android 11 为目标平台的应用的变更。
如果您的应用以 Android 11 为目标平台,默认情况下,这些变更在兼容性框架中处于启用状态,并且会在界面的在 SDK 29 之后启用的应用兼容性变更部分列出。
在图 1 中,您还会看到一个名为默认停用的应用兼容性变更部分。此部分中的变更通常为实验性变更。
使用 logcat 识别已启用的变更
对于每项行为变更,应用在其进程运行过程中首次调用受影响的 API 时,系统都会输出一条类似如下的 logcat 消息:
D CompatibilityChangeReporter: Compat change id reported: 141455849; UID 10265; state: ENABLED
每条 logcat 消息都包含以下信息:
- 变更 ID
- 指明影响到应用的变更。该值映射到“应用兼容性变更”屏幕中列出的某项行为变更(参见图 1)。在此示例中,
141455849
映射到ANONYMIZED_DEVICE_ADDRESS_CHANGE_ID
。 - UID
- 指示受该变更影响的应用。
- 状态
指示该变更当前是否正在影响应用。
状态可以是以下值之一:
状态 含义 ENABLED
该变更当前已启用,如果应用使用已变更的相应 API,该变更将会影响应用的行为。 DISABLED
该变更当前已停用,不会影响应用。
注意:如果此变更停用的原因是应用的
targetSDKVersion
低于要求的阈值(应用不是以 Android 11 为目标平台),当应用提高其targetSDKVersion
,从而以 Android 11 为目标平台时,系统会默认启用此变更。LOGGED
此变更当前通过兼容性框架记录,但无法开启或关闭。虽然无法切换此变更的状态,但它仍可能会影响应用的行为。如需了解详情,请参阅行为变更列表中的变更说明。在许多情况下,这些类型的变更是实验性变更,可以忽略。
使用 ADB 识别已启用的变更
如需查看整个设备上的所有变更(包括已启用和已停用的变更),请运行以下 ADB 命令:
adb shell dumpsys platform_compat
输出内容中会列出每项变更的以下信息:
- 变更 ID
- 此行为变更的唯一标识符,例如
141455849
。 - 名称
- 此行为变更的名称,例如
ANONYMIZED_DEVICE_ADDRESS_CHANGE_ID
。 - targetSDKVersion 条件
控制此变更是否启用的
targetSDKVersion
值(如果有)。例如,如果此变更仅对以 SDK 版本 30 或更高版本为目标平台的应用才会启用,系统会输出
enableAfterTargetSdk=29
。如果此变更的启用与否不受targetSDKVersion
控制,系统会输出enableAfterTargetSdk=0
。- 软件包替换
其中变更的默认状态(启用或停用)已被替换的各个软件包的名称。
例如,如果此变更默认处于启用状态,而您使用开发者选项或 ADB 关闭了此变更,应用的软件包名称会在此列出。在这种情况下,输出结果如下:
packageOverrides={com.my.package=false}
受
targetSDKVersion
控制的变更在默认情况下可以处于启用状态,也可以处于停用状态,因此该软件包列表可以同时包含 true 和 false 实例,具体取决于每个应用的targetSDKVersion
。例如:packageOverrides={com.my.package=true, com.another.package=false}
在何时切换变更的开启/关闭状态
兼容性框架的主要目的在于,在您使用新版 Android 测试应用时,为您提供可控性和灵活性。
何时关闭变更
对于特定的平台版本,影响所有应用(无论应用的 targetSDKVersion
是什么)的变更在默认情况下处于启用状态。通常,您首先需要针对这些变更测试并更新您的应用,以确保用户在该版本平台上使用应用的体验不会受到影响。您也应该优先测试这些变更,因为在使用 Android 的公开发布 build 时,为保护最终用户的安全,您无法关闭这些变更。
如果您的应用以特定的 targetSDKVersion
为目标平台,受该版本控制的任何变更在默认情况下也将处于启用状态。
由于应用可能会受到多项变更的影响,因此您可以逐项关闭这些变更。如果应用崩溃,您可以使用此方法确定是哪项平台变更造成了应用的崩溃。
何时开启变更
对于受特定 targetSDKVersion
控制的变更,当应用的目标 SDK 版本低于该版本阈值时,这些变更在默认情况下就会处于停用状态。在某些情况下,您可能需要启用这些变更。
例如,您可能需要针对下一 targetSdkVersion
中的一系列平台变更测试您的应用。您可以使用开发者选项或 ADB 命令逐个启用和测试受 targetSDKVersion 控制的变更,而不是更改应用清单并一次性选择启用所有变更。这项附加控制可以帮助您单独测试各项变更,避免同时调试和更新应用的多个部分。
开启或关闭变更
兼容性框架支持您使用开发者选项或 ADB 命令开启或关闭各项变更。由于开启或关闭变更可能会导致应用崩溃或停用重要的安全变更,因此对于何时可以切换变更的状态有一些限制。
使用开发者选项开启或关闭变更
您可以使用开发者选项开启或关闭变更。如需找到开发者选项,请按以下步骤操作:
- 如果开发者选项尚未启用,请启用开发者选项。
- 打开设备的“设置”应用,导航到系统 > 高级 > 开发者选项 > 应用兼容性变更。
- 从列表中选择您的应用。
在变更列表中,找到想要开启或关闭的变更,然后点按相应的开关。
使用 ADB 开启或关闭变更
如需使用 ADB 开启或关闭变更,请运行以下相应的命令:
adb shell am compat enable (CHANGE_ID|CHANGE_NAME) PACKAGE_NAME
adb shell am compat disable (CHANGE_ID|CHANGE_NAME) PACKAGE_NAME
您需要传递 CHANGE_ID
(例如 141455849
)或 CHANGE_NAME
(例如 ANONYMIZED_DEVICE_ADDRESS_CHANGE_ID
)以及应用的 PACKAGE_NAME
。
您也可以使用以下命令将变更重置回默认状态,移除您使用 ADB 或开发者选项设置的任何替换状态:
adb shell am compat reset (CHANGE_ID|CHANGE_NAME) PACKAGE_NAME
切换变更的开启/关闭状态的限制
默认情况下,每项行为变更不是处于启用状态,就是处于停用状态。影响所有应用的变更在默认情况下处于启用状态。其他变更的启用与否受 targetSdkVersion
控制。如果应用以相应的 SDK 版本或更高版本为目标平台,这些变更在默认情况下处于启用状态;如果应用的目标 SDK 版本低于该版本阈值,这些变更在默认情况下将处于停用状态。当您开启或关闭某项变更时,会替换其默认状态。
为了避免兼容性框架遭到恶意使用,对于何时可以切换变更的状态有一些限制。是否可以切换变更的状态取决于变更的类型、应用的可调试性,以及设备上运行的 build 类型。下表介绍了不同类型的变更的状态切换限制:
Build 类型 | 不可调试的应用 | 可调试的应用 | |
---|---|---|---|
所有变更 | 受 targetSDKVersion 控制的变更 | 所有其他变更 | |
开发者预览版或 Beta build | 无法切换 | 可以切换 | 可以切换 |
公开用户 build | 无法切换 | 可以切换 | 无法切换 |
兼容性框架中包含的行为变更
此部分的列表中介绍了 Android 11 中的兼容性框架中包含的各项行为变更。您可以结合使用此列表与开发者选项和 ADB 命令对应用进行测试和调试。
ADD_CONTENT_OBSERVER_FLAGS
变更 ID:150939131
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,系统会提供一个包含整数 flags
参数的新的公共 API 重载 onChange(boolean, Uri, int)
。
对于使用包含整数 userId
参数的非 SDK onChange()
重载方法的应用,该新方法是一种公共 SDK 方法。
ADMIN_APP_PASSWORD_COMPLEXITY
变更 ID:123562444
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的管理应用,每当应用设置的密码要求与当前指定的密码质量不相符时,系统就会抛出错误。例如,当密码质量设置为 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
时,应用将无法设置最小密码长度。在这种情况下,在尝试设置最小密码长度之前,应用应首先调用 setPasswordQuality()
方法,然后才能调用 setPasswordMinimumLength()
方法。
此外,如果以 Android 11 为目标平台的管理应用降低密码质量,任何不再适用的现有密码要求都会重置为其默认值。
APP_DATA_DIRECTORY_ISOLATION
变更 ID:143937733
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
以 Android 11 为目标平台的应用不能再访问任何应用的私有数据目录中的文件,而不管其他应用的目标 SDK 版本是什么。
如需了解详情,请参阅访问私有目录。
APN_READING_PERMISSION_CHANGE_ID
变更 ID:124107808
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,现在必须具备 Manifest.permission.WRITE_APN_SETTINGS
权限才能访问 APN 数据库。
如需详细了解此变更,请参阅限制对 APN 数据库的读取访问。
BACKGROUND_RATIONALE_CHANGE_ID
变更 ID:147316723
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
现在,应用每次在后台请求访问设备的位置信息时,都必须提供有效的理由。
如需详细了解此变更,请参阅有关如何在 Android 11 中在后台访问位置信息的指南,该指南介绍了 Android 11 中与位置信息相关的隐私权变更。
CALLBACK_ON_CLEAR_CHANGE
变更 ID:119147584
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
现在每次调用 Editor.clear
时,都会使用 null
键回调 OnSharedPreferenceChangeListener.onSharedPreferenceChanged
。
如需详细了解此变更,请参阅 OnSharedPreferenceChangeListener 的回调变更。
CALLBACK_ON_MORE_ERROR_CODE_CHANGE
变更 ID:130595455
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
错误代码现在针对 updateAvailableNetworks(List,
Executor,
Consumer)
和 setPreferredOpportunisticDataSubscription(int, boolean, Executor,
Consumer)
进行了扩展。
CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
变更 ID:148180766
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
这是 startWatchingMode(String, String,
AppOpsManager.OnOpChangedListener)
的细微行为变更。在进行此变更之前,系统会针对切换的操作回调。在进行此变更之后,系统会针对实际请求的操作回调;如果未指定操作,就会针对所有切换的操作回调。
CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID
变更 ID:136219221
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,只有在清单文件中将 R.attr.foregroundServiceType
分别配置为 ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
和 ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
时,前台服务才会接收正在使用的摄像头和麦克风功能。在较低版本的 Android 系统中,前台服务会自动接收摄像头和麦克风功能。
如需详细了解此变更,请参阅 Android 11 中的前台服务类型。
CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK
变更 ID:128611929
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
应用无法再在后台发布自定义消息框。但是,应用在后台仍然可以使用 Toast.makeText(Context, CharSequence,
int)
方法及其变体发布消息框。
如需详细了解此变更,请参阅自定义消息框视图被屏蔽。
CHANGE_RESTRICT_SAW_INTENT
变更 ID:135920175
默认状态:无法切换此变更的状态。它只由兼容性框架记录。
使用 android.settings.MANAGE_APP_OVERLAY_PERMISSION
操作和 package
数据 URI 架构的 intent 不再将用户引导至应用专用屏幕以管理相关权限。相反,用户会被引导至另一个屏幕,在该屏幕中,用户可以管理所有已请求该权限的应用。
CHANGE_TEXT_TOASTS_IN_THE_SYSTEM
变更 ID:147798919
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
文本消息框现在由 SystemUI 呈现,而不是在应用内呈现。这样可防止应用规避对在后台发布自定义消息框的限制。
DEFAULT_SCOPED_STORAGE
变更 ID:149924527
默认状态:对于所有应用处于启用状态。
以 Android 11 为目标平台的所有应用现在都默认使用分区存储,并且不能再停用分区存储。
不过,无论您应用的目标 SDK 版本和清单标记值是什么,您都可以在不使用分区存储的情况下测试应用,只需关闭此变更即可。
如需详细了解 Android 11 中分区存储的变更,请转到关于 Android 11 中 Android 存储变更的页面,请参阅分区存储部分。
EMPTY_INTENT_ACTION_CATEGORY
变更 ID:151163173
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,如果 intent 过滤器的 action
或 category
为空字符串,系统现在会抛出错误。Android 11 之前的平台中有一个错误,允许系统在这种情况下继续运行,而不抛出错误。请注意,这不包括相应属性为 null 或缺失的情况,因为在此类情况下始终都会抛出错误。
FILTER_APPLICATION_QUERY
变更 ID:135549675
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
应用现在需要先声明想要使用的软件包和 intent,然后才能获取有关设备上其他应用的详细信息。应用必须在其清单中使用 <queries>
标记进行声明。
如需详细了解如何在 Android 11 中查询安装的其他应用并与之交互,请参阅软件包可见性隐私权页面。
FORCE_ENABLE_SCOPED_STORAGE
变更 ID:值 - 132649864
默认状态:对于所有应用处于停用状态。
以 Android 11 为目标平台的所有应用现在都默认使用分区存储,并且不能再停用分区存储。
但是,如果您的应用仍以 Android 10(API 级别 29)或更低版本为目标平台,无论应用的目标 SDK 版本和清单标记值是什么,您都可以在使用分区存储的情况下测试应用,只需开启此变更即可。
如需详细了解 Android 11 中分区存储的变更,请转到关于 Android 11 中 Android 存储变更的页面,请参阅分区存储部分。
GET_DATA_CONNECTION_STATE_R_VERSION
变更 ID:148535736
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
检查 PreciseDataConnectionState#getDataConnectionState
的 SDK 版本。
GET_DATA_STATE_R_VERSION
变更 ID:148534348
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
检查 getDataState()
的 SDK 版本。
GET_PROVIDER_SECURITY_EXCEPTIONS
变更 ID:150935354
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11(API 级别 30)或更高版本为目标平台的应用,getProvider(String)
不再抛出任何安全异常。
GET_TARGET_SDK_VERSION_CODE_CHANGE
变更 ID:145147528
默认状态:对于以 Android 10(API 级别 29)或更高版本为目标平台的应用处于启用状态。
检查 SmsManager.sendResolverResult()
方法的 SDK 版本。
GWP_ASAN
变更 ID:135634846
默认状态:对于所有应用处于停用状态。
在应用中启用采样原生内存错误检测。
如需详细了解此变更,请参阅 GWP-ASan 指南。
HIDE_MAXTARGETSDK_P_HIDDEN_APIS
变更 ID:149997251
默认状态:对于以 Android 10(API 级别 29)或更高版本为目标平台的应用处于启用状态。
对于以 Android 10(API 级别 29)或更高版本为目标平台的应用,移除了对 Android 10(API 级别 29)的 max-target-p
(greylist-max-p
) 列表中所有非 SDK 接口的访问权限。
HIDE_MAXTARGETSDK_Q_HIDDEN_APIS
变更 ID:149994052
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11(API 级别 30)或更高版本为目标平台的应用,移除了对 Android 11(API 级别 30)的 max-target-q
(greylist-max-q
) 列表中所有非 SDK 接口的访问权限。
如需详细了解此变更,请参阅 Android 11 中现在被屏蔽的非 SDK 接口。
LISTEN_CODE_CHANGE
变更 ID:147600208
默认状态:对于以 Android 10(API 级别 29)或更高版本为目标平台的应用处于启用状态。
检查 TelephonyManager.listen(PhoneStateListener,
int)
的 SDK 版本。
MISSING_APP_TAG
变更 ID:150776642
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,如果应用的清单文件缺少 application
或 instrumentation
标记,系统现在会抛出错误。
NATIVE_HEAP_POINTER_TAGGING
变更 ID:135754954
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,现在原生堆分配在最高有效字节中有一个非零标记。
如需了解详情,请参阅堆指针标记。
PHONE_STATE_LISTENER_LIMIT_CHANGE_ID
变更 ID:150880553
默认状态:对于所有应用处于启用状态。
对于以 Android 11 为目标平台的应用,现在对任何进程可通过 TelephonyManager.listen(PhoneStateListener, int)
注册的 PhoneStateListener
对象数量施加了限制。默认限制为 50,该值可能会因远程设备配置更新而发生变化。当违规进程试图注册过多的监听器时,TelephonyManager.listen(PhoneStateListener, int)
会抛出 IllegalStateException
,从而强制执行此限制。
PREVENT_META_REFLECTION_BLACKLIST_ACCESS
变更 ID:142365358
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
以 Android 11 为目标平台的应用不能再使用额外的反射层访问受限制的非 SDK 接口。
PROCESS_CAPABILITY_CHANGE_ID
变更 ID:136274596
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,现在可以使用 Context.BIND_INCLUDE_CAPABILITIES
标记将正在使用的功能从客户端进程传递到绑定服务。
REMOVE_ANDROID_TEST_BASE
变更 ID:133396946
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的应用,已将 android.test.base
库移除,前提是应用不依赖于 android.test.runner
(因为它依赖于 android.test.base
库中的类)。
REQUEST_ACCESSIBILITY_BUTTON_CHANGE
变更 ID:136293963
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
对于以 Android 11 为目标平台的无障碍服务,现在必须在无障碍服务元数据文件中指定 FLAG_REQUEST_ACCESSIBILITY_BUTTON
标记。否则,该标记会被忽略。
如需详细了解此变更,请参阅在元数据文件中声明“无障碍”按钮使用情况。
RESOURCES_ARSC_COMPRESSED
变更 ID:132742131
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
如果以 Android 11(API 级别 30)为目标平台的应用包含压缩的 resources.arsc
文件或者如果此文件未按 4 字节边界对齐,应用将无法安装。
如需详细了解此变更,请参阅压缩的资源文件。
RESTRICT_STORAGE_ACCESS_FRAMEWORK
变更 ID:141600225
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
如果您的应用以 Android 11 为目标平台并使用存储访问框架 (SAF),您就无法再使用 ACTION_OPEN_DOCUMENT
和 ACTION_OPEN_DOCUMENT_TREE
intent 操作访问某些目录。如需详细了解这些变更,请转到介绍 Android 11 中与存储相关的隐私权更新的页面,请参阅文档访问限制部分。
SELINUX_LATEST_CHANGES
变更 ID:143539591
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
此变更会控制应用对 untrusted_app_R-targetSDk SELinux 域的访问。这是兼容性框架的其中一项基础变更,可让应用在不更改其 targetSDKVersion
的情况下,切换受 targetSdkVersion
控制的其他变更的状态。因此,对于以 Android 11 为目标平台的应用,您不应停用此变更,否则应用将无法运行。
此变更不会影响使用共享用户 ID 的应用。
THROW_SECURITY_EXCEPTIONS
变更 ID:147340954
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
在 Android 11 之前,SecurityException
只会因权限错误而被 setEnabled
API 抛出。在 Android 11 中,情况不再如此,SecurityException
可以因多种原因而被抛出,并且这些原因不会为调用方所知晓。
为了维持现有的 API 行为,如果不是以 Android 11 为目标平台的应用发生原来的权限失败或操作方强制执行失败,该异常会被强制转换为存在于 Android 11 之前的源代码中的 IllegalStateException
。
USE_SET_LOCATION_ENABLED
变更 ID:117835097
默认状态:对于以 Android 11(API 级别 30)或更高版本为目标平台的应用处于启用状态。
以 Android 11 为目标平台的管理应用不能再使用 DevicePolicyManager.setSecureSetting(ComponentName, String, String)
更改已弃用的 Settings.Secure.LOCATION_MODE
设置,而应改用 DevicePolicyManager.setLocationEnabled(ComponentName, boolean)
。