Android 11 api变更及适配

Android 11 api变更及适配

官方文档 (可能无法访问)

Android 11 不断临近,最近看看 google 的 Android11 api 变更~~~
同时记录下来,方便日后快速适配

对应用的影响分为两部分:

  1. targetSdkVersion>=30 才有影响的 api
  2. 所有应用都有影响的 api

主要的权限变更

无论从分区存储,还是权限变更,Android 11 对于用户来说,隐私保护做的更好
但是对于开发者来说,又需要适配权限变更了

  1. 分区存储
  2. 权限请求临时授权
  3. 自动重置权限
  4. 定位权限细分为:后台定位权限前台定位权限
  5. 软件包可见性:需要显示定义与本应用交互的其它应用
  6. 前台服务限制:摄像头、麦克风、位置信息权限限制

1. 分区存储变更

分区存储对于一些相机、录像、共享文件、工具类的App影响应该挺大

以 Android 11 为目标版本

在之前的 Android 10 中,只要在 Application 中使用 android:requestLegacyExternalStorage="true" 即可停用分区存储(之前就是这么操作的,为了兼容sdk)

在Android11 上,即使 Application 配置了也没有效果

如果应用是从旧版本升级到新版本,可以在 Application 配置 android:preserveLegacyExternalStorage="true" 暂时不使用分区存储

注意:不要依赖android:preserveLegacyExternalStorage配置,因为卸载重装或者是全新安装app,即使配置了这个参数,也必须使用分区存储

如果要升级 targetSdkVersion,必须确保使用了分区存储,否则不要升级目标版本

但是

如果app是工具类或者因为某些原因必须要在任意位置读写,在Android 11 上也是有办法的

Android 11 提供了一个新的权限: MANAGE_EXTERNAL_STORAGE

  • 首先在清单中声明: MANAGE_EXTERNAL_STORAGE
  • 然后使用 intent: ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION 跳转到设置页面

但即便是使用了 MANAGE_EXTERNAL_STORAGE 权限并且授予,也依旧无法访问 /sdcard/Android 目录,这样的变更对垃圾清理类的应用影响很大

如果需要清理其他app的缓存空间:

  • 调用 ACTION_MANAGE_STORAGE intent 操作检查可用空间。
  • 调用 ACTION_CLEAR_APP_CACHE intent 操作清除所有缓存。

需要注意的是:如果应用具有 OTG 功能,需要使用外部摄像头、麦克风、U盘或者传感器等,则需要申请 MANAGE_EXTERNAL_STORAGE 权限才能访问 OTG 设备

影响:

之前开发过使用 otg 接入外部摄像头的 app ,为了适配 11 ,看来是要申请MANAGE_EXTERNAL_STORAGE权限了
以后垃圾清理估计只能依靠系统自带的 安全管家 应用了
如果非必须,建议使用分区存储,跳转到设置页面要求用户开启权限的做法,显然不够友好

另外, Android 11 如果访问的是应用内私有目录,或者应用具有 READ_EXTERNAL_STORAGE 权限,是可以直接使用 File() fopen 访问文件的

任意 targetSdkVersion 的app运行在Android11 系统

只要运行在 Android 11 上,请求 READ_EXTERNAL_STORAGE 权限,用户会看到更详细的权限请求提示

仅仅是提示更改,授予后依旧可以使用旧 Api 也就是 new File("xxxxx") 对文件进行访问的

2. 权限请求临时授权

权限请求临时授权,对目前的应用来说,影响并不大。
现今的应用在使用某个功能时,基本都会首先检查并请求权限

但如果应用是在最初启动时便把app涉及的所有权限全都请求了,那么在每次进入app的时候体验就不够友好了

3. 自动重置权限

如果 targetSdkVersion 为 Android 11 ,且应用好几个月未与用户交互,则系统会自动重置敏感权限。

自动重置权限对服务型app有很大影响,这些程序可能需要长期在后台运行而不与用户交互,如:同步备份类app

但对一般app来说影响并不大,如果应用几个月未交互,基本可以断定用户长时间未使用。此时重置权限显然无可厚非

如果开发的app 恰好是同步类,备份类应用,需要长期后台运行:android 11 提供了一个intent: Intent.ACTION_AUTO_REVOKE_PERMISSIONS ,使用此 intent 跳转到设置页面,设置页面有一个开关,可以关闭重置权限功能

伪代码:

//Intent intent =  new Intent(Intent.ACTION_AUTO_REVOKE_PERMISSIONS);
// 进入app详情页-》权限页-》关闭重置权限功能
Intent intent =  new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);    
startActivity(intent); 

同时 PackageManager 提供了一个方法: isAutoRevokeWhitelisted() 来确定用户是否已经停用了重置功能

4. 定位权限细分

目前请求定位权限,在android 11上不会再有 一直允许 的选项,如果地图类应用需要一直后台获取位置信息,要根据以下情况做适配

以android 11 为目标版本

需要自定义界面,提示用户,并跳转到系统的设置页面,由用户手动打开

目标版本为 android 10 或以下

请求权限时,不需要自定义提示页面,授权框内有一个选项,用户如果点击选项,会自动跳转到权限选项页面

相当于一个android 11 以后,需要自己定义界面,要求用户手动打开后台位置权限,然后使用按钮触发跳转到权限页面

5. 软件列表可见性

此变更应该会影响一些统计类的app,如:统计应用使用时长的app

如果应用以 android 11 为目标平台,则会受到此限制

现在 app 需要在清单文件中配置 <queries> 元素,才能与这些元素中指定的 app 进行交互。否则无法获取 已安装应用列表 和交互

