我的应用程序将缓存文件写入(并读取)到getExternalCacheDir()位置。在Android Lollipop(API 21)之前,我一直在成功使用此权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
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)
我在模拟器和Nexus 4中都看到了这一点。有什么变化,或者我一直在做错什么?我只是想访问我自己的应用程序缓存。
更新:我现在只能在我的设备上看到这一点(运行标准Android 5.1.1的Nexus 4,自从我第一次遇到此问题以来,它甚至有了新的Android重新启动)。我不再在模拟器中看到这一点 - 当然系统图像已经多次更新。
答案 0 :(得分: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)
在谷歌将Android 5.0推向AOSP之前,如果它出现了错误或故意(但没有记录)的变化,我们就无法解决这个问题,但是我提出了这个错误,无论如何: https://code.google.com/p/android/issues/detail?id=81357
添加WRITE_EXTERNAL_STORAGE权限可防止抛出上述异常,但需要最终用户权限才能升级现有应用。由于我们的应用未使用此权限,而我们不想添加该权限,因此除了KitKat设备之外,我们还会重新使用内部缓存。
顺便说一句,我发现这是KitKat中引入的变化的有趣背景:http://www.doubleencore.com/2014/03/android-external-storage/