相关文章推荐
仗义的夕阳  ·  valueerror: number of ...·  1 月前    · 
礼貌的高山  ·  ImageJ ...·  1 年前    · 
骑白马的饭卡  ·  C#.NET ...·  1 年前    · 

一、兼容性调试工具

Android 11开始引入了新的工具,可针对Android新平台中的行为变更进行测试和调试。这些工具是兼容性框架的一部分,该框架使得开发者可通过开发者选项或adb命令单独打开和关闭各项变更。藉此,可在最新android预览版中测试我们的app受到新平台及target api调整的影响,完成app对新平台的兼容适配。

使用adb命令打开或关闭变更,请运行以下命令之一:

adb shell am compat enable (CHANGE_ID|CHANGE_NAME) PACKAGE_NAME

adb shell am compat disable (CHANGE_ID|CHANGE_NAME) PACKAGE_NAME

可使用以下命令重置变更为默认状态,移除通过adb或开发者选项设置的覆盖更改:

adb shell am compat reset (CHANGE_ID|CHANGE_NAME) PACKAGE_NAME

具体说明及使用方法见:

https://developer.android.google.cn/guide/app-compatibility/test-debug

*注意:每当使用开发者选项或adb命令切换应用变更时,应用都会被杀死,以确保覆盖立即生效。

由于切换变更的开启或关闭可能导致应用崩溃或禁用重要的安全变更,为防止恶意使用兼容性框架,在何时切换变更会存在一些限制。是否可以切换变更,取决于变更的类型,应用是否可调试(app: debuggable )以及设备上运行的版本类型。

下表是限制情况:

二、行为变更

2.1、更安全的组件输出

以Android 12为目标平台的应用(target API 级别31),如果包含用 intent filters 修饰的 activities services broadcast receivers ,则必须为这些应用组件显式声明 android:exported 属性,表明是否支持其它应用调用当前组件。

谷歌官网特性介绍:

https://developer.android.com/about/versions/12/behavior-changes-12#exported

2)兼容性影响

如果您的应用包含使用intent filter但未声明android:exported的Activity,Service,broadcast receiver,开发过程中会提示以下警告消息,具体取决于您使用的Android Studio版本:

Android Studio 2020.3.1 Canary 11或更高版本

清单文件中将出现以下警告:

When using intent filters, please specify android:exported as well

当您尝试编译应用程序时,会生成以下错误消息:

Manifest merger failed : Apps targeting Android 12 and higher are required \

to specify an explicit value for android:exported when the corresponding \

component has an intent filter defined.

旧版Android Studio

如果您尝试安装该应用程序,Logcat将显示以下错误消息:

Installation did not succeed.

The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE

List of apks:

[0] '.../build/outputs/apk/debug/app-debug.apk'

Installation failed due to: 'null'

3)适配指导

以下代码段显示了一个包含intent filter且已针对Android 12正确配置的service示例,其余组件应该按照同样规则进行配置:

<service android:name="com.example.app.backgroundService" android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.START_BACKGROUND" />
    </intent-filter>
</service>

2.2、Notification trampolines 限制

当用户与通知交互时,某些应用程序会通过启动应用程序组件来响应通知点击,该组件最终会启动用户最终看到并与之交互的Activity。 此应用程序组件称为通知中介。

为了提高应用程序性能和用户体验,面向Android 12的应用程序无法从用作通知中介的服务或广播接收器启动Activity。

2)兼容性影响

如果应用Target API 级别是31或者更高,应用尝试从充当通知中介的服务或广播接收器启动Activity时,系统将阻止该Activity启动,并且在Logcat中显示以下消息:

Indirect notification activity start (trampoline) from PACKAGE_NAME, \

this should be avoided for performance reasons.

3)适配指导

如果您的应用从充当通知中介的服务或广播接收器启动Activity,请完成以下迁移步骤:

1 创建与用户点击通知后看到的Activity相关联的 PendingIntent 对象

2 将第一步创建的PendingIntent对象用作构建通知的一部分

另外,如何识别一个组件是通知中介,测试方法见:

https://developer.android.com/about/versions/12/behavior-changes-12#notification-trampolines

2.3、ACTION_CLOSE_SYSTEM_DIALOGS 弃用

为了在应用程序和系统进行交互时,改善用户控制体验,从Android 12开始弃用 ACTION_CLOSE_SYSTEM_DIALOGS intent的操作。

2)兼容性影响

当应用尝试调用包含此操作的intent时,系统会根据应用的目标SDK版本执行以下操作 :

如果应用的targetSdk版本是针对Android 12的,则会抛出SecurityException;

如果应用的targetSdk版本是针对Android 11(API级别为30)或者更低版本的,该intent不会执行,但会在logcat中显示如下信息:

E ActivityTaskManager Permission Denial: \

android.intent.action.CLOSE_SYSTEM_DIALOGS broadcast from \

com.package.name requires

android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, \

dropping broadcast.

3)适配指导

对于使用ACTION_CLOSE_SYSTEM_DIALOGS广播的app应该注意该变更。 platform app可配置以下权限,进行豁免:

Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS

另外,有极少数情景,应用仍然可以在android 12上关闭系统弹框,详情见:

https://developer.android.com/about/versions/12/behavior-changes-all#close-system-dialogs

2.4、Foreground service 启动限制

为完善隐私保护,加强安全功能,android 12对后台应用有进一步的限制。除少数特殊情况外,针对Android 12的应用程序,无法在后台运行时启动前台服务。

参考Google官网:

https://developer.android.com/about/versions/12/foreground-services#cases-fgs-background-starts-allowed

2)兼容性影响

如果应用的targetSdk版本是针对Android 12的,应用处于后台,除开特殊情况外,调用 startForegroundService ,系统将引发IllegalStateException。

以下情况,即使您的应用程序在后台运行,您的应用程序也可以启动前台服务。详情见

https://developer.android.com/about/versions/12/foreground-services#cases-fgs-background-starts-allowed

3)适配指导

如果您的应用受此更改影响,建议您迁移到使用 WorkManager 。Android 12 beta版发布时,WorkManager将成为启动优先级更高的后台任务的推荐解决方案。

从WorkManager 2.7.0开始,您的应用程序可以调用 setExpedited() 来声明Worker应该使用 expedited job 。当在Android 12上运行时,此新API会用于加急任务,并且该API使用Android早期版本上的前台服务以提供向后兼容性。

为了促进开发人员在他们的应用程序中请求加急任务时保持谨慎,并支持耗时任务的运行能力,不建议使用 CoroutineWorker.setForeground() ListenableWorker.setForegroundAsync() 方法。特别是,在运行Android 12的设备上,尝试调用ListenableWorker.setForegroundAsync()会导致IllegalStateException。建议开发人员改用setExpedited()替代。

要查看有关WorkManager 2.7.0如何使用加急任务的完整示例,请查看GitHub上的 WorkManagerSample

Platfom app也可以使用如下权限对此特性规避:

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

2.5、PendingIntent mutability

如果您的应用程序以Android 12为目标平台,则必须指定应用创建的每个PendingIntent对象的可变性。此附加要求可提高应用程序的安全性。

2)兼容性影响

如果您的应用尝试在未设置任何可变性标志的情况下创建PendingIntent对象,则系统将引发IllegalArgumentException,并且在Logcat中显示以下消息:

