Android 11 看我就行了

      Android 11 开发者预览版计划从 2020 年 2 月启动,到向 AOSP 和 OEM 提供最终的公开版本时结束,最终版本预计将于 2020 年第 3 季度发布。那就是说等我们真正用上正式版的时间大概是九、十月份,不过因为疫情原因可能会有些许推迟,希望疫情能早日结束吧!

附上谷歌官网放出的时间线:

Android 11 看我就行了_第1张图片

      很多小伙伴说刚刚用上了Android 10完成了版本适配,然而Android 11就已经到来了,安卓仔表示太难了...

     虽然有些不情愿,但是想着系统版本升级肯定是为了Android系统更加完善,想想还是挺好的一件事。那就让我们一起来看看这次Android 11给我们带来了什么吧 !

版本特性

对于用户来说有哪些重要更新呢?

  • 无缝更新

    无缝更新会在Android 11 系统启动时需要虚拟A / B两个分区以减少由系统更新引起的停机时间,并提供一种在更新出现问题时可以恢复的机制。

    Android系统更新时手机会启动进入恢复状态,并且可能会停留在“安装系统更新”屏幕上长达25分钟。这将导致大量的停机时间,在此期间您将无法运行任何APP,查看任何短信或接听任何电话。发生停机是因为更新系统文件时需要使系统分区脱机,但是无缝更新系统通使用两个系统分区来解决这个问题。

  • 优化5G支持

    Android 11 带来了全新的链接 API,用以支持 5G 网络,因此可以充分利用 5G 提供的改进的速度和延迟,如在检测到高质量网络时,使 APP 自动提供高质量视频。

    动态计量API

    使用此API,你可以检查连接是否未计量,如果是,则提供更高的分辨率或质量,从而可能使用更多数据。扩展了API的范围,使其包含蜂窝网络,以便您可以识别运营商在连接到运营商的5G网络时提供真正未计量数据的用户。

    带宽估算器API

    已更新了适用于5G的API,以使其更易于检查下行/上行带宽,而无需轮询网络或计算您自己的估算值。如果调制解调器不提供支持,我们将基于当前连接进行默认估算。

  • 打开飞行模式,蓝牙耳机不断连

    在 Android 11 开发者预览版中,用户连接蓝牙耳机后,开启飞行模式依然支持蓝牙不断连,并且还有消息提醒。

  • 滚动截屏/长截图

    虽然很多手机厂商深度定制系统中早已集成,但是原生Android 11系统总算是支持了,也不错了。

  • 电池共享

    电池共享功能类似于“反向无线充电”,用户可以与其他兼容设备(包括智能手表,耳机等)共享 Pixel 的电池。

  • 在快速回复中使用富媒体

    从 Android 11 开始,用户可以在快速回复中插入图片和其他富媒体内容。

  • 悬浮聊天气泡

    Android 11 的新增了悬浮聊天气泡功能,只要 APP 使用全新的 API,就可以将正在进行的对话以气泡的形式悬浮在屏幕中。

  • 隐私和权限

    Android 11 新增了关于位置、麦克风和摄像头的一次性权限许可。也就是说,获得一次性权限许可的 APP 在下次使用时,依然要询问用户获取授权。

  • 屏幕录像

    屏幕录像曾在 Android 10 的早期版本中出现,但随后被删除了。随着 Android 11 开发者预览版的推出,屏幕录像功能又再次上线。

对于开发人员适配需要注意哪些呢?

  • 存储机制更新

  • 权限更新

  • 应用包可见性

  • 前台服务类型

  • 消息框(Toast)的更新

  • 支持并发使用多个摄像头

  • 其他一些新功能

附官网重大隐私权变更图:

Android 11 看我就行了_第2张图片

存储机制更新

分区存储强制执行

Android10 就开始引进了分区存储功能,分区存储主要是将共享存储去分为各个集合,并限制应用对此区域随意访问

  • 清晰的应用归属

  • 对应用数据的保护

  • 对用户数据的保护

Android 11 看我就行了_第3张图片

        大家都知道Android10 提供了requestLegacyExternalStorage = true 选择退出分区存储,在Android11中就将会强制使用分区存储了。

