Android 11 不看没什么问题,一看都是问题

本文解析了Android11的新特性与变化,包括控制外部设备、媒体控件显示方式更新、屏幕适配改进等内容,并介绍了适配时需要注意的隐私、安全等方面的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

奋斗是什么?每一天很难,但是一年比一年容易。不奋斗就是每天很容易,一年比一年难。

一、前言

  让人又爱又恨的Android 11来了,新一轮的适配也要准备了。咖啡、茶、辣条已经准备妥当,兄弟们可以开始熬夜搬砖了 。看完了更新文档后,瑟瑟发抖的我还是写下了读后感。

二、新体验

官方文档

1.控制外部设备

 简介:Android 11 包含一个新的 ControlsProviderService API,可用于提供所连接的外部设备的控件。这些控件显示于Android 电源菜单中的设备控制器下。内容有限 点击详细说明 。应用在android 11版本中适配添加该功能点击适配
2. 媒体控件的显示方式

 简介:Android 11 更新了媒体控件的显示方式,使用 MediaSession 和 MediaRouter2 API 呈现控件和音频输出信息。支持“继续播放媒体内容”功能,想使用此功能,必须在“开发者选项”设置中启用继续播放媒体内容。点击详情
3.屏幕更新

 简介:1.Android 11 提供了一些 API 以支持瀑布屏,这是一种无边框的全面屏。如需要在您的应用中添加该功能执行以下操作:

  • 调用 DisplayCutout.getWaterfallInsets() 以获取瀑布边衬区的精确尺寸
  • 将窗口布局属性 layoutInDisplayCutoutMode 设为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,以允许窗口延伸到屏幕各个边缘上的刘海和瀑布区域。您必须确保刘海或瀑布区域中没有重要的内容 2.Android 11 针对可折叠设备提供了新的传感器,可以监控折叠合页时的角度。点击详情

4.会话
 简介:Android 11 对会话的处理方式进行了多项改进。点击详情官方文档

5.5G 图标显示
 简介:Android 11及更高版本中,具有 android.Manifest.permission.READ_PHONE_STATE 权限的应用可以通过 PhoneStateListener.onDisplayInfoChanged() 请求更新电话显示信息,其中包括用于营销和品牌塑造的无线接入技术信息。### 三、适配 Android 11 行为变化
 变化分为两部分:1.应用运行在手机版本 >= android 11 上 2.targetSdkVersion>=30的应用

 根据变化情况考虑我们的应用是否需要适配新的变化。