PACKAGE_NAME: Targeting S+ (version 10000 and above) requires that one of \

FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \

some functionality depends on the PendingIntent being mutable, e.g. if \

it needs to be used with inline replies or bubbles.

3)适配指导

需要声明给定的PendingIntent对象是可变的或不可变的,请分别使用 PendingIntent.FLAG_MUTABLE 或者 PendingIntent.FLAG_IMMUTABLE 标志

该变更详情见官网:

https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability

2.6、PackageManager setInstallerPackageName(...) 权限需求

PackageManager中存在一个接口 setInstallerPackageName(@NonNull String targetPackage, @Nullable String installerPackageName) ,用于修改目标应用包的安装渠道。

如果应用程序目标平台是Android 11及以上,当targetPackage的installer package 还未进行设定时,调用此接口,必须要求调用方拥有INSTALL_PACKAGES permission权限。

2)兼容性影响

该情境如果权限不满足,系统会根据应用的目标SDK版本执行以下操作 :

如果应用的targetSdk版本是针对Android 11及以上,则会抛出SecurityException;

如果应用的targetSdk版本是针对Android 10(API级别为29)或者更低版本,则以静默方式失败。

3)适配指导
为保证setInstallerPackageName(...)接口的功能正常,需要在应用程序AndroidManifest.xml文件中配置INSTALL_PACKAGES permission:
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />

*注意,该权限仅支持system app使用。

2.7、GpsStatus API限制

GPS是英文Global Positioning System(全球定位系统)的简称。GNSS全球导航卫星系统(Global Navigation Satellite System),它是泛指所有的卫星导航系统,包括全球的、区域的和增强的。Android 7.0 以后官方推荐使用GNSS。

目标平台是Android 12及以上的应用程序,所用到的GpsStatus API必须要用GnssStates API替换。

2)兼容性影响

需要进行替换的public GpsStatus API接口如下,否则系统会引发异常,导致应用程序崩溃。

getGpsStatus(GpsStatus status)

addGpsStatusListener(GpsStatus.Listener listener)

removeGpsStatusListener(GpsStatus.Listener listener)

3)适配指导

如果应用的targetSdk版本是针对Android 12及以上,为保证功能的正常,请使用GnssStatus.Callback对GpsStatus.Listener进行替代:

registerGnssStatusCallback(android.location.GnssStatus.Callback)

unregisterGnssStatusCallback(android.location.GnssStatus.Callback)

可根据应用功能需求,选择合适API进行替换,详情请参考:

https://developer.android.com/reference/android/location/LocationManager

调用样例如下:

记得不要遗忘反注册:

2.8、PendingIntent.FLAG_IMMUTABLE与Location API冲突

以Android 12为目标平台的应用(target API 级别31),固定不变的PendingIntent传给location apis会报IllegalArgumentException异常。

2)兼容性影响

可能受影响的public API接口如下:

requestSingleUpdate (String provider, PendingIntent pendingIntent)

requestSingleUpdate (Criteria criteria, PendingIntent pendingIntent)

requestLocationUpdates (LocationRequest locationRequest,

PendingIntent pendingIntent)

requestLocationUpdates (String provider, LocationRequest locationRequest,

PendingIntent pendingIntent)

requestLocationUpdates (long minTimeMs, float minDistanceM, Criteria criteria,

PendingIntent pendingIntent)

requestLocationUpdates (String provider, long minTimeMs, float minDistanceM,

PendingIntent pendingIntent)

addProximityAlert (double latitude, double longitude, float radius,

long expiration, PendingIntent pendingIntent)

3)适配指导

应用调用以上API接口,所构建的PendingIntent只能带入可变性标志:

PendingIntent.FLAG_MUTABLE 禁止 PendingIntent.FLAG_IMMUTABLE

2.9、PendingIntent与 LocationRequest system APIs冲突

目标平台是Android 12及以上的应用程序,LocationRequest system APIs不能与PendingIntent位置请求一起使用。

2)兼容性影响

如发生冲突,系统会引发安全异常。可能受影响的public API接口如下:

requestLocationUpdates (LocationRequest locationRequest,

PendingIntent pendingIntent)

requestLocationUpdates (String provider, LocationRequest locationRequest,

PendingIntent pendingIntent)

3)适配指导

应用调用以上API接口,所构建的LocationRequest 禁止调用@SystemApi进行修饰,涉及到的接口如下:

LocationRequest$Builder .setLowPower(boolean)

LocationRequest .setLowPowerMode(boolean)

LocationRequest$Builder .setLocationSettingsIgnored(boolean)

LocationRequest .setLocationSettingsIgnored(boolean)

LocationRequest$Builder .setHiddenFromAppOps(boolean)

LocationRequest .setHideFromAppOps(boolean)

LocationRequest$Builder .setWorkSource(WorkSource)

LocationRequest .setWorkSource(WorkSource)

由于@SystemApi仅允许system app调用,所以该变更需要system app注意适配。

2.10、不信任触摸事件的阻塞

为了提升系统的安全性和用户体验,当叠加层以不安全的方式覆盖app,Android 12 会阻止app消费触摸事件。换句话说,除了少数例外,系统会阻止通过某些窗口的触摸事件。

例外情况如下:

https://developer.android.com/about/versions/12/behavior-changes-all#untrusted-touch-events-exceptions

2)兼容性影响

此变更会影响选择让触摸通过其窗口(例如使用 FLAG_NOT_TOUCHABLE 标志)的应用。包括但不限于以下示例:

需要SYSTEM_ALERT_WINDOW权限的叠加层,例如使用TYPE_APPLICATION_OVERLAY并使用FLAG_NOT_TOUCHABLE标志的窗口。

使用FLAG_NOT_TOUCHABLE标志的Activity窗口。

Toast消息。

3)适配指导

应用需要check允许触摸事件通过窗口的场景及功能正常。还可以通过以下log的输出检测触摸事件被系统Block的情景:

对于可信任的窗口,触摸事件是不会被阻塞的,以下type的窗口为可信任的,可以参考:

TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY

TYPE_INPUT_METHOD

TYPE_INPUT_METHOD_DIALOG

TYPE_MAGNIFICATION_OVERLAY

TYPE_STATUS_BAR

TYPE_NOTIFICATION_SHADE

TYPE_NAVIGATION_BAR

TYPE_NAVIGATION_BAR_PANEL

TYPE_SECURE_SYSTEM_OVERLAY

TYPE_DOCK_DIVIDER

TYPE_ACCESSIBILITY_OVERLAY

TYPE_INPUT_CONSUMER

TYPE_VOICE_INTERACTION

以下实例构建了一个overlay view,当跟app进行交互时,触摸事件被正常下传,属于例外情况的一个场景;当应用置于后台,该覆盖层会置于launcher之上,此时覆盖层的触摸事件会受到变更的影响。

2.11、Nested intent 启动

Nested intent是在其他intent中作为附加数据传递的intent。如果您的应用程序同时执行以下两个操作,则会发生 StrictMode 违规:

您的应用程序从获取的intent内容中解析到一个nested intent。

您的应用程序使用该nested intent启动app组件,例如将intent传递给startActivity(),startService()或bindService()。

为了提高平台安全性,Android 12提供了一种调试功能,可在应用执行不安全的嵌套意图(nested intent)启动时发出警告。

2)兼容性影响

谷歌提供以下配置方法,可检测到应用程序中不安全的nested intent启动。