不过官方为了给开发者更多时间进行测试,以 Android 10(API 级别 29)为目标平台的应用仍可请求 requestLegacyExternalStorage 属性。应用可以利用此标记暂时停用与分区存储相关的变更,例如授予对不同目录和不同类型的媒体文件的访问权限。当您将应用更新为以 Android 11 为目标平台后,系统会忽略 requestLegacyExternalStorage 标记。

保持与 Android 10 的兼容性

如果应用在 Android 10 设备上运行时选择退出分区存储,建议您继续在应用的清单文件中将 requestLegacyExternalStorage 设为 true。这样,应用就可以在运行 Android 10 的设备上继续按预期运行。

将数据迁移到使用分区存储时可见的目录

如果您的应用使用旧版存储模型且之前以 Android 10 或更低版本为目标平台,您可能会将数据存储到启用分区存储模型后您的应用无法访问的目录中。在以 Android 11 为目标平台之前,请将数据迁移到与分区存储兼容的目录。在大多数情况下,您可以将数据迁移到您的应用专用目录。

如果您有需要迁移的数据,当用户升级到以 Android 11 为目标平台的新版应用时,可以保留旧版存储模型。这样,用户就可以保留对您的应用之前用于保存数据的目录中存储的应用数据的访问权限。如需启用旧版存储模型以进行升级,请在应用的清单中将 preserveLegacyExternalStorage 属性设为 true。

注意:大多数应用都不需要使用 preserveLegacyExternalStorage。此标记仅适用于这样一种情况:您将应用数据迁移到了与分区存储兼容的位置,并且希望用户在更新您的应用时保留对数据的访问权限。使用此标记会导致更难以测试分区存储对您应用的用户有何影响,因为当用户更新您的应用时,它会继续使用旧版存储模型。

如果您使用 preserveLegacyExternalStorage,旧版存储模型只在用户卸载您的应用之前保持有效。如果用户在搭载 Android 11 的设备上安装或重新安装您的应用,那么无论 preserveLegacyExternalStorage 的值是什么,您的应用都无法停用分区存储模型。

测试分区存储如需在您的应用中启用分区存储,而不考虑应用的目标 SDK 版本和清单标记值,请启用以下应用兼容性标记:

DEFAULT_SCOPED_STORAGE(默认情况下,对所有应用处于启用状态) FORCE_ENABLE_SCOPED_STORAGE(默认情况下,对所有应用处于停用状态) 如需停用分区存储而改用旧版存储模型,请取消设置这两个标记。

媒体文件访问权限

存储权限

  • 针对所有应用

    存储(Storage)运行时权限已更名为文件和媒体(Files & Media)

  • 针对Android11为目标平台的应用

    WRITE_EXTERNALSTORAGE 和WRITE_MEDIA_STORAGE不再提供任何其他访问权限

管理设备存储空间

如果您的应用是文件管理器应用并且在 Android 11 上运行,它就不能再删除其他应用的缓存文件,即使您的应用具有所有文件访问权限也是如此。相反,您的应用应执行以下操作:

通过调用 ACTION_MANAGE_STORAGE intent 操作检查可用空间。如果设备上的可用空间不足,请提示用户同意让您的应用清除所有缓存。为此,请调用 ACTION_CLEAR_APP_CACHE intent 操作。

注意:ACTION_CLEAR_APP_CACHE intent 操作会严重影响设备的电池续航时间,并且可能会从设备上移除大量的文件。

MediaStore API 和 批量处理

Android 11中未经过用户同意是不能再删除其他应用的文件,即使您的应用具有所有文件访问权限也是如此。

  • 允许进行批量编辑/删除

  • MediaStore API 中添加了多种方法

    createWriteRequest()

    用户向应用授予对指定媒体文件组的写入访问权限的请求。

    createFavoriteRequest()

    用户将设备上指定的媒体文件标记为“收藏”的请求。对该文件具有读取访问权限的任何应用都可以看到用户已将该文件标记为“收藏”。

    createTrashRequest()

    用户将指定的媒体文件放入设备垃圾箱的请求。垃圾箱中的内容会在系统定义的时间段后被永久删除。

    createDeleteRequest()

    用户立即永久删除指定的媒体文件(而不是先将其放入垃圾箱)的请求。

申请媒体文件的批量操作权限如下:(感谢google团队分享)

Android 11 看我就行了_第4张图片

使用原始路径访问文件

