安卓KitKat 4.4 SD卡文件夹

16

我们刚刚遇到了在Android 4.4中写入sd卡(外部存储)文件的新权限问题(EACCES Permission Denied)。

在KitKat之前,我们是按照以下方式设置可写文件夹:

mfolder = Environment.getExternalStorageDirectory().getPath() + "/appfiles";

然而,经过数小时的搜索,我得出了结论,正确或错误,在4.4设备上启用文件写入需要更改为:

mfolder = Environment.getExternalStorageDirectory().getPath() + "/Android/data/com.xyz.abc/appfiles";

所以,mfolder应该是这样的:/mnt/sdcard/Android/data/com.xyz.abc/appfiles

这样创建一个类似上述sd卡上的文件夹,能让4.4设备写入文件吗?

mfolder是我们保存到共享偏好中的字符串。

然后,我们有了一段代码,如果API>=19,它将更改mfolder字符串,然后将所有文件从旧文件夹复制到新的“kitkat”文件夹。

if (android.os.Build.VERSION.SDK_INT>=19){
        if (!mfolder.contains("/Android/data/com.xyz.abc/appfiles")){
            if (prefs.getBoolean("kitkatcheck", false)==false){

                //update mfolder from
                      // /mnt/sdcard/appfiles
                      // to
                      // /mnt/sdcard/Android/data/com.xyz.abc/appfiles
                String prekitkatfolder = mfolder;
                String kitkatfolder = mfolder.replace("/appfiles", "/Android/data/com.xyz.abc/appfiles");
                mfolder = kitkatfolder;
                try {
                    File sd = new File(mfolder);
                    if(!sd.exists() || !sd.isDirectory()) {
                        sd.mkdirs();
                    }
                } catch (Exception e) {
                    Toast.makeText(getBaseContext(), "Error creating Kitkat folder!\n" + e.toString(), Toast.LENGTH_LONG).show();
                    return;
                }
                prefEditor.putString("patternfolder", mfolder);
                prefEditor.putBoolean("kitkatcheck", true);
                prefEditor.commit();

                //copy files and folder from old appfiles folder to new.
                AllFiles.clear();
                listFilesAndFilesSubDirectories(prekitkatfolder);
                if (AllFiles.size()>0){
                    for (File child : AllFiles ) {
                        try {

                            File dest = new File(child.toString().replace(prekitkatfolder, kitkatfolder));


                            try {
                                String filePath = dest.getPath().substring(0, dest.getPath().lastIndexOf(File.separator));
                                File subfolder = new File(filePath);
                                if(!subfolder.exists() || !subfolder.isDirectory()) {
                                    subfolder.mkdirs();
                                }
                            } catch (Exception ex) {
                            }

                            copyFile(child, dest);  

                        } catch (Throwable t) {

                        }
                    }

                }


            }

        }

我会通知用户他们的文件已经复制到新文件夹,由于新权限,他们需要手动删除旧的prekitkatfolder文件夹。我猜只有当他们拥有原始文件管理器或将SD卡卸载并放入PC时,才能这样做,因为新的4.4权限限制了此操作?
另外,对我们来说,似乎这些4.4权限并没有影响所有使用Kitkat的用户。一些人仍然可以将文件写入其外部存储器的原始位置,而另一些人则会出现EACCES(权限被拒绝)错误。有谁能解释一下为什么会出现这种情况?人们可能认为这适用于所有使用外部存储器的4.4设备。
由于我们没有实际的4.4设备,我们必须使用模拟器(API 19)测试此代码,但我们没有收到EACCES权限被拒绝的错误。因此,我们发布了一个带有上述代码的beta版本,并被告知复制的文件最终存储在内部存储器中,这是怎么回事?
请问我们做错了什么,提前感谢您的帮助。

嗨,Zorac,我在某些设备上遇到了类似的情况:在路径中不需要包名称就能正常工作,在另一些设备上则需要添加长路径,例如/Android/data/com.xyz.abc/appfiles。不确定发生了什么。你找到解决方案了吗? - Ahmed
2个回答

7

更新的解决方案。

该解决方案将在正确的位置设置并创建文件夹,以适应KitKat系统。

mfolder = this.getExternalFilesDir("asubfoldername").getAbsolutePath();

然而,这并不是完美的解决方案,如果Android设备同时具有内部和外部次要存储位置,则上述方法将使用内部存储位置。这并不是我们想要的,因为我们需要可移动SD卡的路径或者最空闲可用空间的次要存储位置的路径。
File[] possible_kitkat_mounts = getExternalFilesDirs(null);

请注意getExternalFilesDirs末尾的"s"。这将创建一个次要外部存储位置的数组。
for (int x = 0; x < possible_kitkat_mounts.length; x++) {
    //Log.d("test", "possible_kitkat_mounts " + possible_kitkat_mounts[x].toString());
    boolean isgood=false;
    if (possible_kitkat_mounts[x] != null){
        isgood = test_mount(possible_kitkat_mounts[x].toString());  
        if (isgood==true){
            arrMyMounts.add(newymounts(Device_get_device_info(possible_kitkat_mounts[x].toString()), possible_kitkat_mounts[x].toString()));
        }   
    }
}                           

//sort arrMyMounts size so we can use largest
Collections.sort(arrMyMounts, new Comparator<mymounts>(){
    public int compare(mymounts obj1, mymounts obj2){
        return (obj1.avaliablesize > obj2.avaliablesize) ? -1: (obj1.avaliablesize > obj2.avaliablesize) ? 1:0 ;
    }
}); 


if (arrMyMounts.size()>0){
    mfolder = arrMyMounts.get(0).name + "/asubfoldername";
    //Log.d("test", "selected kitkat mount " + kitkatfolder);   
}else{
    //do something else...
}

通过测试挂载点 possible_kitkat_mounts,检查我们是否能够实际写入所选位置,如果成功,将该位置添加到 arrMyMounts 中。

通过对 arrMyMounts 进行排序,我们可以得到可用空间最多的位置。

嘿,arrMyMounts.get(0).name 就是拥有最多可用空间的 KitKat 次要存储位置。


我在三星Galaxy Note 10.1上安装了一个应用程序,它提供了内置的外部存储和可移动SD卡选项。我尝试使用上述方法(即getExternalFilesDirs(null))检索可移动SD卡的路径,但上下文中不存在此类方法。我所需要的就是获取SD卡的路径,以便创建特定于包的目录来读取/写入应用程序文件。我还尝试使用硬编码路径创建此目录,但不允许这样做。您能否帮忙解决这个问题?谢谢。 - Abdul Rehman
什么是'this'?这是哪个类? - Stealth Rabbi

5

4
但是ES文件浏览器可以在我的KitKat设备上创建文件夹!我做不到。 - Ali Yousefi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接