在配置VmPolicy时调用 detectUnsafeIntentLaunch() ,如以下代码片段所示:

protected void onCreate() {
       StrictMode.setVmPolicy(new VmPolicy.Builder()
       // Other StrictMode checks that you've previously added.
       // ...
       .detectUnsafeIntentLaunch()
       .penaltyLog()
       // Consider also adding penaltyDeath()
       .build());

对于Android 12为目标的应用,如果在其VmPolicy定义中使用了detectAll()方法,则会自动调用detectUnsafeIntentLaunch()方法。

如果检测到违反StrictMode的行为,则可能要停止执行应用程序以保护潜在的敏感信息。

3)适配指导

您的app可能会启动nested intent,以在app内部组件之间导航,或代表另一个应用执行操作。为了最大程度地减少在任何情况下遇到StrictMode违规的概率,请执行以下操作:

内部启动nested intent:配置android:export = “false”,确保这些组件不是对外导出的,以activity组件为例:

<activity android:name=".MainActivity" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

跨应用启动nested intent:使用PendingIntent代替nested intent。这样,App1发送附加了Pendingintent的intent到App2时,App2将其中的PendingIntent解析出来,由于PendingIntent中包含的是App1的context,再启动PendingIntent会以App1的上下文启动PendingIntent代表的intent。此配置允许拉起App1的任何组件,包括未导出的组件,也不会在中间被恶意劫持,暴露App2不对外的敏感信息界面。示意代码如下:

2.12、WebView中的现代SameSite Cookie行为

Android的WebView组件基于Chromium,Chromium是为Google Chrome浏览器提供支持的开源项目。去年,Chromium对第三方Cookie的处理方式进行了变更,以提供更高的安全性和隐私性,并为用户提供更高的透明度和可控性。这些变更已向广大Chrome用户推出,并且从Android 12开始,这些变更已应用于WebView。

2)兼容性影响

Cookie的SameSite属性决定了它是否可以与任何请求一起发送,或仅与相同站点的请求一起发送。Android 12中的WebView的基础版本(版本89.0.4385.0)包括以下隐私保护变更,这些变更改进了第三方Cookie的默认处理,并有助于防止意外的跨站点共享。

没有SameSite属性的Cookie被视为SameSite = Lax。

配置有SameSite = None的Cookie还必须指定Secure属性,这意味着它们需要安全的上下文,并应通过HTTPS发送。

站点的HTTP和HTTPS版本之间的链接现在被视为跨站点请求,因此,除非将cookie适当地标记为SameSite = None,Secure,否则cookie不被发送。

对于开发者,一般建议是在关键用户流中标识跨站点cookie的依赖性,并确保在需要时使用适当的值对SameSite属性进行显式设置。您必须明确指定cookie允许跨站点或同一站点导航中从HTTP到HTTPS的访问。

有关这些变更的Web开发人员的完整指南,请参阅SameSite Cookies Explained和 Schemeful SameSite.

3)适配指导

如果您的应用程序使用WebView,或者如果您使用Cookie管理网站或服务,则建议您在Android 12 WebView测试网络流。如果发现问题,则可能需要更新cookie以支持新的SameSite行为。

观察登录和嵌入内容中的问题,以及登录流程,购买流程和其他身份验证流程,在这些流程中,用户从不安全的页面开始,然后过渡到安全的页面。

要使用WebView测试app,必须通过完成以下任一步骤来为要测试的应用程序启用新的SameSite行为:

在测试设备上手动启用SameSite行为,通过在 WebView devtools中切换UI标志webview-enable-modern-cookie-same-site

这种方法,使得您可以在Android 5.0(API级别21)或更高版本(包括Android 12)和WebView 89.0.4385.0或更高版本的任何设备上进行测试。

修改targetSdkVersion将您的应用编译为目标Android 12的应用程序。

如果使用这种方法,则必须使用运行Android 12和WebView 89.0.4385.0或更高版本的设备。

2.13、自定义通知的模板化

Android 12会更改完全自定义通知的外观和行为。以前,自定义通知能够使用整个通知区域并支持自己的布局和样式。该模式反而可能会使用户感到困惑或在不同设备上引起布局兼容性问题。

对于定位到Android 12的应用,带有自定义内容视图的通知将不再使用完整的通知区域,系统会采用标准模板。此模板可确保自定义通知在所有状态下都与其他通知具有相同的修饰,例如通知的图标和扩展功能(处于折叠状态),以及通知的图标,应用程序名称和折叠功能(处于展开状态)。此行为与Notification.DecoratedCustomViewStyle的行为几乎相同。

经过这种方式,Android 12使所有通知在视觉上保持统一并易于辨认,以及可见熟悉的扩展方式。

2)兼容性影响

Android 12中的变更会影响定义了Notification.Style的子类,以及使用了如下Notification.Builder方法的应用:

setCustomContentView(RemoteViews)

setCustomBigContentView(RemoteViews)

setCustomHeadsUpContentView(RemoteViews)

3)适配指导

如果您的应用使用的是完全自定义的通知,建议您尽快使用新模板进行测试。

1. 启用自定义通知变更:

A. 将应用程序的targetSdkVersion更改为S以启用新行为

B. 重新编译

C. 在运行Android 12的设备或模拟器上安装您的应用。

2. 测试所有使用自定义视图的通知,确保它们在形状上看起来像您期望的那样。在测试时,请考虑以下因素并进行必要的调整:

自定义视图的尺寸已更改。通常,自定义通知的高度要小于以前。在折叠状态下,自定义内容的最大高度已从106dp降低到48dp。同样,水平空间也更少。

所有通知均可针对以Android 12为目标的应用进行扩展。通常,这意味着,如果您使用setCustomContentView,则还需要使用setCustomBigContentView来确保折叠状态和展开状态一致。

为了确保”Heads Up”状态看起来像您期望的那样,请不要忘记将通知频道的重要性提高到“高”(屏幕弹出)。

自定义通知的实例如下:

2.14、传感器的数据刷新率限制

为了保护用户的潜在敏感信息,如果您的应用针对Android 12,则系统会将来自某些运动传感器和位置传感器的数据刷新率限制为200 Hz。此数据包括由设备的加速度,陀螺仪和磁力传感器记录的值。

2)兼容性影响

如果您的应用程序以Android 12为目标并且需要以更高的速率收集运动传感器数据,则必须声明HIGH_SAMPLING_RATE_SENSORS权限。 否则,如果您的应用尝试在不声明此权限的情况下以更高的速率收集运动传感器数据,则会发生SecurityException。

可能受影响的public API接口如下:

SensorManager.registerListener(SensorEventListener listener, Sensor sensor,int samplingPeriodUs)

SensorManager.registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs, int maxReportLatencyUs)

SensorManager.registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs, Handler handler)

SensorManager.registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs, int maxReportLatencyUs, Handler handler)

SensorManager.registerListener(SensorListener listener, int sensors)

SensorManager.registerListener(SensorListener listener, int sensors, int rate)

SensorManager.requestTriggerSensor(TriggerEventListener listener, Sensor sensor)

SensorDirectChannel.configure(Sensor sensor, @RateLevel int rateLevel)

3)适配指导

应用的清单文件中配置HIGH_SAMPLING_RATE_SENSORS权限。

使用实例如下:

实例如下:

2.15、MediaProvider对私有文件的修改限制