Android 10是不允许直接使用文件路径这种方式访问的,但是有些第三方框架调用native方法很难避免直接使用文件路径的方式,所以Android 11 开始允许具有 READ_EXTERNAL_STORAGE 权限的应用读取使用直接文件路径和原生库的设备媒体文件。借助此功能,您的应用与第三方媒体库会配合使用得更顺畅。

如果您使用直接文件路径和原生库,建议您在应用的清单文件中将 requestLegacyExternalStorage 设置为 true,从而选择停用分区存储。这样就能保证各个版本之前的兼容了。

需要注意的地方:

  • 直接访问路径是基于MediaStore的,直接使用必定会造成性能下降,对性能的影响取决于I/O模式

  • 打开和第一次读取相对来说性能影响会比较明显

  • 如果第三方库需要直接访问路径的时候才考虑用它,而为了性能考虑还是尽可能的使用MediaStore API

访问其他应用的私有目录

在 Android 11 上,应用无法再访问外部存储设备中的任何其他应用的专用于特定应用的目录中的文件。

文档访问限制

为让开发者有时间进行测试,以下与存储访问框架 (SAF) 相关的变更只有在应用以 Android 11 为目标平台时才会生效。

  • 访问目录

    您无法再使用 ACTION_OPEN_DOCUMENT_TREE intent 操作请求访问以下目录:

    内部存储卷的根目录。

    设备制造商认为可靠的各个 SD 卡卷的根目录,无论该卡是模拟卡还是可移除的卡。Download 目录。

  • 访问文件

    您无法再使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT intent 操作请求用户从以下目录中选择单独的文件:

    Android/data/ 目录及其所有子目录。

    Android/obb/ 目录及其所有子目录。

所有文件访问权限

如果你的应用需要访问大量共享存储区的文件可以通过以下方式获取“所有文件访问权限”:

  • 声明 MANAGE_EXTERNAL_STORAGE 权限。

  • 使用 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent

操作将用户引导至一个系统设置页面,在该页面上,用户可以为您的应用启用以下选项:授予所有文件的管理权限。

“所有文件访问权限”可授予以下权限:

  • 对共享的存储空间内所有文件的读写访问权限。

  • 对 MediaStore.Files 表的内容的访问权限。

该权限适用于文件管理和备份还原等批量处理功能的应用使用的,如果您只需要访问一个文件和几个文件这样的功能时使用存储访问框架就可以而不是获取“所有文件访问权限”,期待Google play作出更进一步的规范,明确合规/不合规的用例。

权限更新

随着用户更加在意应用的隐私性,在Android 11 中,用户能够针对位置信息、麦克风和摄像头指定更精细的权限

一次性权限

Android 11 中加入了一次性权限,每当应用请求与位置信息、麦克风或摄像头相关的权限时,面向用户的权限对话框就会包含仅限这一次选项。如果用户在对话框中选择此选项,系统会向应用授予临时的单次授权。当使用完功能之后,系统就会回收此次权限。

然后,应用可以在一段时间内访问相关数据,具体时间取决于应用的行为和用户的操作:

  • 当应用的 Activity 可见时,应用可以访问相关数据。

  • 如果用户将应用转为后台运行,应用可以在短时间内继续访问相关数据。

  • 如果您在 Activity 可见时启动了一项前台服务,并且用户随后将您的应用转到后台,那么您的应用可以继续访问相关数据,直到该前台服务停止。

  • 如果用户撤消单次授权(例如在系统设置中撤消),无论您是否启动了前台服务,应用都无法访问相关数据。与任何权限一样,如果用户撤消了应用的单次授权,应用进程就会终止。

关于适配:无需任何改动!!!

如果您的应用已遵循与权限相关的最佳做法,您无需更改应用即可支持单次授权。

需要特别指出的是,在尝试访问受某项权限保护的信息之前,请务必检查应用是否具有该权限;如果应用首次请求权限,或者如果用户已撤消权限,请完成以下流程:

1.调用 shouldShowRequestPermissionRationale()。如果此方法返回 true,请在您的应用中显示一个界面元素,向用户说明您的应用为何需要获取权限。

2.请求权限。

Android 11 看我就行了_第5张图片

再次请求权限时显示的对话框