(1)应用运行在手机版本 >= android 11 上
  1. 隐私变化

    单次授权: 每当应用请求与位置信息、麦克风或相机相关的权限时,面向用户的权限对话框会包含仅限这一次选项。如果用户在对话框中选择此选项,系统会向应用授予临时的单次授权。然后,应用可以在一段时间内访问相关数据,当用户下次打开应用并且应用中的某项功能请求访问位置信息、麦克风或摄像头时,系统会再次提示用户授予权限。

    权限对话框的可见性: 如果用户在使用过程中多次针对某项特定的权限点按拒绝,那么在您的应用再次请求该权限时,用户将不会看到系统权限对话框。该操作表示用户希望“不再询问”。所以当要访问权限时还需要检查是否有权限等一系列操作。

    数据访问审核: 引入了数据访问审核功能,当应用的代码访问私密数据,依赖库或 SDK 中的代码访问私密数据时。应用可以注册 AppOpsManager.OnOpNotedCallback 实例,监听访问私密数据过程。查看详情

    系统提醒窗口权限: 向应用授予 SYSTEM_ALERT_WINDOW 权限的方式发生了一些变更。1.系统会自动向具有 ROLE_CALL_SCREENING 且请求 SYSTEM_ALERT_WINDOW 的所有应用授予该权限。如果应用失去 ROLE_CALL_SCREENING,就会失去该权限。2.系统会自动向通过 MediaProjection 截取屏幕且请求 SYSTEM_ALERT_WINDOW 的所有应用授予该权限,除非用户已明确拒绝向应用授予该权限。这些应用无需发送 ACTION_MANAGE_OVERLAY_PERMISSION 以获取 SYSTEM_ALERT_WINDOW 权限,它们只需直接请求 SYSTEM_ALERT_WINDOW 即可。

    永久 SIM 卡标识符: 在 Android 11 及更高版本中,使用 getIccId() 方法访问 ICCID 受到限制。该方法会返回一个非 null 的空字符串。如需唯一标识设备上安装的 SIM 卡,请改用 getSubscriptionId() 方法
  2. Exposure Notification

    Android 11 将对 Exposure Notification API 进行例外处理,并默认为其授予位置服务权限。
  3. 安全性

    SSL 套接字默认情况下使用 Conscrypt SSL 引擎: Android 的默认 SSLSocket 实现基于 Conscrypt。从 Android 11 开始,该实现是在 Conscrypt 的 SSLEngine 之上内部构建的。

    Scudo Hardened Allocator: Android 11 在内部使用 Scudo Hardened Allocator 为堆分配提供服务。Scudo 能够检测并减轻某些类型的内存安全违规行为。如果您在原生代码崩溃报告中发现与 Scudo 相关的崩溃(例如 Scudo ERROR:),请参阅 Scudo 问题排查文档。

    应用使用情况统计信息: Android 11 将每个用户的应用使用情况统计信息存储在凭据加密存储空间中。系统和任何应用都无法访问该数据,除非 isUserUnlocked() 返回 true,这发生在用户在系统启动后首次解锁其设备或用户在设备上切换到自己帐号的情况。

    针对 5G 的模拟器支持: Android 11 添加了 5G API,使您的应用能够添加各种先进的功能,如需在添加这些功能时对其进行测试,您可以使用 Android SDK 模拟器的新功能。
  4. 性能和调试

    JobScheduler API 调用限制调试: JobScheduler 任务调度器,可以在设备空闲时做一些任务处理。Android11 中如果你设置为 debug 模式(debuggable 清单属性设置为 true),超出速率限制的 JobScheduler API 调用将返回 RESULT_FAILURE。

    文件描述符排错程序: Android 10 引入了 fdsan(文件描述符排错程序),在 Android 11 中,fdsan 的默认模式发生了变化。fdsan 会在检测到错误时中止,而以前的行为则是记录警告并继续。如果您在应用中发现由于 fdsan 而导致的崩溃,请参阅 fdsan documentation
  5. V1 版 Google 地图共享库已移除

    Android 11 中已完全移除 V1 版 Google 地图共享库。此库之前已被弃用,并已停止在 Android 10 中的应用中运行。对于搭载 Android 9(API 级别 28)或更低版本的设备,之前依赖于此共享库的应用应改用适用于 Android 的 Google 地图 SDK
  6. 分享内容 URI

    如果您的应用与其他应用分享内容 URI,相应 intent 必须至少设置以下 intent 标记中的一个,以便授予对 URI 的访问权限:FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION,如果其他应用以 Android 11 为目标平台,相应应用仍可访问内容 URI。即使内容 URI 与不属于您的应用的内容提供程序相关联,您的应用也必须包含 intent 标记。
