Android 11 应用适配 兼容性

Android 11 应用兼容性适配指导

本文非原创-若侵犯到原创利益,请联系删除

原文 https://open.oppomobile.com/wiki/doc#id=1072

 

一、隐私更新

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

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

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

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

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

1.2. 兼容影响

当您将应用更新为以 Android 11 为目标平台后,您将无法使用requestLegacyExternalStorage,而且也没有其他标记可以提供停用分区存储。
分区存储对于App访问存储方式、App数据存放以及App间数据共享,都产生很大影响。
而Environment.getExternalStorageDirectory() 在 API Level 29 开始已被弃用,开发者应迁移至 Context#getExternalFilesDir(String), MediaStore, 或Intent#ACTION_OPEN_DOCUMENT。

1.3. 适配

1 应用targetSdkVersion
应用targetSdkVersion >= 30,都会强制打开分区存储,同时requestLegacyExternalStorage将会无效。
如果您需要对已安装的应用进行适配分区存储的数据迁移,则可以在应用更新到目标平台为Android 11版本后仍暂时保留原有的存储模式。请在应用的manifest中设置preserveLegacyExternalStorage属性为true,应用更新到android 11可以保留存储继承模式。

2 应用私有目录访问
对于运行在Android 11的应用,无论targetSdkVersion是什么都无法访问Emulated存储中的其他应用私有目录(Android/data)。SAF(Storage Access Framework)同样也禁止访问应用私有目录。
某些应用的核心用例需要访问大量的文件,如文件管理操作或备份和恢复操作。这些应用可通过执行以下操作获取“所有文件访问权限”:

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

●  注意:获得此权限的应用仍然无法访问属于其他应用的应用专用目录。这些目录在存储卷上显示为 Android/data/ 的子目录。

3 直接路径访问
注意:使用直接路径和原生库保存媒体文件时,应用的性能会略有下降。请尽可能改用MediaStore API。

具体适配参考:
https://developer.android.google.cn/training/data-storage#scoped-storage
https://developer.android.google.cn/preview/privacy/storage
1.3.1. 运行模式
1.3.1.1. App运行模式
在Android 11版本上,系统会根据App targetSdkVersion决定运行模式:
●  App targetSdkVersion >= 30,默认为分区存储,并且无法取消。

●  App targetSdkVersion < 29,默认为分区存储,可通过requestLegacyExternalStorage更改

应用可以通过AndroidManifest.xml设置requestLegacyExternalStorage, 选择对应的方式:

●  App targetSdkVersion < 29,声明了READ_EXTERNAL_STORAGE,默认Legacy Mode
●  App在下列条件都成立时
   ■  声明 MANAGE_EXTERNAL_STORAGE 权限。
   ■  使用 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent 操作将用户引导至一个系统设置页面,在该页面上,用户可以为您的应用启用以下选项:授予所有文件的管理权限。
App拥有外置存储空间Read、Write权限。但是通过Environment.isExternalStorageLegacy接口判断,返回不一定是Legacy Mode。
 

1.3.1.2. 判断当前App运行模式
判断当前App运行什么模式,可以通过这个API判断:
Environment.isExternalStorageLegacy() (added in api 29);


1.3.2. 读写公共目录
App启动分区存储后,只能直接访问自身专属目录,所以Android 11,提供了两种访问公共目录的方法(特殊直接路径访问参考1.3.8. 直接路径访问):


1.3.2.1. 通过MediaStore定义的Uri
MediaStore提供了下列几种类型的访问Uri,通过查找对应Uri数据,达到访问的目的。
下列每种类型又分为三种Uri,Internal、External、可移动存储:

●Audio
   ■  Internal: MediaStore.Audio.Media.INTERNAL_CONTENT_URI

       content://media/internal/audio/media。

   ■  External: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

       content://media/external/audio/media。

   ■  可移动存储: MediaStore.Audio.Media.getContentUri

       content://media/<volumeName>/audio/media。
●  Video
   ■    Internal: MediaStore.Video.Media.INTERNAL_CONTENT_URI
         content://media/internal/video/media。
   ■    External: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
         content://media/external/video/media。
   ■    可移动存储: MediaStore.Video.Media.getContentUri
         content://media/<volumeName>/video/media。
●  Image
   ■    Internal: MediaStore.Images.Media.INTERNAL_CONTENT_URI
         content://media/internal/images/media。
   ■    External: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
         content://media/external/images/media。
   ■    可移动存储: MediaStore.Images.Media.getContentUri
         content://media/<volumeName>/images/media。
●  File
   ■    MediaStore. Files.Media.getContentUri
         content://media/<volumeName>/file。
●  Downloads
   ■    Internal: MediaStore.Downloads.INTERNAL_CONTENT_URI
         content://media/internal/downloads。
   ■    External: MediaStore.Downloads.EXTERNAL_CONTENT_URI
content://media/external/downloads。
   ■    可移动存储: MediaStore.Downloads.getContentUri
content://media/<volumeName>/downloads。

1.3.2.1.1. 获取所有的Volume
对于前面描述的Uri中,getContentUri如何获取所有<volumeName>,可以通过下述方式:


1.3.2.1.2.Uri跟公共目录关系
MediaProvider对于App存放到公共目录文件,通过ContentResolver insert方法中Uri来确定,其中下表中<Uri路径>为相对路径,完整为:
content://media/<volumeName>/<Uri路径>。

Mine Type Uri路径 一级目录
audio/* images/media
images/media/#
Environment.DIRECTORY_ALARMS
Environment.DIRECTORY_MUSIC
Environment.DIRECTORY_NOTIFICATIONS
Environment.DIRECTORY_PODCASTS
Environment.DIRECTORY_RINGTONES
image/* audio/albumart
audio/albumart/#
Environment.DIRECTORY_MUSIC
  audio/playlists
audio/playlists/#
Environment.DIRECTORY_MUSIC
video/* video/media
video/media/#
Environment.DIRECTORY_DCIM
Environment.DIRECTORY_MOVIES
image/* images/media
images/media/#
Environment.DIRECTORY_DCIM
Environment.DIRECTORY_PICTURES
image/* video/thumbnails
video/thumbnails/#
Environment.DIRECTORY_MOVIES
image/* images/thumbnails
images/thumbnails/#
Environment.DIRECTORY_PICTURES
  downloads
downloads/#
Environment.DIRECTORY_DOWNLOADS
  file
file/#
Environment.DIRECTORY_DOWNLOADS
Environment.DIRECTORY_DOCUMENTS

 

通过ContentResolver,根据不同的Uri查询不同的内容:1.3.2.1.4. 查询文件1.3.2.1.3. 权限
MediaStore通过不同Uri,为用户提供了增、删、改。
App对应的权限如下:

  Audio Image Video File Downloads
WRITE_EXTERNAL_STORAGE no-op
READ_EXTERNAL_STORAGE 能读取所有App的多媒体文件 不能读取非多媒体文件
只能读取、修改自己新建的文件

 

1.3.2.1.4. 查询文件

通过ContentResolver,根据不同的Uri查询不同的内容:


1.3.2.1.5.读取文件
通过ContentResolver query接口,查找出来文件后如何读取,可以通过下面的方式:
●  通过ContentResolver openFileDescriptor接口,选择对应的打开方式

    例如”r”表示读,”w”表示写,返回ParcelFileDescriptor类型FD。

●  访问Thumbnail,通过ContentResolver loadThumbnail接口

    通过传递大小,MediaProvider返回指定大小的Thumbnail。
●    Native代码访问文件
      如果Native代码需要访问文件,可以参考下面方式:

  ■  通过openFileDescriptor返回ParcelFileDescriptor

  ■  通过ParcelFileDescriptor.detachFd()读取FD
  ■  将FD传递给Native层代码
  ■  App需要负责通过close接口关闭FD


1.3.2.1.6.新建文件
如果需要新建文件存放到公共目录,需要通过ContentResolver insert接口,使用不同的Uri,选择存储到不同的目录。


1.3.2.1.7.修改文件

如果需要修改多媒体文件,需要通过ContentResolver query接口查找出来对应文件的Uri。
如果不是自己新建的文件,需要注意1.3.2.1.3. 权限中描述,需要catch RecoverableSecurityException,弹框给用户选择。



通过下列接口,获取需要修改文件的FD或者Output

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在开发 Android 应用程序时,需要考虑 WebSocket 兼容性问题,主要有以下几个方面: 1. WebSocket API 兼容性Android 平台在不同版本中可能存在 WebSocket API 的差异,需要根据目标用户的 Android 系统版本选择适当的 API。 2. 网络环境兼容性:在某些网络环境下,WebSocket 可能会受到限制或阻塞,需要通过其他方式实现实时通信,例如使用长轮询或 SSE。 3. 安全性兼容性:WebSocket 是一种明文协议,可能会存在安全漏洞,需要注意避免使用不安全的 WebSocket 实现,或者加密 WebSocket 数据以确保数据安全。 为了解决这些兼容性问题,可以采取以下几个适配方法: 1. 选择适当的 WebSocket 实现库:根据目标用户的 Android 系统版本选择适当的 WebSocket 实现库,例如在 Android 5.0 及以上版本中可以使用 android.net.http.WebSocket 类来实现 WebSocket 功能,而在 Android 4.4 及以下版本,则需要使用第三方库来实现 WebSocket。 2. 处理网络环境问题:在某些网络环境下,WebSocket 可能会受到限制或阻塞,需要通过其他方式实现实时通信。例如,可以使用长轮询或 SSE,或者使用反向Ajax等技术来实现实时通信。 3. 处理安全问题:可以使用 SSL/TLS 等方式加密 WebSocket 数据,确保数据安全。 4. 处理 WebSocket 连接管理问题:需要合理管理 WebSocket 连接,例如在应用程序进入后台或网络状态发生变化时,需要关闭 WebSocket 连接以避免网络带宽占用过多,或者重新建立 WebSocket 连接以确保通信正常。 综上所述,为了确保 Android 应用程序的 WebSocket 功能兼容性,需要根据不同版本的 Android 平台选择适当的 WebSocket 实现库,并合理处理网络环境、安全性和连接管理等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值