对于以 Android 12 及更高版本为目标平台的应用,无法使用media provider插入或更新私有文件。

2)兼容性影响

如果应用Target API 级别是31或者更高,应用将会默认支持ENABLE_CHECK_FOR_PRIVATE_FILES,此时,系统将不允许将保存在/sdcard/Android/data或者/sdcard/Android/obb中的文件路径添加到mediaprovider数据库中。换句话说,应用程序专有目录的文件无法添加到公共媒体收藏中,无法被media provider扫描并share出去。

3)适配指导

当应用通过以下接口或者其它组合形式获取专有目录(/sdcard/Android/data或者/sdcard/Android/obb),来保存媒体资源,这些文件将不会被mediaScan扫描到,也就无法将这些文件分享给其他应用使用。建议将需要共享的文件保存到其他路径以避免功能的异常。

Context.getExternalCacheDir()

Context.getExternalFileDir(String type)

Context.getExternalFileDirs()

Context.getObbDir()

Context.getObbDirs()

2.16、REQUIRE_EXACT_ALARM_PERMISSION

如果应用Target API 级别是31或者更高,如果要使用以下接口,必须配置新的权限Manifest.permission.SCHEDULE_EXACT_ALARM。

setExactAndAllowWhileIdle(int,long,PendingIntent)

setAlarmClock(AlarmClockInfo,PendingIntent)

2)兼容性影响

可能受影响的public API接口如下:

AlarmManager.setExactAndAllowWhileIdle( int , long , PendingIntent )

AlarmManager.setExact( int , long , PendingIntent )

AlarmManager.setExact( int , long , String , OnAlarmListener , Handler )

AlarmManager.setAlarmClock( AlarmClockInfo , PendingIntent )

面向android 12的应用,有调用这些接口,如果没有配置Manifest.permission.SCHEDULE_EXACT_ALARM权限,将会抛出SecurityException异常。

3)适配指导

在应用的清单文件中配置SCHEDULE_EXACT_ALARM权限。

实例代码如下:

2.17、更新的非SDK接口限制

Android 12包括了基于Android开发人员的协作以及最新的内部测试的受限制的非SDK接口的更新列表。只要有可能,在限制非SDK接口之前,请确保可以使用公共替代方案。

2)兼容性影响

如果您的应用程序不是面向Android 12,则其中的一些变更可能不会立即对您产生影响。但是,尽管您目前可以使用某些非SDK接口(取决于应用程序的目标API级别),但使用任何非SDK方法或字段始终会带来破坏应用程序的高风险。

3)适配指导

non-SDK接口介绍

https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces

Android 12 限制非SDK

https://dl.google.com/developers/android/sc/non-sdk/hiddenapi-flags.csv

1 如果不确定您的应用程序是否使用非SDK接口,可以测试您的应用程序以找出答案。方法如下:

https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces#test-for-non-sdk

2 如果您的应用程序依赖于非SDK接口,则应开始计划向SDK替代方案的迁移。不过,我们了解到某些应用程序具有使用非SDK界面的有效用例。替代的API会在名单中以注释的形式给出。

3 如果您找不到在应用程序功能中使用非SDK接口的替代方法,则应请求新的公共API。

https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces#feature-request

2.18、RenderScript的弃用

从Android 12开始,不推荐使用RenderScript API。他们将继续发挥作用,但是我们希望设备和组件制造商将随着时间的推移停止提供硬件加速支持。为了充分利用GPU加速,我们建议从RenderScript迁移。

2)兼容性影响

可能影响性能,但暂无兼容性风险,后续会存在高风险。

3)适配指导

为了充分利用GPU加速,我们建议您的程序从内部函数迁移到独立的toolkit,从脚本迁移到Vulkan。

1 从内部函数迁移

尽管RenderScript内部函数在RenderScript弃用后将继续起作用,但它们只能在CPU上执行,而不在GPU上执行。

如果您的应用程序使用内部函数,则可以使用独立的替换库。测试表明,它比使用现有的RenderScript CPU实现要快。

该工具包包含以下功能:

直方图和点柱图

查找表(LUT)和LUT 3D

YUV到RGB

有关详细信息和限制,请参阅工具箱的 README.mdToolkit.kt文件。

执行以下步骤下载,添加和使用该库:

1) 从GitHub下载project

2) 找到并构建renderscript-toolkit模块

注意:如果您想在GPU上运行内部函数,请参阅从脚本迁移中描述的Vulkan中编码模糊和颜色矩阵的示例。

3) 通过修改应用程序的build.gradle文件,将该库添加到您的Android Studio项目中

4) 调用工具箱的适当方法

示例:从ScriptIntrinsicBlur函数迁移

      替换ScriptIntrinsicBlur函数:

      模糊位图,请调用Toolkit.blur

模糊由字节数组表示的图像,请指定宽度,高度和每个像素的字节数

注意:由于该库将继续发展,因此请查看工具箱文档以获取最新指南。

以Android 12(API级别31)及更高版本为目标时,请考虑使用RenderEffect类。

2 从脚本迁移

为充分利用 GPU 加速功能,我们建议将 RenderScript 脚本迁移到跨平台 Vulkan API。即使您不迁移,脚本也会继续运行,但这些脚本可能会针对CPU(而非 GPU)执行,具体取决于驱动程序是否可用。

为了更好地了解如何迁移功能,请查看示例应用。该示例演示了如何使用 RenderScript 对位图进行模糊处理并执行颜色矩阵转换,以及如何使用Vulkan 编写等效的代码。

如果您的应用需要支持一系列版本,请为搭载 Android 9(API 级别 28)及更低版本的设备使用RenderScript,为 Android 10(API 级别 29)及更高版本使用 Vulkan。

Vulkan不提供 Kotlin API 和 Java API,因此不存在从 RenderScript 到 Vulkan 的直接映射。如需通过 Kotlin 或 Java 访问此代码,您需要使用 NDK 编写 Vulkan 代码,并创建 JNI 函数。

详细的适配说明请参考以下:

https://developer.android.com/guide/topics/renderscript/migrate#scripts

2.19、Display API 的弃用

Android设备正以多种不同的形式出现,例如大屏幕,平板电脑和可折叠设备。为了适当地为每个设备呈现内容,您的应用需要确定屏幕或显示尺寸。随着时间的发展,Android提供了不同的API来检索此信息。

2)兼容性影响

在Android 11中,我们引入了WindowMetrics API并弃用了以下方法:

Display.getSize()

Display.getMetrics()

在Android 12中,我们继续建议您使用WindowMetrics,并且不建议使用以下方法:

Display.getRealSize()

Display.getRealMetrics()

getRealSize(),一般情况下返回的是DisplayArea的大小,而不再是屏幕的大小了。

3)适配指导

应用应使用WindowMetrics API来查询其窗口的边界,或使用Configuration.densityDpi来查询当前的密度。

请注意,Jetpack WindowManager库包括一个支持Android 4.0.1(API级别14)及更高版本的WindowMetrics类。

以下是一些使用WindowMetrics的示例。

首先,请确保您的应用Activity可以全屏调整大小。

Activity应该依赖于Activity上下文中的WindowMetrics来进行任何与UI相关的工作,尤其是WindowManager.getCurrentWindowMetrics()。

如果您的应用创建了MediaProjection,则边界的大小必须正确,因为投影需要捕获显示内容。如果应用程序全屏可调整大小,则Activity上下文将返回正确的范围。