(2)targetSdkVersion >= 30的应用
  1. 隐私设置

    强制执行分区存储: 在 Android 11 上运行但以 Android 10(API 级别 29)为目标平台的应用仍可请求 requestLegacyExternalStorage 属性。应用可以利用此标记暂时停用与分区存储相关的变更,例如授予对不同目录和不同类型的媒体文件的访问权限。当您将应用更新为以 Android 11 为目标平台后,系统会忽略 requestLegacyExternalStorage 标记。解决:存储用例和最佳做法Android 11 存储常见问题解答

    自动重置权限: 如果应用以 Android 11 或更高版本为目标平台并且数月未使用,系统会通过自动重置用户已授予应用的运行时敏感权限来保护用户数据。此操作与用户在系统设置中查看权限并将应用的访问权限级别更改为拒绝的做法效果一样。如果应用遵循了有关在[运行时请求权限的最佳做法](https://developer.android.google.cn/training/permissions/requesting),那么您不必对应用进行任何更改。这是因为,当用户与应用中的功能互动时,您应该会验证相关功能是否具有所需权限。

    在后台访问位置信息的权限: Android 11 更改了应用中的功能获取后台位置信息访问权限的方式,

    软件包可见性: Android 11 更改了应用查询用户已在设备上安装的其他应用以及与之交互的方式,使用 queries 元素,应用可以定义一组自身可访问的其他软件包。解决方案:管理其他已安装应用的软件包可见性
  2. 安全

    堆指针标记: 堆指针在最高有效字节 (MSB) 中有一个非零标记,错误地使用指针的应用(包括修改 MSB 的应用)现在会崩溃或遇到其他问题。这是支持未来启用了 ARM 内存标记扩展 (MTE) 的硬件所必需的变更。如需了解详情,请参阅已加标记的指针

    消息框的更新: 出于安全方面的考虑,同时也为了保持良好的用户体验,如果包含自定义视图的消息框是以 Android 11 或更高版本为目标平台的应用从后台发送的,系统会屏蔽这些消息框。请注意,仍允许使用文本消息框;此类消息框是使用 Toast.makeText() 创建的,并不调用 setView()。
  3. 网络连接

    限制对 APN 数据库的读取访问: 以 Android 11 为目标平台的应用现在必须具备 Manifest.permission.WRITE_APN_SETTINGS 特权,才能读取或访问电话提供程序 APN 数据库。如果在不具备此权限的情况下尝试访问 APN 数据库,会生成安全异常。
  4. 无障碍服务

    在清单文件中声明与 TTS 引擎的交互: 由于软件包可见性发生了变更,因此以 Android 11 为目标平台且与文字转语音 (TTS) 引擎交互的应用需要将以下 queries 元素添加到其清单文件中
<queries>
  <intent>
    <action
       android:name="android.intent.action.TTS_SERVICE" />
  </intent>
</queries>

在元数据文件中声明“无障碍”按钮使用情况: 从 Android 11 开始,您的无障碍服务无法在运行时声明与系统的“无障碍”按钮相关联;如需在无障碍服务中收到无障碍回调事件,请使用无障碍服务元数据文件声明您的服务与“无障碍”按钮的关联。在 accessibilityFlags 属性的定义中添加 flagRequestAccessibilityButton 值。无障碍服务元数据文件的常用位置为 res/raw/accessibilityservice.xml。
 5.相机

媒体 intent 操作需要系统默认相机: 从 Android 11 开始,只有预装的系统相机应用可以响应以下 intent 操作:

android.media.action.VIDEO_CAPTURE
android.media.action.IMAGE_CAPTURE
android.media.action.IMAGE_CAPTURE_SECURE

如果有多个预装的系统相机应用可用,系统会显示一个对话框,供用户选择应用。如果您希望自己的应用使用特定的第三方相机应用来代表其捕获图片或视频,可以通过为 intent 设置软件包名称或组件来使这些 intent 变得明确。
 6. 应用打包和安装

压缩的资源文件 如果以 Android 11(API 级别 30)或更高版本为目标平台的应用包含压缩的 resources.arsc 文件或者如果此文件未按 4 字节边界对齐,应用将无法安装。

现在需要 APK 签名方案 v2 用户无法在搭载 Android 11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用,现在必须使用 APK 签名方案 v2 或更高版本进行签名。
 7. 设备到设备文件传输

如果您的应用以 Android 11 或更高版本为目标平台,您将无法使用 allowBackup 属性停用应用文件的设备到设备迁移。系统会自动启用此功能。但可以通过将 allowBackup 属性设为 false 来停用应用文件的云端备份和恢复。
 8. OnSharedPreferenceChangeListener 的回调变更

 对于以 Android 11(API 级别 30)为目标平台的应用,现在每次调用 Editor.clear 时,都会使用 null 键回调 OnSharedPreferenceChangeListener.onSharedPreferenceChanged。

四、总结



  本文没有详细涉及到如何适配android 11的改变。但从蛛丝马迹中还是可以发现一点点解决办法。本文属于总结陈述android 11的变化。希望可以全方位的了解更新内容。然后从中发现自己应用需要做哪些改变与适配。

五、内容推荐 《优快云》《简书》

<think>好的,我现在需要详细解释这段代码:decorView.getRootWindowInsets().getInsetsIgnoringVisibility(navigationBars()).bottom。同时还要给出个通过adb命令获取相同值的命令。让我步步思考这个问题。 首先,分解代码结构。DecorView是Android中窗口的根视图,getRootWindowInsets()应该获取与该视图关联的WindowInsets,也就是窗口的嵌入区域信息,比如状态栏、导航栏等占据的空间。接下来是getInsetsIgnoringVisibility(navigationBars()),这个方法的作用是获取导航栏的嵌入尺寸,管导航栏当前是否可见。最后取的是bottom部分,也就是底部的嵌入值,即导航栏的高度。 那问题来了,这个代码的作用是获取导航栏的高度,即使导航栏当前是隐藏的。通常,如果导航栏可见的话,系统会自动调整内容区域,但这里用getInsetsIgnoringVisibility可能意味着即使可见也会返回其尺寸。这可能在某些情况下需要,比如全屏应用但仍需要考虑系统UI的占位。 接下来,用户还希望用adb命令获取相同的值。这需要知道如何通过adb访问系统UI的尺寸信息。通常,Android系统中导航栏的高度等信息存储在系统属性中,或者可以通过wm命令获取。例如,使用adb shell wm命令来获取显示信息,或者通过读取系统资源的值。 过,导航栏的高度可能因设备而异,取决于屏幕密度和设备的设置。通常,导航栏的高度存储在系统的资源中,比如config_navBarHeight或者类似的值。可以通过adb shell命令进入设备,然后使用dumpsys window或者getprop来查找相关配置。 另外,可能需要检查具体的资源标识符。例如,使用adb shell dumpsys window displays可以查看当前显示的参数,包括屏幕尺寸和系统UI的尺寸。过,其中可能包含导航栏的高度信息。或者,使用adb shell cmd window get-nav-bar-height这样的命令是否存在?可能同的Android版本有同的方法。 或者,考虑通过资源工具获取。例如,使用adb shell dumpsys window | grep mNavigationBarHeight,但需要确认是否存在这样的字段。或者使用adb shell getprop ro.navigationbar.height,但有些设备可能没有这个属性。 另外,有些设备可能允许通过settings获取,例如adb shell settings get secure sysui_nav_bar_height,但确定是否通用。需要进步验证。 总结下,可能的步骤是: 1. 分析代码的作用是获取导航栏的底部嵌入高度,忽略可见性。 2. 导航栏的高度通常存储在系统资源中,如config_navBarHeight。 3. 通过adb命令获取该资源的值,或者通过dumpsys window命令查找相关信息。 现在,需要找到具体的命令。例如,使用adb shell dumpsys window displays命令,查看输出中的Insets信息。例如,在某个设备上,输出可能包含类似: Display: mDisplayId=0 init=1080x2400px 420dpi cur=1080x2400px app=1080x2274 rng=1080x1017-2400x2400 deferred=false layoutNeeded=false mSystem=android.view.InsetsState@7d21b3e InsetsSource: type=NAVIGATION_BAR frame=[0,2274][1080,2400] visible=true ... 这里可以看到导航栏的frame是[0,2274][1080,2400],所以高度是2400-2274=126像素。这应该就是导航栏的高度。 所以对应的adb命令可能是: adb shell dumpsys window displays | grep NavigationBarInsets 或者更具体地解析输出中的Insets部分。同设备输出可能同,需要调整grep的条件。例如,使用: adb shell dumpsys window displays | grep -Eo 'NavigationBarInsets: .*' 或者查找包含导航栏信息的行。例如,在某些设备上,可能没有直接的显示,但可以通过查找包含导航栏的部分。例如,使用: adb shell dumpsys window | grep mNavigationBarHeight 或者: adb shell dumpsys window policy | grep mNavigationBarHeight 例如,在某个设备上运行这个命令可能得到类似: mNavigationBarHeight=126 或者,在资源中查找: 使用adb shell命令访问资源值。每个资源在Android中都有唯的标识符,可以通过Resources.getSystem().getIdentifier()获取。例如,config_navBarHeight对应的资源ID可以通过如下方式获取: adb shell "cmd overlay lookup android android:dimen/navigation_bar_height" 或者直接使用资源ID: 在Android系统中,导航栏高度的资源名称通常是navigation_bar_height,对应的dimen资源。例如,在系统资源中,其ID为com.android.internal.R.dimen.navigation_bar_height。但是,直接访问可能需要知道其具体的资源ID或者使用对应的工具。 或者,使用如下命令: adb shell dumpsys window | grep mStableInsets 或者查看WindowInsets的信息。例如: adb shell dumpsys window insets 过这可能只在较新的Android版本中存在。 另外,个更直接的方法是使用wm命令: adb shell wm size adb shell wm overscan adb shell wm density 但这些可能直接显示导航栏高度。 综上,可能最可靠的方式是使用dumpsys window displays并解析其中的Insets信息。例如: adb shell dumpsys window displays | grep 'NavigationBar' 然后手动计算其高度,比如找到其frame的坐标差。 或者,使用更精确的解析,例如: adb shell dumpsys window displays | awk '/NavigationBar/ {gsub(/[\[\]]/, "", $4); split($4, a, ","); print a[4]-a[2]}' 这个命令假设在输出中有类似frame=[0,2274][1080,2400]的结构,那么用awk分割后,第四个字段是第二个坐标的结束点,即2400,第二个是起始点的y坐标2274,差值为126。这样就能得到导航栏的高度。 过这个命令的正确性依赖于具体的输出格式,可能在同设备或系统版本上有所同。因此,可能需要用户手动检查dumpsys的输出,并调整相应的解析方式。 总结: 代码解释部分: decorView.getRootWindowInsets()获取窗口的嵌入区域信息,包括系统UI如导航栏。getInsetsIgnoringVisibility(Type.navigationBars())返回导航栏的嵌入尺寸,考虑其可见性,最后取bottom得到底部的高度。 adb命令部分: 需要通过dumpsys window命令解析导航栏的尺寸,或者获取系统资源中的导航栏高度。例如: adb shell dumpsys window displays | grep -A 10 'Display:' 然后在输出中查找导航栏的frame信息,手动计算高度。或者更自动化的命令可能需要更复杂的解析,但可能通用。例如: adb shell dumpsys window displays | awk '/NavigationBar/ {gsub(/.*\[|\].*/, "", $4); split($4, a, /,|\[|\]/); print a[4]-a[2]}' 过可能需要根据实际输出调整。或者,更简单的命令是: adb shell wm size 和 adb shell wm overscan 的组合,但这可能直接给出导航栏高度。 另外,查看系统资源的方式: 导航栏的高度通常存储在系统的dimen资源中,可以使用以下命令获取: adb shell dumpsys activity com.android.systemui | grep navigation_bar_height 这可能太直接。或者,使用: adb shell getprop ro.navigationbar.height 如果设备支持的话。有些设备可能没有这个属性。 最终,可能最可靠的方式是结合dumpsys window的输出,手动查找导航栏的frame值,并计算高度。例如: 运行: adb shell dumpsys window displays 然后查找类似"InsetsSource: type=NAVIGATION_BAR frame=[0,2274][1080,2400]"的行,计算高度为2400-2274=126,即导航栏高度为126像素。 因此,对应的adb命令可能无法直接得到数值,但可以通过解析输出中的frame值来得到。例如,使用: adb shell dumpsys window displays | grep NavigationBar -A 1 | grep frame= | cut -d']' -f1 | cut -d',' -f4 | tr -d '[]' 然后计算结束Y坐标减去起始Y坐标。过具体的命令可能需要更复杂的处理,比如使用sed或awk来提取数值。 例如,使用以下命令组合: adb shell dumpsys window displays | grep -A 1 'type=NAVIGATION_BAR' | grep 'frame=' | sed -E 's/.*\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\].*/\4-\2/' | bc 这个命令的作用是提取frame的四个数值,并计算第四个(结束Y)减去第二个(起始Y),得到高度。例如,如果frame是[0,2274][1080,2400],则第四个数值是2400,第二个是2274,相减得到126,即导航栏高度。 过,这个命令的正确性依赖于sed的正则表达式是否能够正确匹配输出中的frame值。同的设备可能有同的输出格式,因此可能需要调整正则表达式。 综上所述,虽然可以提供个可能的adb命令,但需要用户根据实际输出来调整解析方式。因此,在回答中可能需要给出两种方法:手动解析dumpsys window displays的输出,或者尝试使用命令组合自动提取。</think>### 代码详解 这段代码 `decorView.getRootWindowInsets().getInsetsIgnoringVisibility(navigationBars()).bottom` 用于获取导航栏的高度,具体逻辑如下: 1. **`decorView`** Android 窗口的根视图(`DecorView`),代表当前窗口的最顶层布局。 2. **`getRootWindowInsets()`** 获取与根视图关联的 `WindowInsets` 对象,包含窗口嵌入区域信息(如状态栏、导航栏等系统 UI 的尺寸)。 3. **`getInsetsIgnoringVisibility(navigationBars())`** - `navigationBars()`:指定要获取的系统 UI 类型为导航栏。 - `getInsetsIgnoringVisibility()`:返回导航栏的嵌入尺寸,**即使导航栏当前处于隐藏状态**(例如全屏模式下)。 4. **`.bottom`** 提取导航栏的底部高度值(单位为像素)。 --- ### 通过 ADB 获取相同值的命令 导航栏高度通常存储于系统 UI 的布局信息中。可通过以下命令获取: ```bash adb shell dumpsys window displays | grep -A 1 'type=NAVIGATION_BAR' | grep 'frame=' | sed -E 's/.*\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\].*/\4-\2/' | bc ``` #### 命令解释: 1. **`adb shell dumpsys window displays`** 输出当前窗口的显示信息,包含导航栏的布局参数。 2. **`grep -A 1 'type=NAVIGATION_BAR'`** 定位到导航栏的 `InsetsSource` 段落。 3. **`grep 'frame='`** 提取包含 `frame` 坐标的行(例如 `frame=[0,2274][1080,2400]`)。 4. **`sed` 正则提取并计算高度** 通过正则表达式提取 `frame` 的 Y 轴坐标,计算 `结束Y - 起始Y`(如 `2400 - 2274 = 126`)。 #### 手动验证步骤: 1. 运行 `adb shell dumpsys window displays`。 2. 查找 `InsetsSource: type=NAVIGATION_BAR` 段落。 3. 记录 `frame=[x1,y1][x2,y2]` 中的 `y2 - y1` 即为导航栏高度。 --- ### 注意事项 - 同设备或系统版本的输出格式可能略有差异,需适当调整命令中的正则表达式。 - 若设备未启用导航栏(如使用手势操作),返回值可能为 `0`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值