解惑Android Scoped Storage

原文链接 Android Scoped Storage Puzzles

安卓对于文件存储这块,其实是相当混乱的,在早期的版本中对存储甚至是没有所谓的管理的,有多种方法可以操作文件存储,比如通过Java原生的方式(File/InputStream/OutputStream),以及通过ContentProvider的方式(openFile/openOutputStream)。文件的路径也是相当混乱的,有公共存储区域,App的沙盒,外部存储中的App沙盒,但其实整个文件系统中的文件都是可读的,除了系统目录,其他应用的沙盒(内部和外部)以外也都是可写的。这就造成了,安卓的文件系统特别的混乱,加之应用使用不规范,对存储造成极大的滥用,外部存储空间产生大量的垃圾文件,应用卸载后仍然存在,这也催生了一系列的清理软件。

但随着用户隐私问题越来越被重视,谷歌也开始收紧了存储权限管理。

存储权限的变迁史

强制动态申请权限

从Android 6.0(Android M, API 23)开始,存储权限除了在AndroidManifest中静态声明以外,还需要在运行时动态的申请,用户授权了后才可以使用。但这并没有本质的变化,只要用户授权了,就跟以前一样,所有文件可读,大量位置的文件也都可写,App依然可以随便乱搞。

Scoped Storage

后来到了Android 10 (Android Q, API 29)时提出了scoped storage的概念,并把权限进一步的收紧,仅留下几个公共的文件夹可写,其他地方均不可写。并且写媒体文件时(Image/Video/Audio),要用MediaStore API的方式,直接以Java的文件方式将不再可用。Android 10并未强制开启scoped storage,通过在Manifest中设置requestLegacyStorageManage=true,依然可以像以往那样搞,但到了Android 11时,就强制开启了scoped storage。

强制Scoped Storage

到了Android 11(Android R, API 30)时,就强制了,只有应用自己的沙盒可自由读写。创建媒体文件必须 通过MediaStore API。只有少数公共区域可读可写(Documents/Downloads/Pictures)等,并且这些区域只有自己创建的文件是可见和可读的。这就导致了,应用能乱搞的区间相当有限了。

细分文件种类权限

到了Android 13(Android T, API 33),更加变态了,把原来的WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE权限细分为对具体文件种类的操作,拆分为Image/Audio/Video三种媒体文件类型的读写。

注意:只有当targetSdk=33时,并且运行的设备是Android 13时,才需要做权限的细分处理。也许后面的版本就会强制了,如果强制那无论taregtSdk是多少都会强制使用细分 权限。

存储问题的适配

前面简单的介绍了安卓存储权限的变化过程,重点还是要了解一下如何适配。因为现在已经是2023年了,Android 13(Android T),API 33也快要普及了,所以就直接总结下现在应该怎么做。

动态申请存储权限

对于现在来说,动态申请权限已经是必备的技能之一了,不用多说了。就是先在应用的入口处,或者将要使用存储的地方去申请

在manifest中声明requestLegacyExternalStorage=true

用MediaStore API来操作媒体文件(Image/Audio/Video)

首先要声明具体的权限,然后用MediaStore API来操作。

申请另外一个权限MANAGE_EXTERNAL_STORAGE

注意: 这个不管你的targetSDK是多少,只要目标运行设备是Android 11,就必须 这样做。

从Android 11开始,要想看到公共区域(Documents/Downloads)中的所有文件,还必须申请另外一个权限MANAGE_EXTERNAL_STORAGE。因为理论上来说,公共区域你只能看见你自己创建的文件就够了,想看所有文件就越权了。但对于有些应用来说,如文件浏览器,或者请记录阅读器来说,肯定要能看到所有的文件。这个权限需要再次单独申请,用户授权后即可以看到公共区域的所有的文件了。

需要注意,这个权限像常规权限那样去申请是没用的,它的状态永远是denied的,所以,逻辑要这样写:

  1. 先正常申请存储相关的权限
  2. 正常权限有了后,判断Environment.isExternalStorageManager(),如果 是false则需要再次申请另外一个叫做access all files的权限,通过ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION或者ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
       // after read/write permission grantedif (!Environment.isExternalStorageManager()) {requestAllFilesAccess();}// ...private void requestAllFilesAccess() {Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);intent.addCategory(Intent.CATEGORY_DEFAULT);Uri uri = Uri.fromParts("package", getPackageName(), null);intent.setData(uri);try {startActivity(intent);} catch (ActivityNotFoundException e) {Log.d(LOG_TAG, "Exception: " + e.getMessage());}}