<queries> 元素可以设定三种内容:包名Intent,Provider

示例:

通过包名指定要交互的 app:

    <queries>
        <package android:name="com.example.store" />
        <package android:name="com.example.services" />
    </queries>

通过 Intent 指定要交互的app:

    <queries>
        <intent>
            <action android:name="android.intent.action.SEND" />
            <data android:mimeType="image/jpeg" />
        </intent>
    </queries>

通过 Provider 指定要交互的app:

    <queries>
        <provider android:authorities="com.example.settings.files" />
    </queries>

只有通过这种方式指定之后,app 才能与另外的应用进行交互

也有例外,在下列例外的情况下,不需要 <queries> 也可以与其他应用交互:

  • 需要交互的目标应用是自己
  • 使用 Intent 启动 Activity
  • 应用与系统软件包交互(如提供文件)
  • 目标应用安装了自己:如果你的应用是使用应用宝app下载安装的,那你与应用宝app可以直接交互
  • 第三方应用使用 startActivityForResult 启动自己(第三方应用自动变为可见)
  • 第三方应用启动或绑定自己应用的某个服务(第三方应用自动变为可见)
  • 第三方应用向自己应用的内容提供程序(Provider)发出请求(第三方应用自动变为可见)
  • 自己的应用是输入法(第三方应用自动变为可见)

如果应用必须要获取所有的已安装应用怎么办(一些用机时长统计的app获取用的到):

在 android 11 上需要申请:QUERY_ALL_PACKAGES 权限

6. Service 使用 摄像头、麦克风、位置信息权限限制

如果app后台启动了一个前台Service,那么摄像头和麦克风不可用,位置权限根据是否授予 ACCESS_BACKGROUND_LOCATION 来决定

在service 中使用 摄像头、麦克风、位置信息现在会受到限制,

这个限制根据服务位于前台还是后台而有所不同

定义 Service 位于前台还是后台的标准:

  • 该应用的所有 Activity 目前对用户都不可见。
  • 该应用目前未运行任何在它的某个 Activity 对用户可见时启动的前台服务。

豁免:下列的情况,不会受到后台运行模式的影响,从而限制摄像头或麦克风或后台位置信息使用权限

  • 服务是系统组件启动的(无障碍、设备管理器)
  • 服务通过与应用微件进行交互启动(桌面天气组件、桌面小工具)
  • 服务与通知进行交互启动
  • 服务是通过其他应用发送的 PendingIntent 启动的
  • 该服务由作为在设备所有者模式下运行的设备政策控制器的应用启动(这里我也没有很理解是什么意思?是通过设备管理器启动吗,一般应用应该涉及不到)
  • 服务由提供: VoiceInteractionService 的应用启动 (也就是语音助手启动)
  • 该服务由具有 START_ACTIVITIES_FROM_BACKGROUND 特权的应用启动。(START_ACTIVITIES_FROM_BACKGROUND 权限为Android10新增的权限,普通应用基本不会授予这个权限)

前台服务使用摄像头、麦克风或定位权限

对于前台服务,如果要在服务中使用这三种权限,需要在清单文件中首先声明(根据需要可以删减android:foregroundServiceType中的类型):

<manifest>
    ...
    <service ...
        android:foregroundServiceType="location|camera|microphone" />
</manifest>

然后在使用的时候指定这个前台服务需要使用的服务类型:

val notification: Notification = ...;
Service.startForeground(notification, FOREGROUND_SERVICE_TYPE_LOCATION)

代码指定服务类型如下:

  • FOREGROUND_SERVICE_TYPE_LOCATION
  • FOREGROUND_SERVICE_TYPE_CAMERA
  • FOREGROUND_SERVICE_TYPE_MICROPHONE

其它变更

  1. 随机mac 地址

修改了随机 mac 地址的分配方式

  1. 目标版本为 android 11 将无法获取设备mac 地址,例如: NetworkInterface.getHardwareAddress() 方法

  2. 数据访问审核

可以通过接口查看到 线程的堆栈轨迹 ,数据调用回调

  1. 系统提醒窗口变更

影响需要全局浮窗的应用,权限:SYSTEM_ALERT_WINDOW

  1. 电话号码(细分手机号码和手机状态权限)

现在应用无法通过申请 READ_PHONE_STATE 直接获取手机号了,新增 READ_PHONE_NUMBERS 权限。如果要获取手机号,需要申请这个权限
接口:TelephonyManager 类和 TelecomManager 类中的 getLine1Number()
除了获取手机号需要新权限外,其它手机状态信息依旧使用 READ_PHONE_STATE 权限

  1. 5G api 支持

提供接口用来判断用户是否位于5g网络,需要 READ_PHONE_STATE 权限
方法: TelephonyManager.listen(callback, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)

  1. 后台无法弹出自定义Toast(注意限定条件:后台、自定义)

如果位于后台,只能弹出原生 Toast。如果不位于后台,可以弹出自定义Toast
Toast.getView() 方法废弃,现在会返回空值

  1. 提供一个新的组件功能,可以使用电源菜单键快速控制开关

创建并声明 ControlsProviderService 然后实现。智能家居类app很实用

  1. 内嵌式的自动填充功能(目前已经有弹窗式的,即点击用户密码输入框,系统弹窗选择保存的用户密码)

  2. 调用相机无法使第三方相机app响应(对相机类app有影响)

如果必须调用第三方相机,需要使用包名或者组件指定

  1. 应用打包必须 4 字节对齐

  2. 必须使用 v2 签名,否则无法安装

  3. 更新了非sdk接口限制列表

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://zwc365.com/2020/09/09/android-11-release-info

Buy me a cup of coffee ☕.