[Android4.4]第三方APP无法操作外置SD卡原因分析以及延伸阅读

1.问题背景:

最近做Android4.4的平台移植,遇到一个问题:在Android4.4中,第三方App是没有权限操作外置SD卡的(除非是与自己包名相同的目录),开始以为是自己申请的权限不足,最后发现是Google在Android中限制了这一权限.这是原文:

The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions.

意思就是说,只有主存储有读写的权限,第二存储(通常是外置SD卡或者USBOTG,这个可以在设置菜单中自己设置)只有读的权限.原因也有给出:

Restricting writes in this way ensures the system can clean up files when applications are uninstalled.

另一个原因我觉得是安全的问题,这一方面的陈述会在下面详细介绍.

2.解决办法:

解决办法分两种,一种针对用户,一种针对开发者.

针对用户:

已经root的用户可以通过修改:/system/etc/permissions/platform.xml 文件(使用RE文件管理器即可),找到如下代码块:

    <permission name=\"android.permission.WRITE_EXTERNAL_STORAGE\" >
        <group gid=\"sdcard_r\" />
        <group gid=\"sdcard_rw\" />
    </permission>

修改为:

    <permission name=\"android.permission.WRITE_EXTERNAL_STORAGE\" >
        <group gid=\"sdcard_r\" />
        <group gid=\"sdcard_rw\" />
    <group gid=\"media_rw\" />
    </permission>

然后重启.就可以读写SD卡了.

这个做法其实就是给android.permission.WRITE_EXTERNAL_STORAGE 这个权限组加上对media的读写权限.

针对开发者:

论坛上的方法,先把文件改为图片类型,再用media content provider来删除