当用户下次打开应用并且应用随后再次请求与位置信息、麦克风或摄像头相关的权限时,系统会再次提示用户。

请求权限的流程(感谢google团队分享):

第一次申请权限默认是不会有权限的调用原因,当用户第一次拒绝了在这个回调里解释其权限调用原因,当用户知道了原因,再次申请权限系统就会调shouldShowRequestPermissionRationale() = true,开发者就可以在这个判断里面弹出权限的解释并让用户决定是否继续申请权限调取系统权限框或者(no thanks),系统的权限框调用了二次都拒绝了的话,就再也不会显示了。

Android 11 看我就行了_第6张图片

Android 11 看我就行了_第7张图片

权限对话框的可见性

Android 11 不建议重复请求特定权限组中的权限。在应用安装到设备上后,如果用户在使用过程中两次针对某项特定的权限点按拒绝,此操作表示其希望以后请求相应权限组中的该权限时“不再询问”。

系统还对与点按拒绝选项相仿的操作的响应行为做出了定义:

如果用户按返回按钮关闭权限对话框,此操作不算作“拒绝”操作。

如果用户使用 requestPermissions() 从您的应用转到系统设置,然后按返回按钮,此操作就算作“拒绝”操作。

电话号码

Android 11 更改了您的应用在读取电话号码时使用的与电话相关的权限。

如果您的应用以 Android 11 为目标平台,并且需要访问以下列表中显示的电话号码 API,则必须请求 READ_PHONE_NUMBERS 权限,而不是 READ_PHONE_STATE 权限。

TelephonyManager 类和 TelecomManager 类中的 getLine1Number() 方法。

TelephonyManager 类中不受支持的 getMsisdn() 方法。

如果您的应用声明 READ_PHONE_STATE 以调用前面列表中的方法以外的方法,您可以继续在所有 Android 版本中请求 READ_PHONE_STATE。不过,如果您仅对前面列表中的方法使用 READ_PHONE_STATE 权限,请按以下方式更新您的清单文件:

更改 READ_PHONE_STATE 的声明,以使您的应用仅在 Android 10(API 级别 29)及更低版本中使用该权限。

添加 READ_PHONE_NUMBERS 权限。

以下清单声明代码段演示了此过程:


    
    
    



位置权限

关于位置权限有前台位置权限和后台位置权限,在目标版本Android R以下版本的时候默认是申请前台位置权限的时候就同时申请了后台位置权限,而Android R开始是不能同时申请的,只能先申请前台位置权限再申请后台位置权限。

后台位置信息访问权限

Android 11 通过以下方法进一步强调了用户对位置信息的控制:添加了单次授权,并移除了用户通过应用内提示授予 ACCESS_BACKGROUND_LOCATION 权限的功能

  • 如果您的应用以 Android 11 为目标平台,您可以创建自定义界面,向用户解释您的应用为什么需要 ACCESS_BACKGROUND_LOCATION 权限。

  • 如果您的应用以较低版本为目标平台,您必须使用系统提供的界面,该界面中指出您的应用需要在后台访问位置信息,即使您的应用没有被使用。

创建自定义界面

如果您的应用以 Android 11 为目标平台,您可以显示自定义界面,用于更清楚地向用户解释您的应用为什么需要 ACCESS_BACKGROUND_LOCATION 权限。

请遵循本部分中的准则,创建用户更容易理解的界面。

说明应用对后台位置信息的要求 如需在您的应用中请求 ACCESS_BACKGROUND_LOCATION,您的应用必须先获取前台位置权限,即 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION。如果您尝试同时请求 ACCESS_BACKGROUND_LOCATION 和其他任何权限,系统会抛出异常。

当有了前台位置权限后,你需要弹出为什么请求后台位置权限的原因的对话框:

  • 授予权限。如果用户选择此选项,就对 ACCESS_BACKGROUND_LOCATION 发出权限请求。系统会将用户定向到系统设置,以完成授予此权限的过程。

    为了帮助用户在设置中找到用于授予 ACCESS_BACKGROUND_LOCATION 权限的选项,您可以在应用的界面中为相应的设置选项添加用户可见的标签。getBackgroundPermissionOptionLabel() 方法可提供根据用户的设备语言偏好设置进行了本地化的标签。

  • 不授予权限。如果用户不授予权限,他们应能够继续使用应用。如果用户选择此选项,应用可以正常继续运行,但可能会让用户离开需要后台位置信息访问权限的功能。

