测试应用与 Android 11 的兼容性

Android 11 引入了新的工具,用于针对最新版平台中的行为变更测试和调试应用。这些工具属于新的兼容性框架的一部分,可让应用开发者单独开启和关闭各项变更。有了这种灵活性,您可以关闭单项变更,然后继续针对平台中的其他变更测试应用;也可以每次单独针对一项行为变更测试应用。

不管是影响所有应用的行为变更还是只影响以 Android 11 为目标平台的应用的行为变更,您都可以随意开启或关闭。这还只是让您抢先体验一下这项新功能,所以请向我们提供反馈,告知我们您遇到的任何问题、您对进一步的增强功能有何想法,或者您有其他什么意见。

欢迎您提供相关反馈!请填写这份简短的调查问卷,将您使用此功能的情况告知我们。特别是,请将受此功能影响的用例告知我们。

如何识别已启用的变更

您可以使用开发者选项、logcat 或 ADB 命令查看当前已启用的行为变更。

使用开发者选项识别已启用的变更

图 1. 开发者选项中的“应用兼容性变更”屏幕

您可以在设备的开发者选项中查看当前已启用的变更,并且可以开启/关闭这些变更。如需访问这些选项,请按以下步骤操作:

  1. 如果开发者选项尚未启用,请启用开发者选项
  2. 打开设备的“设置”应用,导航到系统 > 高级 > 开发者选项 > 应用兼容性变更
  3. 从列表中选择您的应用。

每项行为变更通常属于以下两种类别之一:

  • 影响在 Android 11 上运行的所有应用(无论应用的 targetSdkVersion 是什么)的变更。

    默认情况下,这些变更在兼容性框架中处于启用状态,并且会在界面的默认启用的应用兼容性变更部分列出。

  • 只会影响以Android 11 为目标平台的应用的变更。

    如果您的应用以 Android 11 为目标平台,默认情况下,这些变更在兼容性框架中处于启用状态,并且会在界面的已在 SDK 29 之后启用部分列出。

在图 1 中,您还会看到一个名为默认停用的应用兼容性变更部分。属于此部分的变更通常为实验性变更,这些变更一般会归入另外两个类别之一,除非在未来的开发者预览版或 Beta 版中将其移除。

使用 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 命令开启或关闭各项变更。由于开启或关闭变更可能会导致应用崩溃或停用重要的安全变更,因此对于何时可以切换变更的状态有一些限制

使用开发者选项开启或关闭变更

您可以使用开发者选项开启或关闭变更。如需找到开发者选项,请按以下步骤操作:

  1. 如果开发者选项尚未启用,请启用开发者选项
  2. 打开设备的“设置”应用,导航到系统 > 高级 > 开发者选项 > 应用兼容性变更
  3. 从列表中选择您的应用。
  4. 在变更列表中,找到想要开启或关闭的变更,然后点按相应的开关。

    可以开启或关闭的变更列表

使用 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 最新开发者预览版 build 中的兼容性框架中包含的各项行为变更。您可以结合使用此列表与开发者选项和 ADB 命令对应用进行测试和调试。

ADD_CONTENT_OBSERVER_FLAGS

变更 ID:150939131

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的应用,系统会提供一个包含整数 flags 参数的新的公共 API 重载 onChange(boolean, Uri, int)

对于使用包含整数 userId 参数的非 SDK onChange() 重载方法的应用,该新方法是一种公共 SDK 方法。

ADMIN_APP_PASSWORD_COMPLEXITY

变更 ID:123562444

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的管理应用,每当应用设置的密码要求与当前指定的密码质量不相符时,系统就会抛出错误。例如,当密码质量设置为 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED 时,应用将无法设置最小密码长度。在这种情况下,在尝试设置最小密码长度之前,应用应首先调用 setPasswordQuality() 方法,然后才能调用 setPasswordMinimumLength() 方法。

此外,如果以 Android 11 为目标平台的管理应用降低密码质量,任何不再适用的现有密码要求都会重置为其默认值。

APP_DATA_DIRECTORY_ISOLATION

变更 ID:143937733

默认状态:无法切换此变更的状态。它只由兼容性框架记录。

以 Android 11 为目标平台的应用不能再访问任何应用的私有数据目录中的文件,而不管其他应用的目标 SDK 版本是什么。

如需了解详情,请参阅访问私有目录

APN_READING_PERMISSION_CHANGE_ID

变更 ID:124107808

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的应用,现在必须具备 Manifest.permission.WRITE_APN_SETTINGS 权限才能访问 APN 数据库。

如需详细了解此变更,请参阅限制对 APN 数据库的读取访问

BACKGROUND_RATIONALE_CHANGE_ID

变更 ID:147316723

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

现在,应用每次在后台请求访问设备的位置信息时,都必须提供有效的理由。

如需详细了解此变更,请参阅有关如何在Android 11 中访问后台位置信息的指南,该指南介绍了 Android 11 中与位置信息相关的隐私权变更。

CALLBACK_ON_CLEAR_CHANGE

变更 ID:119147584

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

现在每次调用 Editor.clear 时,都会使用 null 键回调 OnSharedPreferenceChangeListener.onSharedPreferenceChanged

CALLBACK_ON_MORE_ERROR_CODE_CHANGE

变更 ID:130595455

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

错误代码现在针对 updateAvailableNetworks(List, Executor, Consumer)setPreferredOpportunisticDataSubscription(int, boolean, Executor, Consumer) 进行了扩展。

CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE

变更 ID:148180766

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

这是 startWatchingMode(String, String, AppOpsManager.OnOpChangedListener) 的细微行为变更。在进行此变更之前,系统会针对切换的操作回调。在进行此变更之后,系统会针对实际请求的操作回调;如果未指定操作,就会针对所有切换的操作回调。

CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID

变更 ID:136219221

默认状态:对于所有应用处于停用状态。

对于以 Android 11 为目标平台的应用,只有在清单文件中将 R.attr.foregroundServiceType 分别配置为 ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERAServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE 时,前台服务才会接收正在使用的摄像头和麦克风功能。在较低版本的 Android 系统中,前台服务会自动接收摄像头和麦克风功能。

CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK

变更 ID:128611929

默认状态:对于所有应用处于启用状态。

应用无法再在后台发布自定义消息框。但是,应用在后台仍然可以使用 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 级别“R”)或更高版本为目标平台的应用处于启用状态。

文本消息框现在由 SystemUI 呈现,而不是在应用内呈现。这样可防止应用规避对在后台发布自定义消息框的限制。

DEFAULT_SCOPED_STORAGE

变更 ID:149924527

默认状态:对于所有应用处于启用状态。

以 Android 11 为目标平台的所有应用现在都默认使用分区存储,并且不能再停用分区存储

不过,无论您应用的目标 SDK 版本和清单标记值是什么,您都可以在不使用分区存储的情况下测试应用,只需关闭此变更即可。

如需详细了解 Android 11 中分区存储的变更,请转到关于 Android 11 中行为变更的页面,参阅分区存储部分。

EMPTY_INTENT_ACTION_CATEGORY

变更 ID:151163173

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的应用,如果 intent 过滤器的 actioncategory 为空字符串,系统现在会抛出错误。Android 11 之前的平台中有一个错误,允许系统在这种情况下继续运行,而不抛出错误。请注意,这不包括相应属性为 null 或缺失的情况,因为在此类情况下始终都会抛出错误。

FILTER_APPLICATION_QUERY

变更 ID:135549675

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

应用现在需要先声明想要使用的软件包和 intent,然后才能获取有关设备上其他应用的详细信息。应用必须在其清单中使用 <queries> 标记进行声明。

如需详细了解如何在 Android 11 中查询安装的其他应用并与之交互,请参阅软件包可见性隐私权页面。

FORCE_ENABLE_SCOPED_STORAGE

变更 ID:值 - 132649864

默认状态:对于所有应用处于停用状态。

以 Android 11 为目标平台的所有应用现在都默认使用分区存储,并且不能再停用分区存储

但是,如果您的应用仍以 Android 10(API 级别 29)或更低版本为目标平台,无论应用的目标 SDK 版本和清单标记值是什么,您都可以在使用分区存储的情况下测试应用,只需开启此变更即可。

如需详细了解 Android 11 中分区存储的变更,请转到关于 Android 11 中行为变更的页面,参阅分区存储部分。

GET_DATA_CONNECTION_STATE_R_VERSION

变更 ID:148535736

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

检查 PreciseDataConnectionState#getDataConnectionState 的 SDK 版本。

