为什么我需要在Android Lollipop上使用getExternalCacheDir()的WRITE_EXTERNAL_STORAGE权限?

mur*_*ayc 9 android android-file android-permissions

我的应用程序将缓存文件写入(并读取)到getExternalCacheDir()位置.在Android Lollipop(API 21)之前,我一直在使用此权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
Run Code Online (Sandbox Code Playgroud)

maxSdkVersion存在,因为在API v18之后不应该需要此权限:http: //developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE

但是在Android Lollipop(5.0)上,我获得了这样的访问权限(使用我的日志输出来显示实际使用的路径):

11-19 13:01:59.257    4462-4541/com.murrayc.galaxyzoo.app E/android-galaxyzoo?     createCacheFile(): IOException for filename=/storage/emulated/0/Android/data/com.murrayc.galaxyzoo.app/cache/52
    java.io.IOException: open failed: EACCES (Permission denied)
            at java.io.File.createNewFile(File.java:941)
            at com.murrayc.galaxyzoo.app.provider.ItemsContentProvider.createCacheFile(ItemsContentProvider.java:528)
Run Code Online (Sandbox Code Playgroud)

我在模拟器和我的Nexus 4中看到了这一点.有什么变化,或者我一直在做错什么?我只是想访问我自己的应用程序的缓存.

更新:我现在只在我的设备上看到这一点(运行标准Android 5.1.1的Nexus 4,自从我第一次遇到这个问题以来,它甚至有了新的Android重新刷新).我不再在模拟器中看到这一点 - 当然系统图像已经多次更新.

fin*_*cks 5

我们在Nexus 5上看到了API 21(Lollipop)上的相同行为:

java.io.FileNotFoundException: /storage/emulated/0/Android/data/[package name]/cache/http/journal.tmp: open failed: EACCES (Permission denied)
   at libcore.io.IoBridge.open(IoBridge.java:456)
   at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
   at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
   at com.android.okhttp.internal.DiskLruCache.rebuildJournal(DiskLruCache.java:346)
   at com.android.okhttp.internal.DiskLruCache.open(DiskLruCache.java:239)
   at com.android.okhttp.HttpResponseCache.<init>(HttpResponseCache.java:140)
   at android.net.http.HttpResponseCache.install(HttpResponseCache.java:199)
...
   at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011)
   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4518)
   at android.app.ActivityThread.access$1500(ActivityThread.java:144)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5221)
   at java.lang.reflect.Method.invoke(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
   at libcore.io.Posix.open(Posix.java)
   at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
   at libcore.io.IoBridge.open(IoBridge.java:442)
   at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
   at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
   at com.android.okhttp.internal.DiskLruCache.rebuildJournal(DiskLruCache.java:346)
   at com.android.okhttp.internal.DiskLruCache.open(DiskLruCache.java:239)
   at com.android.okhttp.HttpResponseCache.<init>(HttpResponseCache.java:140)
   at android.net.http.HttpResponseCache.install(HttpResponseCache.java:199)
...
   at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011)
   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4518)
   at android.app.ActivityThread.access$1500(ActivityThread.java:144)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5221)
   at java.lang.reflect.Method.invoke(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Run Code Online (Sandbox Code Playgroud)

在谷歌将Android 5.0推向AOSP之前,我们将无法解决它是否存在错误或故意(但未记录)的变化,但无论如何我都提出了这个错误:https: //code.google.com/p/安卓/问题/细节?ID = 81357

添加WRITE_EXTERNAL_STORAGE权限可防止抛出上述异常,但需要最终用户权限才能升级现有应用程序.由于我们的应用程序不使用此权限,并且我们不想添加它,因此我们将重新使用除KitKat设备之外的所有内部缓存.

顺便说一下,我发现这是KitKat中引入的变化的有趣背景:http://www.doubleencore.com/2014/03/android-external-storage/