如果应用程序不能完全调整大小,则它必须从WindowContext实例查询范围,并使用WindowManager.getMaximumWindowMetrics() 检索应用程序可用的最大显示区域的WindowMetrics。

*注意:任何使用MediaProjection的库也应遵循此建议,并为应用程序窗口查询适当的WindowMetrics。

2.20、单应用的兼容性Overrides

Android 12 兼容性框架,引入了新的注解字段@Overridable,与原有的注解字段@ChangeId配合使用,支持对非调试app的changeid对应的兼容性有效值进行重写。

2)兼容性影响

有助于开发人员定位问题,并提供解决问题的途径。

3)适配指导

以调整应用显示宽高比例的兼容性为例,进行适配说明,涉及到的兼容性id如下,这些change都带有@Overridable标志,允许重写。

市场上存在许多应用,未对更大的屏幕和新的外形进行优化,手动测试可观察到的一些问题:

没声明支持调整大小的应用程序,实际上在调整大小过程中表现良好。

延伸至接近正方形的宽高比时出现UX显示问题的应用,实际可以以更大的宽高比显示。

通过对应用的兼容性进行重写,在应用开发者适配好之前,我们可以改善大型尺寸的体验。

android.app.compat.CompatChanges#setPackageOverride(String packageName,Map <Long,PackageOverride> overrides) 允许具有以下权限的应用设置给定应用包的重写值:

<permission android:name “android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD”

android:protectionLevel =“ signature | privileged” />

●android.app.compat.PackageOverride包含一个布尔值(表明启用还是禁用该变更)以及一个APK版本范围(表明重写生效条件)。

●在com.android.server.compat.CompatConfig#create中,/product/etc/appcompat/compat_framework_overrides.xml进行变更,以使得重写的特性生效。

2.21、Web intent解析

为了提供更简化的Web链接用户体验,如果Web Intent包含未验证的域,Android 12会选择在用户的默认浏览器中打开。您的应用可以使用以下一种方法获得域的批准:

1 使用Android App Links验证域

Android App Links(可在Android 8.0及更高版本中使用)使用Digital Asset Links API将特定应用与web域相关联。通过这种关联,系统认为该应用程序已获得网站的批准,可以自动打开该域的链接。

2 让用户在系统设置中手动将您的应用与该域相关联

2)兼容性影响

Android 12开始,Web意图过滤器必须声明CATEGORY_BROWSABLEcategory,以便给定的Web意图解析为应用程序中的Activity。

无论应用是否针对Android 12,系统都支持手动调用域验证。

面向Android 12的应用程序,系统对验证Android App Links的方式进行了几处更改。这些变更提高了应用程序链接体验的可靠性,并为应用程序开发人员和最终用户提供了更多控制。

3)适配指导

1 使用Android App Links验证域

如果应用以Android 12为目标并且依赖Android App Link验证来打开应用程序中的Web链接,请更新Android App Links声明以支持更改的验证过程。域验证过程需要Internet连接,可能需要一些时间才能完成。为帮助提高流程效率,仅当该域位于特定格式的<intent-filter>元素内时,系统才会验证针对Android 12的应用程序的域。<intent-filter>元素必须包含以下片段中显示的actions,categories和schemes:

手动调用域验证来测试声明的可靠性。详细操作过程见官网说明:

https://developer.android.com/about/versions/12/web-intent-resolution#manually-invoke-domain-verification

2 请求用户将应用与域相关联

在提示用户之前,请检查您的应用程序是否是在<intent-filter>元素中定义的域的默认处理程序。 您可以使用DomainVerificationManager API查询批准状态:

在您请求域批准之前,请为用户提供一些context 。例如,您可能会向他们显示一个初始屏幕,对话框或类似的UI元素,向用户解释为什么您的应用程序应成为特定域的默认处理程序。

在用户了解您的应用要求他们执行的操作后,发出请求。为此,请调用一个包含ACTION_APP_OPEN_BY_DEFAULT_SETTINGS意向操作的意向,以及与目标应用程序匹配的数据字符串package:com.example.pkg的意向,如以下代码片段所示:

调用该意图时,用户会看到一个Open by default的设置界面。此界面包含一个Open supported links单选按钮,如下左图所示。

当用户打开Open supported links时,将在Links to open in this app部分下显示一组复选框, 用户可以从中选择要与应用程序关联的域。 他们还可以选择Add link添加域,如下右图所示。当用户在添加的域中选择链接以后,该链接会在您的应用程序中自动打开。

注意:在给定的设备上,一次只能将一个应用程序与特定域关联。如果已经为该域验证了另一个应用程序,则用户必须先将其他应用程序与该域断开关联,然后才能将您的应用程序与该域相关联。

2.22、无障碍API规范

Android 12中,Google增加了对三方应用无障碍服务的严格管控,因为很多三方应用无障碍服务并不是真正为无障碍人群服务的,只是利用无障碍服务在非法获取用户信息。为了管控这些行为,Google在新一台平台中新增了Flag AccessibilityServiceInfo#isAccessibilityTool,用于表示当前无障碍服务是否是一个无障碍工具;如果没有配置isAccessibilityTool配置,该无障碍服务启动的时会显示前台通知,告知用于当前无障碍服务可能会访问用户数据,并提供选项卸载该无障碍服务。

对于声明了该Flag的应用,被系统信任还需要满足以下条件之一:

a系统应用(ApplicationInfo.FLAG_SYSTEM)

b非系统应用,则必须来源于受信任的安装源

受信任的安装源必须是系统app,并且也要满足以下两个条件之一:

a如果系统无障碍信任安装源的名单为空,安装源的应用不是当前系统的默认安装器

b如果系统无障碍信任安装源的名单不为空,安装源的应用必须要在该名单中

2)兼容性影响

如果应用处于以下条件:

1 没有在无障碍服务配置中声明android:isAccessibilityTool="true"

2 声明了android:isAccessibilityTool="true"同时来源于不受信任的安装源

那么应用在Android 12的版本上运行时,会显示通知信息提示用户该无障碍服务正在运行,并提供选项卸载该应用。

3)适配指导

系统应用(ApplicationInfo.FLAG_SYSTEM)在无障碍服务配置中声明android:isAccessibilityTool="true"。

非系统应用声明了isAccessibilityTool必须通过受信任的安装源安装,才能避免卸载的通知提示。

2.23、大概位置

使用针对Android 12的应用程序时,用户可以要求该应用程序只能访问大概的位置信息。

注意:如果您的应用程序请求ACCESS_COARSE_LOCATION但不请求ACCESS_FINE_LOCATION,则此变更不会影响您的应用程序。图1显示了以Android 12为目标的应用仅请求ACCESS_COARSE_LOCATION时出现的对话框。

如果您的应用面向Android 12并请求ACCESS_FINE_LOCATION运行时权限,则您还必须请求ACCESS_COARSE_LOCATION权限。您必须在单个运行时请求中同时包含两个权限。

当您的应用同时请求ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION时,系统权限对话框将为用户提供以下新选项,如图2所示。

                                     图1                                                             图2

2)兼容性影响

为了更好地尊重用户隐私,建议您仅请求ACCESS_COARSE_LOCATION。即使仅访问大概的位置信息,也可以满足大多数用例。