GET_DATA_STATE_R_VERSION

变更 ID:148534348

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

检查 getDataState() 的 SDK 版本。

GET_PROVIDER_SECURITY_EXCEPTIONS

变更 ID:150935354

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用,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)受限制的灰名单中所有非 SDK 接口的访问权限。

HIDE_MAXTARGETSDK_Q_HIDDEN_APIS

变更 ID:149994052

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用,请移除对 Android 11(API 级别“R“)受限制的灰名单中所有非 SDK 接口的访问。

LISTEN_CODE_CHANGE

变更 ID:147600208

默认状态:对于以 Android 10(API 级别 29)或更高版本为目标平台的应用处于启用状态。

检查 listenForSubscriber(int, String, String, PhoneStateListener, int, boolean) 的 SDK 版本。

MISSING_APP_TAG

变更 ID:150776642

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的应用,如果应用的清单文件缺少 applicationinstrumentation 标记,系统现在会抛出错误。

NATIVE_HEAP_POINTER_TAGGING

变更 ID:135754954

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 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 级别“R”)或更高版本为目标平台的应用处于启用状态。

以 Android 11 为目标平台的应用不能再使用额外的反射层访问受限制的非 SDK 接口。

PROCESS_CAPABILITY_CHANGE_ID

变更 ID:136274596

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的应用,现在可以使用 Context.BIND_INCLUDE_CAPABILITIES 标记将正在使用的功能从客户端进程传递到绑定服务。

REMOVE_ANDROID_TEST_BASE

变更 ID:133396946

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的应用,已将 android.test.base 库移除,前提是应用不依赖于 android.test.runner(因为它依赖于 android.test.base 库中的类)。

REQUEST_ACCESSIBILITY_BUTTON_CHANGE

变更 ID:136293963

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

对于以 Android 11 为目标平台的无障碍服务,现在必须在无障碍服务元数据文件中指定 FLAG_REQUEST_ACCESSIBILITY_BUTTON 标记。否则,该标记会被忽略。

RESOURCES_ARSC_COMPRESSED

变更 ID:132742131

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

要安装的某个 APK 的 resources.arsc 处于压缩状态或在 4 字节边界上未对齐。无法进行内存映射的资源表会对系统施加过大的内存压力,并大大减慢 Resources 对象的构建速度。

RESTRICT_STORAGE_ACCESS_FRAMEWORK

变更 ID:141600225

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

如果您的应用以 Android 11 为目标平台并使用存储访问框架 (SAF),您就无法再使用 ACTION_OPEN_DOCUMENTACTION_OPEN_DOCUMENT_TREE intent 操作访问某些目录。如需详细了解这些变更,请转到介绍 Android 11 中与存储相关的隐私权更新的页面,参阅目录访问限制部分

SELINUX_LATEST_CHANGES

变更 ID:143539591

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

此变更会控制应用对 untrusted_app_R-targetSDk SELinux 域的访问。这是兼容性框架中的其中一项基础变更,该基础变更允许应用在不更改其 targetSDKVersion 的情况下,即可切换受 targetSdkVersion 控制的其他变更的状态。因此,对于以 Android 11 为目标平台的应用,您不应停用此变更,否则应用将无法运行。

此变更不会影响使用共享用户 ID 的应用。

THROW_SECURITY_EXCEPTIONS

变更 ID:147340954

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

在 Android 11 之前,SecurityException 只会因权限错误而被 setEnabled API(例如 setEnabled(String, boolean, UserHandle))抛出。在 Android 11 中,情况不再如此,SecurityException 可以因多种原因而被抛出,并且这些原因不会为调用方所知晓。

为了维持现有的 API 行为,如果不是以 Android 11 为目标平台的应用发生原来的权限失败或操作方强制执行失败,该异常会被强制转换为存在于 Android 11 之前的源代码中的 IllegalStateException

USE_SET_LOCATION_ENABLED

变更 ID:117835097

默认状态:对于以 Android 11(API 级别“R”)或更高版本为目标平台的应用处于启用状态。

以 Android 11 为目标平台的管理应用不能再使用 DevicePolicyManager.setSecureSetting(ComponentName, String, String) 更改已弃用的 Settings.Secure.LOCATION_MODE 设置,而应改用 DevicePolicyManager.setLocationEnabled(ComponentName, boolean)