首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  Android

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

  •  7
     
  •   RikkaW · 43 天前 · 3866 次点击
    这是一个创建于 43 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 的行为如下:

    • 直接访问文件:只可访问 Android/data/<package> Android/media/<package>
    • 读取媒体(照片、影片、音乐):使用 Media Store,获取后使用 getContentResolver().openInputStream 打开文件
    • 插入 /删除媒体:使用 Media Store,文档并未提及
    • 访问任意文件:使用 Storage Access Framework

    使用 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)挂载为内置存储根目录,这样应用就只能访问该文件夹而不能访问真实的内置存储。

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

    • 访问媒体文件:媒体存储返回假路径(/mnt/media 开头),在应用进程 hook 相关 IO 函数,如果是假路径就使用通过 content provider 获取到的远端 fd
    • 保存媒体文件:使媒体存储增加扫描 Android/sandbox
    • 跨挂载点移动文件:Google 未解决

    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 ),所以即使予以保留,也肯定是要等待至少一两年后才能有比较好的体验(

    第 1 条附言  ·  42 天前

    给普通用户的补充:

    在 Android 10 上,Scoped Storage 只针对 target 29 的应用启用,且应用还可以选择退出。换句话说,就 Android 10 而言,普通用户的体验没有任何变化

    根据 Google 的计划,在下个大版本对所有应用启用。

    给脑子不太够用的“高级用户”:

    Beta 2 的“沙盒”已经渣都不剩了,现在的 Scoped Storage 即使可以强制开启效果也与直接不给存储权限无异(正文第一大段)。

    31 回复  |  直到 2019-09-05 20:42:10 +08:00
        1
    Love4Taylor   43 天前
    rikka 大法好!
        2
    z919126592   43 天前 via Android
    是 rikka 诶
        3
    photon006   42 天前
    今天升级 android 10 就遇到很多存储相关问题,play store 无法下载 app 更新,无法截图,微信无法选择图片发送给好友,photos 无法查看照片,很多网友也遇到:

    https://support.google.com/photos/thread/13511562?hl=en

    https://support.google.com/photos/thread/13518838?hl=en
        4
    huaxianyan   42 天前
    Rikka 的钱钱又飞回来了

    今天用上了 Android 10,官方可以允许切换到三键模式好评,就是应用不能写剪贴板让我有点难受,其他设备给手机传点文本还要推送个通知过去再复制
        5
    7654   42 天前
    不给权限不给用
        6
    gz911122   42 天前
    是 rikka 耶
        7
    Buges   42 天前 via Android   ♥ 1
    有一点不敢苟同的是,如果“沙盒”保留的话“找不到文件”等问题仅在最开始会存在,在国产厂商争相追 Android 版本的情况下,除非国内定制 ROM 魔改砍掉,否则定然会倒逼 app 做适配(大厂适配慢那是无足轻重的小问题,这种严重影响体验的 bug 不可能不跟进),不然新手机微信之类的都不能用了,怎么可能?
    虽然存储重定向的魔法确实好用,但从根本上让应用不再这么干不是更好么?
    起码到了 Q 终于不再需要 xprivacy 来阻止应用获取 IMEI 了,hook 一时爽,应用不再申请了当然更爽。
        8
    expy   42 天前
    乐观的想法:不适配就崩溃,会倒逼应用适配啊。
        9
    RikkaW   42 天前
    @Buges 然而确实是可以选择完全不开启这个功能的(
        10
    deorth   42 天前
    是大佬,awsl
        11
    tankren   42 天前
    膜拜大佬 正在使用 Storage Redirect
    有个问题啊,微信启用了重定向之后 微博国际版的图片不能直接分享到微信了 分享操作可以无误的完成但是图片并没有发出去
        12
    HankAviator   42 天前 via Android
    逼一波大厂也得妥协,微信就是拖到不匹配通知渠道就从 play 下架的死线前不久才更新适配,之前拿各种借口搪塞,必须改时不也痛快。
        13
    s82kd92l   42 天前
    好像 beta6 文档里面写了有新的 appops 类型可以强制 scoped storage, 不过正式发布的文档里面找不到这个描述了。不知道代码里面还有没有
        15
    RikkaW   42 天前
    @s82kd92l 相关的东西早就看过了 开了也没意义 “我求你了读一读第一段 Scoped Storage 的行为”
    (一种你就是最后讲的那种人的感觉
        16
    momocraft   42 天前
    希望对国内厂家有效,play 版的 QQ 现在都不上架了...
        17
    little_cup   42 天前
    @Buges 除了 Google,其他设备商只能逼小厂,大厂不愿适配那就只能乖乖 ROM 里写死给他们开白名单。
        18
    echo314   42 天前 via iPhone
    @little_cup Google 在这点考虑上可能并不是顾忌大厂不愿适配,而是因为直接强上影响用户体验,不管是厂商还是 Google 都会被用户骂。
    国内大厂不愿适配这点影响不大,Google 对海外安卓市场有极强的控制力,除非国内大厂想放弃海外市场,联合国内厂商搞白名单才有意义,毕竟面向海外的还是适配,既然都得适配为什么要搞两套呢?
        19
    efsg   42 天前
    不明觉厉 简单来说就是存储权限被废掉,不管怎么样都不能读写外部存储吗
        20
    RikkaW   42 天前
    @efsg 先读官方文档再读这个.. 现在是 target 29 才有(并且可以 opt-out ),计划是下个大版本强制
        21
    huangyuanps2   42 天前
    哇,是 RikkaW 大佬,感谢大佬做的储存重定向。给父母的 Android 一般装了稳定版系统,不开放 root,所以也挺期待 Android R 正式发布的。对往储存里乱扔垃圾的 app 早就受够了。。。
        22
    jinyang656   42 天前 via Android
    Google 真是太没魄力了,幸亏还有 Storage Redirect 可用
        23
    Narcissu5   42 天前
    这个真的是 Android 和 ios 差距最大的地方了,而且一点好转的迹象都看不到

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

    如果能做到只有默认文件管理器才能使用 SAF 的话,这个情况是否会有改善? @RikkaW
        31
    kn007   41 天前
    啊,钱钱还在!
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4088 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 45ms · UTC 08:17 · PVG 16:17 · LAX 01:17 · JFK 04:17
    ♥ Do have faith in what you're doing.