如果您的应用面向Android 12,并且您请求ACCESS_FINE_LOCATION权限,那么您还必须请求ACCESS_COARSE_LOCATION权限。您必须在单个运行时请求中同时包含两个权限。如果尝试仅请求ACCESS_FINE_LOCATION,则系统将忽略该请求,并在Logcat中记录以下错误消息:ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION

3 )适配指导

面向Android 12的应用程序,可以使用如下代码进行ACCESS_FINE_LOCATION的申请:

如果当前位置依赖于使用ACCESS_FINE_LOCATION权限访问精确位置的应用,则大概位置可能会影响您的应用。在要求用户将应用程序的访问权限升级到精确位置之前,请考虑您的应用程序用例是否绝对需要这种精确度。如果您的应用需要通过蓝牙或Wi-Fi将设备与附近的设备配对,请考虑使用配对设备配对或新的蓝牙权限,而不是请求ACCESS_FINE_LOCATION权限。 要请求用户将您应用的位置信息访问权限从近似升级为精确,请执行以下操作:如有必要,请说明您的应用为何需要许可。再次一起请求ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限。

要评估是否需要更新应用程序以支持用户可配置的位置准确性,请完成位置准确性切换的测试,详细步骤如下:https://developer.android.com/about/versions/12/approximate-location#test

2.24、备份和还原

新一代平台中,针对Android 12的应用程序,备份和还原的工作方式有所变化。Android备份和还原具有两种形式:

云备份:用户数据存储在用户的Google云盘中,以便以后可以在该设备或新设备上还原。

设备到设备(D2D)传输:用户数据从旧设备直接发送到用户的新设备,例如数据线。

有关如何备份和还原数据的更多信息,请参阅Back up user data with Auto BackupBack up key-value pairs with Android Backup Service

2)兼容性影响

1 D2D传输功能变更

对于以 Android 12 及更高版本为目标平台的应用:

指定android:allowBackup =”false”会禁用备份到Google云盘,但不会禁用该应用程序的D2D传输。

使用XML配置机制指定包含和排除规则,不再影响D2D传输,但仍会影响Google云盘备份。要对D2D传输指定规则,您必须使用下一部分中介绍的新配置规则。

2 新的包含和排除格式

对于以 Android 12 及更高版本为目标平台的应用,使用不同的XML配置格式。通过要求您分别指定云备份和D2D传输的包含和排除规则,此格式可明确区分Google云盘备份和D2D传输。

您也可以使用它来指定备份规则,在这种情况下,旧配置将被忽略。

*注意:如果您使用新的配置格式,则即使您尚未定位到Android 12,您的应用也将使用新的行为。

a  XML格式变更

以下是Android 11及更低版本中用于备份和还原配置的格式:

下面以粗体显示了格式的变更

配置的每个部分(<cloud-backup>,<device-transfer>)都包含仅适用于该特定类型的传输的规则。例如,这使您可以从Google云端硬盘备份中排除文件或目录,同时在D2D传输过程中仍将其传输。如果文件太大而无法备份到云,但是可以在设备之间传输而不会出现问题,这可能会很有用。

如果没有针对特定备份模式的规则(例如,缺少<device-transfer>部分),则该模式将对除no-backup和cache目录之外的所有内容完全启用,如Files that are backed up所述。

您的应用程序可以在<cloud-backup>部分中设置disableIfNoEncryptionCapabilities标志,以确保仅在设备加密时(例如,当用户具有锁定屏幕时)才进行备份。如果用户的设备不支持加密,则设置此约束将阻止将备份发送到云,但是由于D2D传输没有发送到服务器,因此即使在不支持加密的设备上,D2D传输也将继续运行。

b  应用程序的清单标志

使用清单文件中的android:dataExtractionRules属性将您的应用程序指向新的XML配置。 当您指向新的XML配置时,指向旧配置的android:fullBackupContent属性将被忽略。以下代码示例显示了新的清单文件条目:

3)适配指导

请面向android 12的应用按照新的规则进行适配。

2.25、应用休眠

Android 12扩展了Android 11(API级别30)中引入的权限自动重置行为。如果您的应用以Android 12为目标,并且用户几个月没有与应用交互,则系统会自动重置所有授予的权限,并将您的应用置于休眠状态。

2)兼容性影响

处于休眠状态的应用程序具有以下特征:

系统针对存储空间而不是性能进行了优化。应用缓存中的所有文件都将被删除。

该应用程序无法从后台运行作业或警报。

该应用无法接收推送通知,包括通过Firebase Cloud Messaging发送的高优先级消息。

3)适配指导

当用户下次与该应用程序交互时,该应用程序退出休眠状态,并且可以再次创建作业,警报和通知。但是,您需要重新计划,在应用程序进入休眠状态之前计划的所有作业,警报和通知。此工作流程类似于用户手动从系统设置中强制停止您的应用程序。要更轻松地支持此工作流程,请使用WorkManager。您还可以在ACTION_BOOT_COMPLETED广播接收器中添加重新计划逻辑,当您的应用退出休眠状态并在设备启动后被调用。

1 请求用户禁用休眠

如果您预计应用中的用例会受到休眠的影响,则可以向用户发送请求,以授予您的应用免于休眠和权限自动重置的豁免权。此豁免对于即使用户没有与应用程序进行交互,而用户仍希望应用程序在后台运行的工作也很有用,例如当您的应用程序执行以下一项或多项操作时:

通过定期报告家庭成员的位置来提供家庭安全。

在设备和应用服务器之间同步数据。

与电视等智能设备进行通信。

与伴侣设备配对,例如手表。

请求豁免,请调用包含Intent.ACTION_APPLICATION_DETAILS_SETTINGS意向操作的意向。在出现的界面上,用户可以关闭名为”Remove permissions and free up space”选项。

*注意:在调用该意图之前,请考虑向用户显示指导性UI,以使他们理解为什么您的应用将他们带到系统设置。

2 测试休眠行为

要将应用置于休眠状态以进行测试,请执行以下操作:

a 在设备上启用休眠行为:

b 更改应用程序的状态,使其进入休眠状态。包含--global标志的命令会强制您的应用进入“完全休眠”状态,以模拟系统已使您的应用进入设备上所有用户的休眠状态。

2.26、刷新率切换的提升

在Android 12中,无论显示是否支持无缝过渡到新的刷新率,都可以使用setFrameRate()进行刷新率更改。

2)兼容性影响

无缝过渡是一种没有任何视觉中断的过渡,比如一秒钟或两秒钟的黑屏。 以前,如果显示不支持无缝过渡,则通常在调用setFrameRate()之后系统将继续使用相同的刷新率。

在android 12中,您可以通过调用getAlternativeRefreshRates()预先确定向新刷新率的过渡是否将是无缝的。通常,在刷新率切换完成后将调用onDisplayChanged()回调,但对于某些外部连接的显示器,将在非无缝过渡期间调用该回调。

3)适配指导

以下是有关如何实现刷新率切换目的的示例:

2.27、Bouncy Castle实现的移除

Android 12移除了许多之前平台中已标记为deprecated的BouncyCastle加密算法实现,包括所有AES算法。系统改为使用Conscrypt进行替换。

2)兼容性影响

如果满足以下任一条件,则此变更会影响您的应用程序:

您的应用使用512位密钥大小。Conscrypt不支持此大小的密钥。 如有必要,请更新您应用的加密逻辑以使用不同大小的密钥。

