我有一个正确使用"外部存储"中的文件的应用程序。
最近我将Android Studio从2.2升级到2.3。在此升级之后,使用EACCESS (Permission denied)
在外部存储中创建文件时,应用程序将失败。
受影响的版本
我在 Android 4.0.3,4.1,4.2
中有错误我在 Android 4.3,4.4 及更高版本中没有错误。
代码示例
这是代码的一部分,失败
File tempFile = new File(Environment.getExternalStorageDirectory().toString() + "/.tmpfile");
if (!tempFile.exists() && !tempFile.createNewFile()) {
throw new IOException("Cannot create temp file");
}
在方法createNewFile()
中,EACCES
抛出异常:
java.io.IOException: open failed: EACCES (Permission denied)
at java.io.File.createNewFile(File.java:948)
...
Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
at java.io.File.createNewFile(File.java:941)
...
java.io.IOException: open failed: EACCES (Permission denied)
at java.io.File.createNewFile(File.java:948)
...
Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
at java.io.File.createNewFile(File.java:941)
... 15 more
当然,<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
中有AndroidManifest.xml
。
应用程序已授予权限。我通过以下方式在主要活动中查看:
if (checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_CODE);
}
并且requestCode == PackageManager.PERMISSION_GRANTED
是真的。
最奇怪的:当我尝试将代码回滚到之前稳定的生产版本时(当文件在2.2中成功创建时)并创建构建版本时,我得到相同的内容错误! :(我在模拟器中,在真实设备中得到此错误。
为什么呢? Android Studio 2.3中有哪些更改,我无法在旧Android中创建任何文件?
UPD 感谢尼克,他帮助我找到行为上的差异。我在Android 4.2和4.3上测试下面的行,然后得到:
Environment.getExternalStorageDirectory()
4.2: '/mnt/sdcard'
4.3: '/storage/sdcard'
ContextCompat.getExternalFilesDirs(this, null)
4.2: {null} (array with one null-element)
4.3: '/storage/sdcard/Android/data/com.example/files'
Environment.getExternalStorageState()
4.2: 'removed'
4.3: 'mounted'
答案 0 :(得分:3)
您的问题与Android 4.4中所做的更改有关。引用documentation:
有时,设备也可能提供SD卡插槽。当这样的设备运行Android 4.3及更低版本时,getExternalFilesDir()方法仅提供对内部分区的访问,并且您的应用无法读取或写入SD卡
该文档还提供了解决方案:
如果您想在支持Android 4.3及更低版本的同时访问这两个可能的位置,请使用支持库的静态方法
这指的是使用ContextCompat而非核心Android方法
File[] dirs = ContextCompat.getExternalFilesDirs(ctx, null); //null, no specific sub directory
if (dirs.length > 0) {
File ext = dirs[dirs.length -1]; //Just presuming SD card will be the last one offered
//use ext here like you used tempFile before
}
您还应该确保媒体可用,因为较低的Android版本更有可能使用低性能设备。使用Environment类
执行此操作String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
//safe
}
编辑
因此,完整的解决方案可能是替换
File tempFile = new File(Environment.getExternalStorageDirectory().toString() + "/.tmpfile");
使用
File tempFile = null;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
//compatible for ALL the versions
File[] dirs = ContextCompat.getExternalFilesDirs(ctx, null); //null, no specific sub directory
if (dirs.length > 0) {
tempFile = dirs[dirs.length -1];
}
}
if (tempFile != null) {
//here continue exactly as you did before
if (!tempFile.exists() && !tempFile.createNewFile()) {
throw new IOException("Cannot create temp file");
}
} else {
//handle case where sd card isnt reachable (notification etc)
}