需要注意,有可能会有Activity not found exception,注意try-catch下。

因为这个权限又会导致失控,只要申请了就可以在公共区域随意创建文件了,所以谷歌对这个权限管控也是比较严的。虽然你在研发测试阶段可以申请这个权限,但是在发布阶段,要给应用商店一个使用此权限的合理理由,否则Play store会拒绝上线的(当然,如果 不在Play Store上面发布也就无所谓了)。

合理使用公共区域

作为App,最应该做的就是从业务上区分文件的属性,然后合理的选择存储空间进行存储。对于App本身运行相关的文件,如配置,如算法的模型,如数据库,缓存和日志等等应用本身运行密切相关的文件,一定不可以放在公共区域,一定要放在应用自己的沙盒内(通过context.getFilesDir, context.getCacheDir, context.getExternalFilesDir, context.getExternalCacheDir, context.openFileOutput)等来读写,应用自己的沙盒也是属于App的自由空间,你可以随意玩。

对于用户生成的文件则要放在公共区域,比如说相机产出的图片和视频,编辑软件产生的文档,这些属于用户生成文件,它的所有权是用户的,可能会通过其他软件再次编辑或者分享,这些肯定要放在公共区域的。对于媒体类Image/Audio/Video则要使用MediaStore API的方式来创建和管理。对于其他文档类型,在获得了WRITE权限 后也可以在(Documents/Downloads)中创建和管理的,绝大多数情况下,这就够了。

总的来说,在用户隐私越来越被重视的今天,安卓现在存储管理策略在保护用户隐私的前提下是能够满足开发者使用的。

参考资料

  • Android API Levels
  • Open files using storage access framework
  • Storage updates in Android 11
  • Request runtime permissions
  • External Storage in Android with Example
  • Manage all files on a storage device
  • Android 11 Scoped storage permissions
  • How does MANAGE_EXTERNAL_STORAGE permission work in Android?

原创不易,打赏点赞在看收藏分享 总要有一个吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/160939.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【微服务 SpringCloudAlibaba】实用篇 · Nacos注册中心

微服务(5) 文章目录 微服务(5)1. 认识和安装Nacos2. 服务注册到nacos和拉取服务1)引入依赖2)配置nacos地址3)重启 3. 服务分级存储模型3.1 给user-service配置集群3.2 同集群优先的负载均衡 4. …

php74 安装sodium

下载编译安装libsodium wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable.tar.gz tar -zxf libsodium-1.0.18-stable.tar.gz cd libsodium-stable ./configure --without-libsodium make && make check sudo make install下载编译安装…

【Python搜索算法】广度优先搜索(BFS)算法原理详解与应用,示例+代码