您使用12字节以外的大小初始化Galois /计数器模式(GCM)密码。 Conscrypt的GcmParameterSpec的实现需要12字节的初始化,这是NIST推荐的。

3)适配指导

使用Conscrypt进行方案替换,具体实施见:https://github.com/google/conscrypt

2.28、供应商提供的so库的使用

如果应用程序针对的是Android 12或更高版本,默认情况下将无法访问由芯片供应商或设备制造商提供的非NDK本机共享库。 仅当使用<uses-native-library>标记明确请求它们时,这些库才可访问。

如果该应用程序针对Android 11或更低版本,则不需要<uses-native-library>标签。在这种情况下,无论本机共享库是否为NDK库,都可以访问。

2)兼容性影响

如果满足以下条件,则此变更会影响您的应用程序:

您的应用是面向android 12的app,使用到了芯片供应商或设备制造商提供的非NDK so,并且应用的清单文件中没有使用<uses-native-library>对此so的使用声明。

3)适配指导

应用需要排查代码中使用system.loadlibrary的逻辑,使用到了soc或者厂家公开的so。这些so的列表配置在手机的如下位置:

vendor/etc/public.libraries.txt

system/etc/public.libraries-<company>.txt

system_ext/etc/public.libraries-<company>.txt

product/etc/public.libraries-<company>.txt

company为公司名,如高通是qti;mtk平台为mtk。如果app有使用到上述位置中的so,那么应用target api升级到31后,需要在其AndroidManifest.xml中使用 <uses-native-library>标签进行显式声明。

2.29、启动页面

Android 12添加了SplashScreen API,可为所有应用程序提供新的启动动画。这包括启动时的动效,显示app图标的初始画面以及到应用程序本身的过渡。

全新的体验会在每次启动应用程序时带来标准化的设计元素,而且还可以支持自定义以使得您的应用保持独特的品牌形象。

2)兼容性影响

当用户在应用进程未运行(冷启动)或未创建活动(热启动)时,将发生以下事件(热启动期间从不会显示启动画面)。

系统使用主题和您定义的动画显示初始画面。

应用就绪后,启动画面将关闭,并显示该应用。

动画元素由Android清单中的XML资源文件定义。每种都有明暗模式版本。它们由窗口背景,应用动画图标和图标背景组成:

窗口背景是必需的,并且由单一不透明颜色组成。

应用程序图标应该是可绘制的矢量,并且可以是静态的也可以是动画的。动画的持续时间最长为1000毫秒。

图标背景是可选的,如果在图标和窗口背景之间需要更多的对比度,则很有用。

初始画面动画机制包括进入和退出动画。

进入动画包含启动画面的系统视图。这是由系统控制的,无法自定义。

退出动画由隐藏初始画面的动画运行组成。您可以访问SplashScreenView和动画图标,并可以在它们上运行任何动画,设置变换,不透明度和颜色。完成动画后,将移除初始画面。

3)适配指导

您可以在Activity主题中指定以下属性,以自定义应用程序的初始画面。如果您已经有使用诸如android:windowBackground之类的属性的旧式启动屏幕实现,请考虑为Android 12提供备用资源文件。

1 使用windowSplashScreenBackground用特定的单色填充背景:

2 使用windowSplashScreenAnimatableIcon替换启动窗口中心的图标。如果对象是可动画的,通过AnimationDrawable和AnimatedVectorDrawable绘制的,则它还将在显示起始窗口的同时播放动画。

3 使用windowSplashScreenAnimationDuration设置启动画面在关闭前出现的时间。最长时间为1,000毫秒。

4 使用windowSplashScreenIconBackground设置初始画面图标后面的背景。如果窗口背景和图标之间的对比度不足,这很有用。

5 您可以使用windowSplashScreenBrandingImage设置要在初始画面底部显示的图像。设计指南建议不要使用品牌形象。

保持启动画面在屏幕上更长的时间:

当您的应用绘制第一帧时,启动画面即被关闭。如果需要异步从本地磁盘加载少量数据(例如应用程序内主题设置),则可以使用ViewTreeObserver.OnPreDrawListener挂起应用程序以绘制其第一帧。

自定义启动画面消失的动画

您可以通过Activity.getSplashScreen进一步自定义初始画面的动画:

在此回调开始之前,初始画面上可绘制的矢量动画已经开始。根据应用程序启动的持续时间,可绘制对象可能位于其动画的中间。 使用SplashScreenView.getIconAnimationStartMillis可以知道动画何时开始, 您可以用如下计算图标动画的剩余持续时间:

Android 12引入了RoundedCorner和WindowInsets.getRoundedCorner(int position),它们提供了圆角的半径和中心点。

2)兼容性影响

使用这些RoundedCorner API,您的应用程序可以避免UI元素在带有圆角的屏幕上被截断。

在您的应用中实施时,这些API对屏幕不圆的设备不起作用。

3)适配指导

要实现此功能,请通过WindowInsets.getRoundedCorner(int position)相对于应用程序的边界获取RoundedCorner信息。如果应用程序无法占据整个屏幕,则API会通过将圆角的中心点置于应用程序的窗口边界范围内来应用圆角。

// Get the top-right rounded corner from WindowInsets.
final WindowInsets insets = getRootWindowInsets();
final RoundedCorner topRight = insets.getRoundedCorner(POSITION_TOP_RIGHT);
if (topRight == null) {
   return;
// Get the location of the close button in window coordinates.
int [] location = new int[2];
closeButton.getLocationInWindow(location);
final int buttonRightInWindow = location[0] + closeButton.getWidth();
final int buttonTopInWindow = location[1];
// Find the point on the quarter circle with a 45 degree angle.
final int offset = (int) (topRight.getRadius() * Math.sin(Math.toRadians(45)));
final int topBoundary = topRight.getCenter().y - offset;
final int rightBoundary = topRight.getCenter().x + offset;
// Check whether the close button exceeds the boundary.
if (buttonRightInWindow < rightBoundary && buttonTopInWindow > topBoundary) {
   return;
// Set the margin to avoid truncating.
int [] parentLocation = new int[2];
getLocationInWindow(parentLocation);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) closeButton.getLayoutParams();
lp.rightMargin = Math.max(buttonRightInWindow - rightBoundary, 0);
lp.topMargin = Math.max(topBoundary - buttonTopInWindow, 0);
closeButton.setLayoutParams(lp);

3.2、沉浸式手势导航改进

Android 12简化了沉浸式模式,使手势导航更加轻松,并且与其他activities(如观看视频和读书)的体验保持一致。应用仍然可以防止全屏游戏体验中的意外手势,因此用户在玩游戏时不会意外退出游戏;现在,所有其他全屏或身临其境的体验都允许用户轻扫一下即可导航手机。

2)兼容性影响

非粘性沉浸式行为(BEHAVIOR_SHOW_BARS_BY_TOUCHBEHAVIOR_SHOW_BARS_BY_SWIPE)在Android 12中被弃用,在Android 12中可使用默认BEHAVIOR_DEFAULT替代。并且BEHAVIOR_DEFAULT支持只需一次滑动手势即可显示隐藏的系统栏。此标识根据模式不同显示不同的功能和视觉:

1 三键模式下,功能和视觉和Android 12前的版本有相同的沉浸式模式。

2 手势导航模式下,行为如下:

在视觉上,与Android 11及更低版本的沉浸式模式相同。

