Android Q 的 Scoped Storage 和 “沙盒”(早就没了)所有你需要知道的

2019-09-04 16:09:19 +08:00
 RikkaW

Scoped Storage ( Beta 3 起至今)

官方文档 中的 "An app that uses scoped storage always has read/write access to the files that it creates, both inside and outside its app-specific directory." 这句话相当容易误解。其中的 "outside its app-specific directory" 并不是指应用可以像以前有存储权限时一样可以任意读写内置存储,而只是应用可以通过 Media Store 和 Storage Access Framework 在其专有文件夹以外建立文件并可任意访问。

简而言之,使用 Scoped Storage 的行为如下:

使用 Media Store 插入图片的例子

private boolean insertImage(File image) throws IOException {
    ContentValues values;
    // 向 Media Store 插入标记为待定的空白文件
    values = new ContentValues();
    values.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "test"); // 不同类型文件可用 RELATIVE_PATH 不用,具体请参阅 MediaProvider 源码
    values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, Long.toString(System.currentTimeMillis()));
    values.put(MediaStore.Images.ImageColumns.IS_PENDING, true);
    Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    if (uri == null) {
        return false;
    }
    // 写入文件内容
    InputStream is = new FileInputStream(image);
    OutputStream os = getContentResolver().openOutputStream(uri, "rw");
    byte[] b = new byte[8192];
    for (int r; (r = is.read(b)) != -1; ) {
        os.write(b, 0, r);
    }
    os.flush();
    os.close();
    is.close();
    // 移除待定标记,其他应用可访问该文件
    values = new ContentValues();
    values.put(MediaStore.Images.ImageColumns.IS_PENDING, false);
    return getContentResolver().update(uri, values, null, null) == 1;
}

“沙盒”(只存在于 Beta 2,Beta 5 起删除相关代码

Google 的“沙盒”的做法和 Rikka 的 Storage Redirect 核心部分原理相同,即使用挂载将一个只属于应用的文件夹(Android/sandbox)挂载为内置存储根目录,这样应用就只能访问该文件夹而不能访问真实的内置存储。

但这样做显然会产生一些问题(包括但不限于):

Google 在 Beta 2 的“沙盒”使用和 Rikka 一样的思路,即在最小化影响的前提下实现隔离应用产生的文件的功能。但结果是大部分用户根本不 care 有没有隔离(毕竟喜欢乱吐文件的应用几乎都来自中国大陆),只会关心自己要使用的应用有没有炸裂。

个人觉得对 Google 来说,于其使用这样相对激进的方案到头来吃力不讨好,倒不如选择之后的更简单的 Scoped Storage,并给应用一个大版本的时间进行适配,因为毕竟哪种方案都需要应用开发者做出相同的适配工作。<del>然而现在文档既模糊又不全(</del>

个人感慨

应用滥用存储权限的问题自古以来就是一个大问题,Rikka 个人从小时候(划掉)起就一直想解决这个问题。所以 Rikka 从 2016 年底开始创造 Storage Redirect,至今已经有相当高的完成度,并且对各种问题都有相应的解决方案,只要使用者愿意稍微动一动脑子就可以获得相当好的体验。

2019 年,Google 终于愿意开始解决这个问题,根据 Rikka 个人的实验和体验,绝大部分应用需要做的工作并没有很多,只是目前 Google 的文档过于模糊和残缺。

只要 Google 在 Android R 时能真正推行所有应用必须作出改变,那 R 到来的一两年世界后将会变得更美好(划掉)。(当然如果有应用滥用 Storage Access Framework 的授权访问整个存储 Rikka 魔法还是有用的(划掉

对某些过于乐观的人的疑惑(

从 Beta 2 起,就不断地听到有人说“啊,有了 Q 就没有应用乱吐文件的问题啦”,Beta 2 之后砍掉沙盒也有人哀嚎“啊,怎么砍了”。然而即使保留,除非所有应用都进行适配,否则必然是无尽的“找不到文件”“打不开文件”。国内大厂的适配时间都是以年计算(想想 QQ WeChat 今年才支持接收 content uri ),所以即使予以保留,也肯定是要等待至少一两年后才能有比较好的体验(

13755 次点击
所在节点    Android
31 条回复
huangyuanps2
2019-09-04 21:49:01 +08:00
哇,是 RikkaW 大佬,感谢大佬做的储存重定向。给父母的 Android 一般装了稳定版系统,不开放 root,所以也挺期待 Android R 正式发布的。对往储存里乱扔垃圾的 app 早就受够了。。。
jinyang656
2019-09-04 22:23:17 +08:00
Google 真是太没魄力了,幸亏还有 Storage Redirect 可用
Narcissu5
2019-09-04 22:37:18 +08:00
这个真的是 Android 和 ios 差距最大的地方了,而且一点好转的迹象都看不到

我觉得 redirect 不一定会引起奔溃,最多一些功能比如发送文件不可用。启用与否完全可以交给用户,不知道为什么要移除
KamenReborn
2019-09-04 22:48:12 +08:00
是 rikka,啊,我死了
RikkaW
2019-09-05 00:17:47 +08:00
@Narcissu5 然而一般用户真的没有这个脑子来理解这些(以及旧方案用系统的身份做那些稍微有点脏
gzxu
2019-09-05 06:33:21 +08:00
所以这意味着终端模拟器不能好好地访问公共存储了🤔除非 root,毕竟纯 C 程序还没办法直接访问 SAF,当然 Beta2-5 的方案下面也没办法好好访问
wanacry
2019-09-05 08:06:09 +08:00
想和 rikka 一起生猴子🐒
fetich
2019-09-05 09:57:15 +08:00
存储重定向真是个好东西,奈何必须 root
lonelinsky
2019-09-05 09:59:02 +08:00
@photon006 感觉是 Media Storage(Media Provider) 数据库混乱了,可以试下清空 Media Storage 数据库重建看看,我碰到了,通过这个解决了。
smarthing
2019-09-05 16:31:11 +08:00
SAF 被滥用的话,仍然然决不了乱写 sdcard 的问题。

如果能做到只有默认文件管理器才能使用 SAF 的话,这个情况是否会有改善? @RikkaW
kn007
2019-09-05 20:42:10 +08:00
啊,钱钱还在!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/597899

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX