Filedownloader: Access denied to download in sd card

Created on 22 Feb 2016  ·  49Comments  ·  Source: lingochamp/FileDownloader

In Android 5.0 and greater, if I try to download any file in external sd card, I get a IOException: access denied: "open failed: EACCES (Permission denied)". The download path is set to /storage/sdcard1/my_file.xml

enhancement question

Most helpful comment

I think you need to get permission on runtime.

All 49 comments

If you want to download the file to the SDCARD's root path, please declare the w/r permission in your AndroidManifest.xml.

P.S: I do not recommend to download the file to the SDCARD's root path directly.

The permission is already declared: android.permission.WRITE_EXTERNAL_STORAGE

OK, I know. Please check following settings:

Settings->Apps->[Your App]->Permissions

I don't have app permissions settings in android 5.x, only in android 6. I can write in internal storage without problems, but when I try to write in external sdcard, the exception is thrown.

Is the permission declared like this?

<uses-permission
        android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />
<uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />

I'm afraid the problem persist if I declared the permissions like that.

If you declared the permissions like that, it would be wrong. that is a wrong case for your requirement.

Could you give me your sample demo project (by Gmail([email protected]) or by Github repo), I will do my best find out the reason.

I will try to provide an example by tomorrow, thanks.

ok.

Hi, I have created an example project on this repository:

https://github.com/victordigio/DownloadTest

Steps:

  1. Install on device with android >= 5.0 with external sdcard
  2. Click on "Choose path" and select external sdcard
  3. Click on "download file".

That is the error it shows:

screenshot_2016-02-23-09-40-06

ok, get

<uses-permission
        android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <!-- android:maxSdkVersion="18" -->
<uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <!-- android:maxSdkVersion="18" --> 

Sorry, It seems not so simple. There may be other reasons.

No worries. I guess it's something related with the new Storage Access Framework in android lollipop, but I'm not sure.

......
I just change the permission-declare like that(remove android:maxSdkVersion="18"), everything runs ok in Nexus 5(Android M).

Following is a Record-Gif.

abcde

I have removed android:maxSdkVersion from permissions. The problem persist if I download the file on external sd card. In your example, you are downloading the file on internal memory I think (storage/emulated/0). If I download the file in that path, the download is successfull for me too, but when I pick external sd card, I get the error.

Please look the Record-Gif carefully, The Record-Gif just for your repo's project,

image

image

1__adb_shell__adb_

I recommend that please remove android:maxSdkVersion from permissions, and retry your project in the other phone.(Just try it, maybe your phone ROM's bug?).

And in the FileDownloader's demo project, I download files in my app's external cache dir( /sdcard/Android/data/com.liulishuo.filedownloader.demo/cache), which is recommended by Google( https://www.youtube.com/watch?v=C28pvd2plBA&feature=iv&src_vid=BKU-wmTAPdc&annotation_id=annotation_3791593857)

I didin't push the changes to the repository. I just pushed them. I can get this error in any device I have with Android 5.0 and 5.1, so I dont think is a rom bug.

I already know that if you download the file in the internal memory, download is successfull. That is not the problem. The problem happens when you download the file in EXTERNAL sd card.

Steps:

  1. Install on device with android 5.0 or 5.1 with external sdcard
  2. Click on "Choose path" and select external sdcard
  3. Click on "download file".

In your video, you are not doing this.

That is not what I wanted.

I wanted that:

Steps:

  1. Install on device with android >= 5.0 with external sdcard
  2. Click on "Choose path" and select external sdcard
    screenshot_2016-02-23-16-42-28

screenshot_2016-02-23-16-42-28

screenshot_2016-02-23-16-42-28

screenshot_2016-02-23-16-42-28

Click on "download file".

screenshot_2016-02-23-16-42-28

Sorry for my confuse about your case, I know what you said the EXTERNAL sdcard(maybe microSD cards...) is now.

At the moment, there is no device can simulate your case, and I check tomorrow in my company.

On the other hand, I didn't find any post to prove your suppose( SAF with Android 5.0 Lollipop relate this problem), what about you?

I think is a problem with the Storage Access Framework in lollipop. In that version, you can't write in external sd without grant permissions with the native explorer. After select a folder with the file explorer, android knows that the app has permissions to write there. After that, I can write files manually from java code, but the library still can't write there.

http://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-lollipop

Sorry, My English is too poor to express my idea, I will answer the question with both Chinese and English. If you have any confuse by my answer with English, please translate the Chinese, it will be helpful.

This is interesting, because the permission of application in Android is based on each app (as the app permission in Android is based on Linux system, in which each app is seen as an individual user) Therefore, as long as you have permission on the app, and as library is part of the app, there shouldn’t be any problem that it’s ok you can write from java code but can’t do the same thing from the library within the same app. (P.S: we didn't declare any permission on the FileDownloader library, because app did)

这很有趣啊,Android中的权限是以 应用为一个单位的(Android中应用的权限处理,是基于Linux的权限处理,每个应用被模拟为一个用户). 既然App都有权限了,library引用到项目中也是App的一部分,没理由你用代码写就没有问题,而同一个app,在被依赖的library中写就会有权限问题。(P.S: 在library中我们是没有申请任何的权限的, 因为你在应用中申请就可以了)

Right now, I can't find an Android L phone which supports the expand EXTERNAL SDCARD, There is less and less phone supports expand EXTERNAL SDCARD, including Nexus5, Nexs5x, Nexus6, Nexus6p, etc.

现在我们这边没有并没有找到支持拓展SDCARD的Android L的手机。 现在市面上也越来越少的手机支持拓展SDCARD了,包括Nexus5,Nexus5x, Nexus6, Nexus6p, etc.

P.S: You can try to get your app's cache storage path which is recommended by Google to save your app's cache to the external 'sdcard' through the code Context#getExternalCacheDir(), and check the path, and it will be great if you can paste it out. The reason why I wanted to see this path is maybe it can help me to better understand your problem. For now, the demo project in our FileDownloader uses this default path(which is different from the path got from Context#getCacheDir(), Context#getExternalCacheDir() is the one Android got from SDCard). If the phone you are using does not support expand EXTERNAL SDCARD, the Android will mock an SDCARD using part of internal memory space, and for the app, this mocked SDCARD is the same as an expand EXTERNAL SDCARD. Also, the path got from Context#getExternalFilesDir() or Context#getExternalCacheDir() or Context#getExternalMediaDirs() has several features:

  1. It doesn't need to declare the EXTERNAL-W/R permission anymore upon API18 to W/R for these paths.
  2. It will be cleared by some case following Android Rule( uninstall the app, etc.)

P.S: 可以试试你那边通过 Context#getExternalCacheDir() 来获取Google官方推荐你的应用的cache存储路径,看看这个路径是什么路径,方便的话可以贴出来。其实之所以提到这个路径的原因是为了更好的解决你的问题: 目前我们FileDownloader的demo project当中默认是使用该路径(该路径是有别与Context#getCacheDir()获取的路径,该路径是Android中获取的SDCard上的路径(如果当前手机不支持拓展SDCARD,Google就会Mock一块内部空间作为SDCARD并且这部分空间对于应用而言,与拓展的SDCARD无异),而该路径有几个特性:

  1. 在API 18以上不需要申请读写权限也可以读写该目录;
  2. 在应用卸载,或者手机清理的时候也会对该路径进行处理;

因此你可以看到FileDownloader的demo project中的权限申请才带了 android:maxSdkVersion="18" 这个属性。

Context#getExternalCacheDir() returns: "/storage/emulated/0/Android/data/com.test.downloadtest/cache.

In my app, users can select a path to download files, so I can't limit the download folder to a cache folder only.

Tip:

When you get a OutputStream to write a file, you usually do new FileOutputStream(file), and then you do outStream.write(...). But in android 5, to write in some paths like an micro sd card, you can't do this.

You should do something like:

DocumentFile targetDocument = getDocumentFile(context, file, false, true, treeUri); outStream = context.getContentResolver().openOutputStream(targetDocument.getUri());

After that you can do a outStream.write(..);

Function getDocumentFile() is in FileUtil class in my repository. TreeUri parameter is what you get after open native file explorer in android 5. See onActivityResult method in MainActivity.class. There, I get this variable after open native file explorer.

Hi, any updates?

Sorry, I will handle this issue very seriously, when I'm free, Thanks for your patience.

I think you need to get permission on runtime.

这个问题我也遇到了,同样的错误提示。不过机器是HTC 6.0的系统。开始也以为只是权限的问题,但只在那一台机器会有问题,其他设备和系统都没问题(也包括6.0系统)。不过那机器是老板的私人手机,所以没好意思拿过来调试...“I think you need to get permission on runtime."暂时猜想也是这样,还没验证。

As per Android policies, API 19 and after, to provide better security for sdcard google only permits storing files in your app's private data folder inside SDCARD. It works fine if we give location equal to our private folder on sdcard inside data folder otherwise it returns the same error.

结合sudarshaana和deepinder10的回答进行了修改,该问题得到了解决。

@victordigio do you find any solution for the problem ??

@faraz20 Nothing. I ended up giving up .

I run in similar problem with other lib. The problem is that the access to external memory (eg microSD card) has been restricted in something like Android 4.4, and then re-enabled in 5.0 using such a weird thing as SAF. It was too complex for me to figure out how to use it to gain WRITE permission to external sd card for me so far.

@Jacksgong do you have any avance in this issue?

https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous

i met a similar bug in my demo (but only in android 6.0), you should read the doc.

@sudarshaana is right if your are running your app on android 6 or higher you need to ask user for permission at runtime

之前在华为Mate8(Android 6.0)上遇到过类似的情况:已测试的几款手机都可以写到SD卡,但是Mate8不行,而且代码中已经加了读写权限。后来发现把targetSDKVersion由25改成了22后,Mate8上可正常使用了,另项目中 complieSDKVersion 为25 和 buildToolsVersion 为24.0.0。

Any news on this issue? I've just run into the same problem, writing to external sdcard on Android 6 doesn't work. Writing to internal memory works fine.

This is probably because you can only write to an external SD card (outside of the data folder) using output streams from a DocumentFile

哈哈哈笑死我了
\
\
seeming non-solvable
I want this interface too,the same as estrongs exploer、quickpic viewer
image
!!
!!
how do they achieve this?those mysterious developers.

i hate it ,and i will never yield or give up..

Hi ,

I have also same above issue but I don't know how to get select Sd card explorer by app

can anyone pls help me

This has been covered on okdownload.

Was this page helpful?
0 / 5 - 0 ratings