请注意,即使在向应用授予 ACCESS_BACKGROUND_LOCATION 权限后,用户也可以在系统设置中将其位置信息访问权限更改为仅在使用该应用时允许或每次都询问。用户也可以完全拒绝应用访问位置信息。

根据需要将用户定向到系统设置

如果用户同意向您的应用授予 ACCESS_BACKGROUND_LOCATION 权限,您的应用应将用户定向系统设置里去选择开启权限

重定向到系统设置受限制

在应用让用户转到其在系统设置中的权限页面后,用户可能会选择始终允许以外的位置信息访问权限级别,如拒绝。Android 11 最多允许应用将用户从一个界面引导至系统设置两次。因此,请务必清楚地向用户解释应用功能为什么需要在后台访问位置信息。

当应用达到此限制时,您仍然可以调用一个 intent,以将用户定向到应用在系统设置中的信息页面。在该页面中,用户可以转到应用的权限页面。如需加载应用信息页面,请使用 Settings.ACTION_APPLICATION_DETAILS_SETTINGS intent 操作。

应用包可见性

Android 11 更改了应用查询同一设备上的其他已安装应用以及与之交互的方式。如果您的应用以 Android 11 为目标平台,您可能需要在应用的清单文件中添加  元素,以便系统了解应向您的应用显示哪些其他应用。

Android 11 看我就行了_第8张图片

查询特定软件包及与之交互

如果您知道要查询或与之交互的一组特定应用(例如,与您的应用集成的应用或您使用其服务的应用),请将其软件包名称添加到  标记内的一组  元素中:


    
        
        
    
    ...



在给定 intent 过滤器的情况下查询应用及与之交互

您的应用可能需要查询一组具有特定用途的应用或与之交互,但您可能不知道要添加的具体软件包名称。在这种情况下,您可以在  标记中列出 intent 过滤器签名。然后,您的应用就可以发现具有匹配的  标记的应用。

以下示例允许您的应用看到支持 JPEG 图片共享功能的已安装应用:


    
        
            
            
        
    
    ...



查询所有应用及与之交互

在极少数情况下,您的应用可能需要查询设备上的所有已安装应用或与之交互,不管这些应用包含哪些组件。例如,Google Play 等应用商店。为了允许您的应用看到其他所有已安装应用,Android 11 引入了 QUERY_ALL_PACKAGES 权限。

在即将推出的开发者预览版中,Google Play 会为需要此权限的应用提供相关指南,敬请期待。

不受变更影响的用例

以下列表包含几个不需要  声明的用例示例:

  • 目标应用是您自己的应用。

  • 您可以使用隐式 intent 启动 Activity。您的应用可能会限制其使用隐式 intent 与其他应用交互的方式。

  • 您的应用与实现 Android 核心功能的某些系统软件包(如媒体提供程序)交互。其他应用期望从您的应用获得结果。当您的应用是内容提供程序时、当其他应用通过调用 startActivityForResult() 调用您的应用时,以及当您的应用是其他应用尝试启动或连接到的服务时,会出现这种情况。

例如,如果其他应用向您应用中的内容提供程序发出请求,系统将允许您的应用看到该其他应用。

在非浏览器应用中启动网络 intent

如果你想通过应用打开一个url,但是又不想打开的方式框里出现通过浏览器打开选项,则可以按照如下方式实现

Android 11 看我就行了_第9张图片

如果手机中除了浏览器外没有适合打开该url的方式,则会抛出ActivityNotFoundException异常,可以获取到这个异常进行下一步的处理。

前台服务类型

从 Android 9 开始,应用仅限于在前台访问摄像头和麦克风。为了进一步保护用户,Android 11 更改了前台服务访问摄像头和麦克风相关数据的方式。如果您的应用以 Android 11 为目标平台并且在某项前台服务中访问这些类型的数据,您需要在该前台服务的声明的 foregroundServiceType 属性中添加新的 camera 和 microphone 类型。

使用位置信息和摄像头的示例

如果应用中的某项前台服务需要访问与设备的位置信息和摄像头相关的数据,请按以下代码段所示声明该服务:


    ...
    



使用位置信息、摄像头和麦克风的示例