功能上,即使隐藏了栏,也允许使用手势。系统返回仅需要一次滑动即可调用,而无需使用Android 11的两次滑动。无需其他滑动即可拉下通知栏或回到首页。

粘性沉浸式行为BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE在Android 12中没有变化。

3)适配指导

注意非粘性沉浸式行为BEHAVIOR_SHOW_BARS_BY_TOUCHBEHAVIOR_SHOW_BARS_BY_SWIPE在Android 12中被弃用,请使用BEHAVIOR_DEFAULT替代。

×controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH);

×controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE);

controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);

3.3、画中画模式的提升

Android 12改进了单击和双击pip窗口的行为,单击和双击pip窗口的行为优化

l 单击pip窗口时仅显示控制组件,以前单击操作会强制展开pip窗口并显示控制组件。

l 双击pip窗口,窗口会在当前pip窗口大小和最大窗口大小之间切换。以前双击窗口会切换到全屏模式。

2)兼容性影响

如APP已适配双击单击pip窗口的行为,可能导致冲突。

3)适配指导

如APP已适配双击单击pip窗口的行为,可考虑兼容Android 12中的行为优化。

3.4、兼容的媒体转码

Android 12 引入了一项新功能,允许视频相关应用程序可以对设备上录制的视频进行更现代、存储效率更高的编码,同时又不影响与其他应用的兼容性。

2)兼容性影响

如果视频被不支持HEVC 格式的应用打开,Android 会自动将以 HEVC (H.265) 等格式录制的视频转码为 AVC (H.264) 格式。对于在设备上创建的以下格式的内容,系统可以自动进行转码:

3)适配指导

Android假定应用程序可以支持所有媒体格式的播放,因此默认情况下禁用兼容的媒体转码。 需要将媒体转码为更兼容格式的应用要声明其媒体功能。 有两种方法可以声明这些功能:在资源中或在代码中。

1 资源中声明

首先,创建 media_capabilities.xml 资源文件:

在此示例中,设备上录制的 HDR 视频被无缝转码为 AVC SDR视频,而 HEVC 视频则无法转码。

在 application 标记中使用 property 标记来添加对媒体功能文件的引用。将以下属性添加到 AndroidManifest.xml 文件中:

2 在代码中声明功能

通过 ContentResolver#openTypedAssetFileDescriptor() 等方法访问媒体内容时,请使用此对象:

此方法优先于AndroidManifest.xml 静态配置,它允许针对特定代码路径进行更精细的控制。

3.5、熄屏状态下支持NFC支付

在针对Android 12及更高版本的应用中,可以通过将requireDeviceScreenOn设置为false来启用NFC付款,而无需点亮设备的屏幕。

2)兼容性影响

当前的Android会在关闭设备屏幕时完全关闭NFC控制器和应用处理器。 因此,当屏幕关闭时,HCE服务将无法使用。

HCE服务可以从锁定屏幕运行,由HCE服务的<host-apdu-service>标记中的android:requireDeviceUnlock属性控制。默认情况下,不需要设备解锁,即使设备已锁定,您的服务也会被调用。

Android 12上,HCE服务的<host-apdu-service>标记中新增了属性:

android:requireDeviceScreenOn

用来支持熄屏下使用NFC服务。默认值取决于AIDS是否在主机CPU上运行,若在主机CPU上运行,默认值为true,反之默认值为false,即对于host应用和offhost应用的requireDeviceScreenOn默认值的区别。

Host应用是使用基于主机的卡仿真来仿真NFC卡,数据将被路由到直接运行Android应用程序的主机CPU,而不是将NFC协议帧路由到安全元件(Secure Element)。

Offhost应用使用SE提供NFC卡模拟,将通过Android应用程序将要模拟的卡提供到设备上的SE中。然后,当用户通过NFC终端握住设备时,设备中的NFC控制器将来自读卡器的所有数据直接路由到SE。

3)适配指导

下面以构建NFC的应用程序为例进行说明:

1 实现一个服务类,继承自HostApduService,并重写其中的processCommandApdu与onDeactivated方法:

2 修改AndroidManifest.xml文件,在application标签中添加service标签:

3 编写HCE配置xml,在res/xml目录下,新建一个apduservice.xml文件,这个配置文件主要决定NFC通信过程中的数据路由:

Android 12 应用兼容性适配指导一、兼容性调试工具Android 11开始引入了新的工具,可针对Android新平台中的行为变更进行测试和调试。这些工具是兼容性框架的一部分,该框架使得开发者可通过开发者选项或adb命令单独打开和关闭各项变更。藉此,可在最新android预览版中测试我们的app受到新平台及target api调整的影响,完成app对新平台的兼容适配。使用adb命令打开或关闭变更,请运行以下命令之一: adb shell am compat enable (C..
Android 中实现 App 在后台录屏主要需要使用到 MediaProjection API。 MediaProjection API 是 Android 5.0(API Level 21)引入的新特性,用于捕获屏幕内容并输出到文件或流中。 下面是一个简单的示例代码,演示如何使用 MediaProjection API 在后台录屏:
DisplayArea类的继承关系,之前已经分析过,这里用一张简单的类图总结:既然DisplayContent是作为其代表的屏幕的DisplayArea层级结构的根节点,那么从DisplayContent出发,看一下这棵以DisplayContent为根节点的DisplayArea树是如何生成的。 在DisplayContent的构造方法中,调用DisplayAreaPolicy.Provider.instantiate方法,去初始化一个DisplayArea层级结构。DisplayAreaPolicy.P
调试应用,安装apk失败 Installation did not succeed. The application could not be installed: INSTALL_FAILED_TEST_ONLY List of apks: [0] 'D:\develop\work\StarEra\arguesture\app\build\intermediates\apk\debug\Gesture-2022-05-05-debug.apk' Installation failed due 参考:android - APK installation failed: [INSTALL_FAILED_VERIFICATION_FAILURE] - Stack Overflow
Android 12引入了一种新的动态屏幕适配方法,即使用DpSize,以便更好地支持屏幕的多样化。DpSize是指实际屏幕尺寸的大小,以dp为单位。 在Android 12源码中,可以使用以下步骤进行动态屏幕适配: 1. 在values文件夹下新建一个dimens.xml文件,定义DpSize的大小。 <dimen name="dp_size">600dp</dimen> 2. 在AndroidManifest.xml中添加以下代码,以指定应用程序支持的最小DpSize。 <supports-screens android:requiresSmallestWidthDp="600" /> 3. 在res文件夹下新建一个layout-w600dp文件夹,将需要适配的布局文件放在该文件夹中。 res/layout-w600dp/activity_main.xml 4. 在代码中使用dp_size作为参考值,进行动态计算并调整UI元素的大小和位置。 int dpSize = getResources().getDimensionPixelSize(R.dimen.dp_size); int screenWidth = getResources().getDisplayMetrics().widthPixels; int screenHeight = getResources().getDisplayMetrics().heightPixels; int desiredWidth = (int) (screenWidth * 0.8); int desiredHeight = (int) (screenHeight * 0.8); if (dpSize < screenWidth) { // Adjust UI elements for smaller screens } else { // Adjust UI elements for larger screens 通过以上步骤,可以根据设备屏幕的大小和DpSize进行动态屏幕适配,让应用程序在不同的设备上都能够呈现最佳的用户体验。