目录 1 广度优先搜索 2 应用示例 2.1 迷宫路径搜索 2.2 社交网络中的关系度排序 2.3 查找连通区域 1 广度优先搜索 广度优先搜索(Breadth-First Search,BFS)是一种图遍历算法,用于系统地遍历或搜索图(或树…

Linux Zabbix企业级监控平台+cpolar实现远程访问

文章目录 前言1. Linux 局域网访问Zabbix2. Linux 安装cpolar3. 配置Zabbix公网访问地址4. 公网远程访问Zabbix5. 固定Zabbix公网地址 前言 Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。能监视各种网络参数,保证服务器系…

HTML三叉戟,标签、元素、属性各个的意义是什么?

🌟🌟🌟 专栏详解 🎉 🎉 🎉 欢迎来到前端开发之旅专栏! 不管你是完全小白,还是有一点经验的开发者,在这里你会了解到最简单易懂的语言,与你分享有关前端技术和…

【Java基础面试十二】、说一说你对面向对象的理解

文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官: 说一说你对面向对象的理…

thinkphp5.1 获取缓存cache(‘cache_name‘)特别慢,php 7.0 unserialize 特别慢

thinkphp5.1 获取缓存cache(‘cache_name’)特别慢,php 7.0 unserialize 特别慢 场景: 项目中大量使用了缓存,本地运行非常快,二三百毫秒,部署到服务器后 一个表格请求就七八秒,最初猜想是数据库查询慢&am…

消息队列学习分享

消息队列学习 消息队列来解决问题 (1)异步处理 消息通知、日志管理、更新统计数据等步骤 (2)流量控制 如何避免过多的请求压垮我们的系统? 比如一个秒杀系统,网关在收到请求后,将请求放入…

Kotlin中的数值类型

在Kotlin中,Byte、Short、Int、Long、Float和Double是基本数据类型,用于表示不同范围和精度的数值。 Byte(字节):Byte类型是8位有符号整数类型,取值范围为-128到127。在Kotlin中,可以使用字面值…

vscode工程屏蔽不使用的文件夹或文件的方法

一. 简介 vscode是一款 微软提供的免费的代码编辑软件。 对于 IMX6ULL-ALPHA开发板而言,NXP官方uboot一定会支持不止 IMX6ULL芯片的代码,也不止支持 一种架构,还支持其他芯片或架构的源码文件。 为了方便阅读代码,vscode软件可…

腾讯云我的世界mc服务器多少钱一年?

腾讯云我的世界mc服务器多少钱?95元一年2核2G3M轻量应用服务器、2核4G5M带宽优惠价218元一年、4核8G12M带宽轻量服务器446元一年,云服务器CVM标准型S5实例2核2G优惠价280元一年、2核4G配置服务器748元一年,腾讯云百科txybk.com分享腾讯云我的…

[LeetCode周赛复盘] 第 115 场双周赛20231014

[LeetCode周赛复盘] 第 115 场双周赛20231014 一、本周周赛总结100095. 上一个遍历的整数1. 题目描述2. 思路分析3. 代码实现 100078. 最长相邻不相等子序列 I1. 题目描述2. 思路分析3. 代码实现 100077. 最长相邻不相等子序列 II1. 题目描述2. 思路分析3. 代码实现 100029. 和…

【数据结构】排序--选择排序(堆排序)

目录 一 堆排序 二 直接选择排序 一 堆排序 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是 通过堆来进行选择数据。 需要注意的是排升序要建大堆,排降序建小堆。 直接选择排…

HEIC转jpg

下载imagemagick,安装 https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-20-Q16-HDRI-x64-dll.exe cmd D:\soft\ImageMagick-7.1.1-Q16-HDRI\magick.exe "C:\Users\Gamer\Downloads\iCloud 照片1\iCloud 照片\IMG_3889.HEIC" IMG_3889.jpg

WebSocket: 实时通信的新维度

介绍: 在现代Web应用程序中,实时通信对于提供即时更新和交互性至关重要。传统的HTTP协议虽然适合请求-响应模式,但对于需要频繁数据交换的场景并不理想。而WebSocket技术的出现填补了这个空白,为Web开发者们带来了一种高效、实时的…

Elucidating the Design Space of Diffusion-Based Generative Models 阅读笔记

文章用一种新的设计框架统一diffusion-based model,并使用模块化(modular)的思想,分别从采样、训练、score network设计三个方面分析和改进diffusion-based model。 之前的工作1已经把diffusion-based model统一到SDE或者ODE框架…

10-k8s-身份认证与鉴权

文章目录 一、ServiceAccount介绍二、ServiceAccount相关的资源对象三、dashboard空间示例 一、ServiceAccount介绍 ServiceAccount(服务账户)概念介绍 1)ServiceAccount是Kubernetes集群中的一种资源对象,用于为Pod或其他资源提供…

JavaScript基础知识14——运算符:逻辑运算符,运算符优先级

哈喽,大家好,我是雷工! 一、逻辑运算符 1、概念:在程序中用来连接多个比较条件时候使用的符号。 2、应用场景:在程序中用来连接多个比较条件时候使用。 3、逻辑运算符符号: 4、代码演示逻辑运算符的使用…

手机流量卡经营商城小程序的作用是什么

流量卡成为很多用户的选择,同时市场中也出现了不少流量卡卖家,基于多种形式开展生意。然而虽然市场需求度高,但流量卡经营难题也不少。 流量卡客户具有高忠诚度,然而入驻线上第三方平台,客户属于平台,无法…

四川天蝶电子商务有限公司抖音电商服务引领行业标杆

随着电子商务的飞速发展,四川天蝶电子商务有限公司作为一家领先的抖音电商服务提供商,已经脱颖而出。本文将详细解析四川天蝶电子商务有限公司的抖音电商服务,让您一探究竟。 一、卓越的服务理念 四川天蝶电子商务有限公司始终坚持以客户为中…