如果某项前台服务需要访问位置信息、摄像头和麦克风,请按以下代码段所示声明该服务:


    ...
    



消息框(Toast)的更新

Android 11 为了保护用户而弃用了自定义消息框视图。为了给开发者更多的时间来适应这些变更,只有在您的应用以 Android 11 为目标平台时,这些变更才会生效。

需要注意的地方:

  • 如果包含自定义视图(使用了setView())的消息框是以 Android 11 为目标平台的应用从后台发送的,则系统会屏蔽这些消息框。

  • 仍允许使用文本消息框;此类消息框是使用 Toast.makeText() 创建的,并不调用 setView()

  • 如果您希望在消息框(文本消息框或自定义消息框)出现或消失时收到通知,请使用新的 addCallback() 方法。

  • 文本消息框 API 变更(以 Android 11 为目标平台的应用)

     

    以下方法的返回值并不反映实际值,因此不应在您的应用中依赖于它们:

     

    以下方法是空操作,因此您的应用不应使用它们:

     
  •  setMargin()
    
    
      setGravity()
    
    
    
  •  getHorizontalMargin()
    
    
      getVerticalMargin()
    
    
      getGravity()
    
    
      getXOffset()
    
    
      getYOffset()
    
    
    
  •  getView() 方法返回 null
    
    
    

支持并发使用多个摄像头

Android 11 添加了 API 以查询对同时使用多个摄像头(包括前置摄像头和后置摄像头)的支持。

如需在运行应用的设备上检查支持情况,请使用以下方法:

getConcurrentCameraIds() 可返回摄像头 ID 组合 Set,这些组合可与有保证的数据流组合并发进行流式传输(如果它们是由同一应用进程配置的)。

isConcurrentSessionConfigurationSupported() 可查询摄像头设备是否可以并发支持相应的会话配置。

其他一些新功能

更好地支持瀑布屏

Android 11 提供了一些 API 以支持瀑布屏,这是一种无边框的全面屏。这种显示屏被视为刘海屏的变体。现有的 DisplayCutout.getSafeInset…() 方法现在会返回能够避开瀑布区域以及刘海的安全边衬区。如需在瀑布区域中呈现您的应用内容,请执行以下操作:

调用 DisplayCutout.getWaterfallInsets() 以获取瀑布边衬区的精确尺寸。

将窗口布局属性 layoutInDisplayCutoutMode 设为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,以允许窗口延伸到屏幕各个边缘上的刘海和瀑布区域。您必须确保刘海或瀑布区域中没有重要的内容。

合页角度传感器和可折叠设备

使用 Android 11,可以通过以下方法使运行在采用合页式屏幕配置的设备上的应用能够确定合页角度:提供具有 TYPE_HINGE_ANGLE 的新传感器,以及新的 SensorEvent,后者可以监控合页角度,并提供设备的两部分之间的角度测量值。您可以使用这些原始测量值在用户操作设备时执行精细的动画显示。

尽管对于某些类型的应用(例如启动器和壁纸)而言,知道确切的合页角度会很有用,但大多数应用都应该使用 Jetpack 窗口管理器库,通过调用 DeviceState.getPosture() 检索设备状态。

或者,您的应用也可以调用 registerDeviceStateChangeCallback(),以在 DeviceState 更改时收到通知,并在状态发生变化时做出响应。

由于目前市场上已经有且未来还会出现更多不同的窗口和设备配置,因此对设备状态做出响应更加安全可靠。

5G 图标显示

在 Android 11(API 级别“R”)及更高版本中,具有 android.Manifest.permission.READ_PHONE_STATE 权限的应用可以通过 PhoneStateListener.onDisplayInfoChanged() 请求更新电话显示信息,其中包括用于营销和品牌塑造的无线接入技术信息。

这款新 API 提供了适用于不同运营商的各种 5G 图标显示解决方案。支持的技术包括:

  • LTE

  • 采用载波聚合技术的 LTE (LTE+)

  • 高级专业版 LTE (5Ge)

  • NR (5G)

  • 毫米波移动网络频段上的 NR (5G+)


作者:Rain_Shieh
链接:https://juejin.im/post/5ed339546fb9a047a11da81a

关注我获取更多知识或者投稿

你可能感兴趣的:(Android 11 看我就行了)