在Android4.4之后,普通应用就没有外置SD卡的写权限了,对于要操作外置SD的应用来说就是个灾难了。
我最近做一个文件管理器,发现外卡只有读权限,没有办法进行其他操作,刚开始以为是需要运行时权限,然后进队权限进行申请,发现还是不行,然后继续百度Google基本上都是和权限有关,无意发现有一篇是写授权的,根据文章思路,对比了ES文件浏览器。确实在写外置SD卡文件时会弹出这样一个界面:
点击选择进入系统的一个文件目录界面:
点击“选择SD"卡,回来就可以对文件进行操作了。
大概思路就是,先去获取对sdcard进行授权
Intent intent = new Intent("android.intent.action.OPEN_DOCUMENT_TREE");
this.startActivityForResult(intent, requestCode);
过程如上图,点击左边sdcard,在点击右下角的选择,然后在onActivityResult中接收返回结果,如果没有选择sdcard则进行提示在此获取授权,如果获取授权成功,就保存treeUri,就是外置SD的文档Uri。这个Uri和普通Uri是不一样的,打印出来是这样的:
再去找文件操作时是怎么样的,发现外置SD卡都是通过DocumentFile进行文件写的。先根据之前保存的SD卡uri获取根DocumentFile,在一层一层获取子DocumentFile。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case requestCode:
if (resultCode == RESULT_OK) {
Uri treeUri = data.getData();
if (!":".equals(treeUri.getPath().substring(treeUri.getPath().length() - 1)) || treeUri.getPath().contains("primary")) {
Toast.makeText(this, "没有选择SDCARD!", Toast.LENGTH_LONG).show();
} else {
DocumentFile document = DocumentFile.fromTreeUri(this, treeUri);
String[] parts = getStoragePath() +"/test.txt".split(File.separator);
for (int i = 3; i < parts.length; i++) {
DocumentFile nextDocument = document.findFile(parts[i]);
if (nextDocument == null) {
if (i < parts.length - 1) {
if (true) {
nextDocument = document.createDirectory(parts[i]);
}
} else {
nextDocument = document.createFile("test.txt", parts[i]);
}
}
document = nextDocument;
}
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
获取sdcard路径
public String getStoragePath() {
String resultpath = "";
StorageManager mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class
.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod(
"getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Object result = getVolumeList.invoke(mStorageManager);
final int length = Array.getLength(result);
Method getUserLabel = storageVolumeClazz.getMethod("getUserLabel");
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String userLabel = (String) getUserLabel
.invoke(storageVolumeElement);
String path = (String) getPath.invoke(storageVolumeElement);
if (userLabel.contains("SD")) {
resultpath = path;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return resultpath;
}
path是要获取文件的路径,createDirectories是是否要新建,false用于获取DocumentFile执行删除操作,true用于新建文件。遍历不从0开始是因为path的是绝对路径,前面SD卡的路径不需要,从SD卡的第一层目录开始遍历。
有了思路就可以更好的找方法了,再在google搜DocumentFile,SD卡相关的,在stackOverFlow找到了这个:
下来就实现你想要的东西了,不过还有许多细节性的东西需要注意!