1
2
3
4
5
6
7
8
9
10
11
12
13
//转换成媒体文件,再进行操作
private static final Uri FILES_URI = MediaStore.Files.getContentUri(\"external\");
    public static boolean deleteFile(Context context, String path) {
        ContentResolver cr = context.getContentResolver();
        if (cr == nullreturn false;
        final String selection = FileColumns.DATA + \"=?\";
        final String[] selectionArgs = new String[] { path };
        ContentValues values = new ContentValues();
        values.put(FileColumns.MEDIA_TYPE, FileColumns.MEDIA_TYPE_IMAGE);
        return cr.update(FILES_URI, values, selection, selectionArgs) &gt; 0
                &amp;&amp; cr.delete(FILES_URI, selection, selectionArgs) &gt; 0;
    }

这样做是因为MediaProvider拥有读写SD卡的 权限,通过它去操作文件也可以达到目标.不过有人反映如果把默认存储设置为内置SD卡,该方法貌似就失效了。不知道有没有更好的办法?

针对rom开发者:

rom开发者有更好的选择,platform.xml的文件位置在源代码:frameworks/base/data/etc/中,和方法1中的步骤一样:

    <permission name=\"android.permission.WRITE_EXTERNAL_STORAGE\" >
        <group gid=\"sdcard_r\" />
        <group gid=\"sdcard_rw\" />
    </permission>

修改为:

    <permission name=\"android.permission.WRITE_EXTERNAL_STORAGE\" >
        <group gid=\"sdcard_r\" />
        <group gid=\"sdcard_rw\" />
    <group gid=\"media_rw\" />
    </permission>

然后重新编译一个rom即可.

 

3.延伸阅读

Google这么做的原因,我也查阅了一些文章,下面是一些我觉得比较好的回答,大家感兴趣可以自己看一下:

第一篇是Google+上的一个人的分析,大概解释了一下google这样做的原因以及造成的影响(英文很简单):

KitKat will make your SD Card completely useless: per the Android API specification, apps can no longer write files to your SD card. And Samsung is following it.This only applies to dual-storage devices, i.e., devices with a user-writable internal flash storage AND a removable SD card.

From http://source.android.com/devices/tech/storage/index.html:\”The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions.\”

If your device has user-accessible internal flash storage, your SD Card is a \”secondary external storage device\”.

What this means is that with KitKat, applications will no longer be able create, modify, or remove files and folders on your external SD card. As a for-instance, you can no longer use a file manager to copy files from your computer to the SD card over a network. This ability, which has existed since the beginning of Android, has been taken away.

The only stated reason for this removal of functionality is that, \”Restricting writes in this way ensures the system can clean up files when applications are uninstalled.\” I do not pretend to understand this logic. Apps are still allowed to write in arbitrary directories on the primary storage (with the appropriate permission), but are denied the same access to external storage.

Samsung has implemented this feature with their KitKat OTA updates. Note3 users are now complaining that FX File Explorer can no longer write to their external SD cards. There are solutions to this problem for users with root access. Users without root access appear to be screwed.

I\’m not quite certain how Google intends for you to place files on your SD card. Perhaps you have to use proprietary Google apps that contain permissions unavailable to the rest of the developer world. Perhaps you\’re supposed to put everything on the cloud and pay carrier data fees to get it there. Perhaps you\’re supposed to use some kind of WIRE to attach your WIRELESS device to your computer and have the computer do that work for you.

In my opinion this is a horrible misstep by Google and the Android Open Source Project. Functionality has been removed without reason, to the severe detriment of users and developers alike.

I apologize for not bringing this to everyone\’s attention when KitKat 4.4 was released, but it was not mentioned in the Android 4.4 changes document:http://developer.android.com/about/versions/android-4.4.html. It\’s only mentioned in the article on source.android.com. I was only made aware of its existence from user reports as a result of Samsung implementing this change in its KitKat OTA updates.

第二篇是知乎上的讨论,大家自行脑补:

这有可能真的只是一个限制,影响很小,因为这个限制并不彻底,primary external storage 仍然可写,而支持双 SD 的设备并不很多。我们大家更期待的是让 primary external storage 也同样受到这个限制,虽然这个修改将涉及到更多应用的不兼容。

所以这个问题并没有彻底解决,到对 primary external storage 也限制的那个时候,才真正的解决了这个问题。

就目前而言,第二 SD 卡仍然是可以读写的,只是要读写到指定的目录(具体应该在 /Android/data/)。这样的规定意味着应用程序只能对 SD 卡的指定目录进行读写,不能读写任意目录。相当于 Google 出手对 SD 卡目录结构进行了规范。之前 android 不限制目录,所以各种应用就随意的在 SD 卡上建一个目录。然后 SD 卡上的目录到处都是,用户对这种现象早就深恶痛绝了!如果 Google 对这件事情下狠手,只能说是大快人心

另外说一下,SD 卡上的指定目录是这样获取的:
1,程序相关的 内置存储目录,这个目录位于内置 flash,应用程序可以随意读写:

getFilesDir();

2,程序相关的 SD 卡外部存储目录,这个目录位于 SD 卡,应用程序可以随意读写:

getExternalFilesDir(null);

3,SD 卡公共目录,这些目录仍然可以访问,不受权限限制:

Environment.getExternalStoragePublicDirectory(x)

其中 x 可以是 Environment.DIRECTORY_ALARMS 等预定义的常量。可以查找 Environment 的帮助。

如果大家要存储数据,可以用 1 或者 2 的方法,获取正确的目录,然后进行任意读写,这样不会把 SD 卡的目录写乱。

第三篇也是知乎上一个讨论:

Google 给出的理由有一定的道理——相信很多有洁癖的人都很讨厌第三方应用在 SD 卡或者内置存储下随意建立文件夹吧,有节操的应用应该只在以自己的包名区分的目录下存放需要的文件。

至于为什么只限制 SD 卡,不包括内置存储,我觉得是因为 SD 卡是可以插在别的地方的,目录结构是有可能暴露出来的,也有可能被修改。规范应用在 SD 卡的读写,可以使得这个 SD 卡上的目录和文件可以在其他设备上被电脑「理解」——「这个目录是在某一个 Android 设备上用到的,我不必理会它」,如果第三方应用随意在 SD 卡根目录创建命名不规范并且无规律的目录,这个 SD 卡在其他地方就会使电脑或者人迷惑——「这个目录是干什么的?是谁创建的?我可不可以删掉它?」。手机的内部存储空间不能拆卸,所以其目录结构不会轻易暴露给用户,也不会放在别的设备上,所以可以暂时不管。

 

参考:

1.https://plus.google.com/+TodLiebeck/posts/gjnmuaDM8sn

2.http://www.zhihu.com/question/22778889

3.http://source.android.com/devices/tech/storage/index.html

 

相关阅读 :

  1. Android4.4中扫描文件广播权限变更分析

作者:Gracker
出处:androidperformance.com
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
打赏一下: 微博打赏

文章目录
  1. 1. 1.问题背景:
  2. 2. 2.解决办法:
  3. 3. 3.延伸阅读
|