Android11系统应用兼容适配

一、背景

客户使用了安卓11系统手机,发现应用安装闪退,于是分析,发现需要做升级适配。

二、遇到问题

应用中之前有提供一个手机唯一标识的功能,是通过调用安卓系统接口TelephoneManager 来获取IMEI的,然后再新的系统版本上发现此接口无法获取该信息,

才知道原来安卓也和苹果一样,对于这种信息不再提供给外部三方应用,个人猜测也是基于用户隐私安全考虑,市场上这么多三方应用,如果都通过该系统接口获取到唯一标识,多个三方应用之间再共享数据,则可以将每台手机的用户从各个维度进行用户画像,真的是底裤是什么颜色都可以分析出来。

于是需要自己来实现应用的唯一标识,想到的是应用自己生成uuid,然后再存储到手机中。如果是存储在应用自己的沙盒空间中,对于用户清除数据,或者卸载应用,则会一起清理掉,为了能最大可能地规避这种情况,想像以前一样存储到外部空间中。结果在调试的时候才发现已经有了 存储分区 机制, 很好地限制了三方应用随意乱写入数据,导致卸载应用后,各种残留问题。

参考 址说明: https://open.oppomobile.com/wiki/doc#id=10724

2.1 存储
2.1.1 分区存储
1.1. 背景

Android 11 进一步增强了平台功能,为外部存储设备上的应用和用户数据提供了更好的保护。作为这项工作的一部分,平台引入了进一步的改进,以简化向分区存储的转换。
为了让用户更好地控制自己的文件,保护用户隐私数据,并限制文件混乱情况,Android 11在分区存储基础上限制了应用访问其他应用的文件。
 

分区存储将存储空间分为两部分:

●  公共目录:Downloads、Documents、Pictures 、DCIM、Movies、Music、Ringtones等

    ■ 公共目录的文件在App卸载后,不会删除
    ■ 可以通过SAF、MediaStore接口访问
    ■ 拥有权限,也能通过路径直接访问
●  应用专属目录
    ■ 应用专属目录只能自己直接访问
    ■ App卸载,数据会清除。

关于过度配置 requestLegacyExternalStorage 自己在应用中的调试结果如下:

targetSdkVersion = 29,  requestLegacyExternalStorage=true, 存储访问表现还和以前一样,卸载应用后再次重装对于通过contentProvider中之前插入的数据,后面还是能访问到。

插入数据:

读取访问数据:

targetSdkVersion = 29,  requestLegacyExternalStorage=false, 这种情况,以及targetSdkVersion = 30 之后,存储分区机制生效,卸载应用再次重装无法访问之前写入到媒体库中的数据。

另外对于文件的访问方式也是如此,使用 Environment.getExternalStoragePublicDirectory 这个接口虽然不会抛出异常,文件和目录都存在,但是正式访问读取文件时

会 没有权限,最终导致FileNotFound异常:

尝试多次无果之后,最终无奈放弃,卸载重装的应用只能当新用户处理,虽然还是同一台手机。对于安卓这种机制的完善还是很欢迎的,毕竟应用是在不断吃磁盘空间的,如果卸载应用还有残留,那确实体验很不好。

—————————————–补充—————————-

在后续的适配中还遇到了其他问题,最终找到的原因还是和 存储分区机制有关。

1、当targetSdk 改为29 以及以上,即安卓10 开始,使用webview 通过 input 标签获取到 照片或者视频文件进行上传时,会出现如下 错:

Err_Access_Denied ,  一看就是权限问题,但是实际上文件数据已经填充到 input 标签了,所以刚开始自己怀疑是否是和调用后台的接口由关系。但是调试过程中发现将targetSdk 调整到28 却能够正常,将问题还是聚焦在了安卓版本的适配上。但是刚开始一直在找webview 的问题,苦苦没有搜寻到解决方案。然后一个偶然发现有人说过类似问题还是存储分区机制造成的,然后自己就朝着这个方向去了解了。

首先将 argetSdkVersion = 29,  requestLegacyExternalStorage=true,果然问题没有出现,这个就更加坚定了这个 错原因就是因为存储分区机制生效造成。

然后仔细回看了以前写的代码,在给webview回调设置文件数据的时候,居然是先从uri转换成path ,然后又将path转换成了uri 进行设置,也许是当初对于这种绝对路径比较痴迷直观,还是太菜造成的:

最终直接将uri 设置给回调即正常,也不需要将存储分区机制关闭。 因为通过uri里面获取path 这种方式在该机制下已经不行了。

参考了 友的总结:

https://weichao.blog.csdn.net/article/details/105790720

但是此问题还有一点诡异的地方就是只要先安装低版本targetSdk 的 apk ,然后再安装安卓11 版本的apk 进行覆盖, 此错误也会消失。并且在安卓11系统的手机上也不会出现,这个现在还不明其意。另外对于手机存储的理解,可以参考下文:

https://blog.csdn.net/u010937230/article/details/73303034

————————————–关于媒体库的访问————————————–

当在安卓10 系统中使用 uri 方式往input 标签放置文件数据时,此时能够正常方式,但是当前端在调用上传接口进行上传操作时,webview 会 错误:

2021-06-30 14:58:33.881 32521-32521/com.org.BaseWebviewApp.debug D/WebViewActivity: parse uri get path=/storage/emulated/0/DCIM/Camera/VID20210630145441.mp4

2021-06-30 14:58:35.327 32521-32521/com.org.BaseWebviewApp.debug E/WebViewActivity: onReceivedHttpError statusCode=401 reason=Unauthorized

2021-06-30 14:58:35.328 32521-32521/com.org.BaseWebviewApp.debug E/AFTag:WebViewActivity$8.onReceivedHttpError(Line:1156): onReceivedHttpError statusCode=401 reason=Unauthorized

另外在对于视频文件是使用绝对路径path ,还是使用uri 方式,这个需要根据版本来定,在安卓7.0 到 9.0 的时候可以直接使用path, 在安卓10 以上使用uri, 如果在安卓9 上面使用了uri,然后调用通用的根据uri转path 的接口会 如下错误:

2021-07-01 11:24:10.065 19727-19727/com.org.BaseWebviewApp.debug E/AFTag:MyCrashHandler.uncaughtException(Line:24): uncaughtException

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=5, result=-1, data=null} to activity {com.org.BaseWebviewApp.debug/com.hnac.hznet.WebViewActivity}: java.lang.IllegalArgumentException: column ‘_data’ does not exist. Available columns: []

可能是因为使用了如下代码:

于是这边才去的策略就是在安卓10 以及以上使用uri 方式填充数据,安卓9以及以下使用原先的path 填充数据。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年4月22日
下一篇 2021年4月22日

相关推荐