目录
背景描述:
解决方案:
处理过程中遇到的问题(代码中需要替换的点)
结尾:
9.0之后,Google合入一笔patch,去掉了WRITE_MEDIA_STORAGE权限中的sdcard_rw。导致之前的文件读写方式无法对sdcard生效
http://androidxref.com/9.0.0_r3/search?q=&defs=&refs=&path=&hist=86684240eb5753bb97c2cfc93d1d25fa1870f8f1&project=art&project=bionic&project=bootable&project=build&project=compatibility&project=cts&project=dalvik&project=developers&project=development&project=device&project=external&project=frameworks&project=hardware&project=kernel&project=libcore&project=libnativehelper&project=packages&project=pdk&project=platform_testing&project=prebuilts&project=sdk&project=system&project=test&project=toolchain&project=tools
DocumentFile
//申请目录权限
private void getSdCardPermission(){
StorageManager mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
boolean canFindPath=false;
//获取所有挂载的设备(内部sd卡、外部sd卡、挂载的U盘)
List volumes = mStorageManager.getStorageVolumes();
try {
Class> storageVolumeClazz = Class
.forName("android.os.storage.StorageVolume");
//通过反射调用系统hide的方法
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
for (int i = 0; i < volumes.size(); i++) {
StorageVolume storageVolume = volumes.get(i);//获取每个挂载的StorageVolume
//通过反射调用getPath、isRemovable
storagePath = (String) getPath.invoke(storageVolume); //获取路径
boolean isRemovableResult = (boolean) isRemovable.invoke(storageVolume);//是否可移除
String description = storageVolume.getDescription(this);
android.util.Log.d(TAG, " i=" + i + " ,storagePath=" + storagePath
+ " ,isRemovableResult=" + isRemovableResult +" ,description="+description);
// i=0 ,storagePath=/storage/emulated/0 ,isRemovableResult=false ,description=内部共享存储空间
// i=1 ,storagePath=/storage/B8EA-15F1 ,isRemovableResult=true ,description=SD卡
if (filePath.contains(storagePath)){
this.storageVolume=storageVolume;
canFindPath=true;
break;
}
}
} catch (Exception e) {
android.util.Log.d("jason", " e:" + e);
}
if (!canFindPath){
this.storageVolume=null;
Toast.makeText(this,"filePath not find",Toast.LENGTH_SHORT).show();
return;
}
if (storageVolume!=null&&canFindPath){
Intent intent = storageVolume.createAccessIntent(getDirectoryName("DCIM"));//
permissionPath=storagePath + File.separator+"DCIM";
startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
}
}
//请求成功之后,权限持久化
getContentResolver().takePersistableUriPermission(uriForPermissionPath,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
//持久化之后的权限可以通过下面方法获取所有已经获得授权的uriPermission
List persistedUriPermissions = context.getContentResolver().getPersistedUriPermissions();
//获取授权的uri
Uri uri = persistedUriPermissions.get(0).getUri();
//根据uri获取DocumentFile对象
DocumentFile documentFile= DocumentFile.fromTreeUri(context, parentUri);
//创建目录或者文件
//获取权限路径之后的未知目录结构 /100MEDIA/VIDEO0001_01.mp4.hyperlapse
String replace = outPath.replace(permissionPath, "");
//循环取得各层级目录名,判断是否存在并创建
String[] split = replace.split(File.separator);
for (int i = 0; i
1、权限获取方式
2、文件/目录的创建、删除、重命名方式
3、其他文件相关的类的初始化或者方法调用,不能直接传入path,需要改为FileDescriptor。
3.1、MediaMuxer(@NonNull FileDescriptor fd, @Format int format)//初始化时使用FileDescriptor
3.2、RandomAccessFile raf = new RandomAccessFile(ori, "rws");//不支持,无法初始化RandomAccessFile
//*****Open file channel to read byte
FileChannel fc = raf.getChannel();
3.3、MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(FileDescriptor fd);//setDataSource方法需要传入FileDescriptor
3.4、MediaMetadataRetriever retriever = new MediaMetadataRetriever();
if (!inExtStorage){
retriever.setDataSource(pfd.getFileDescriptor());//setDataSource方法需要传入FileDescriptor
}else{
retriever.setDataSource(mContext, Uri.parse(path));
}
3.5、MovieCreator.build(FileChannel in);//入参的获取方式需要通过DocumentFile,不能直接通过路径
in = new FileInputStream(filePath).getChannel();
DocumentFile documentFileByPath = FileUtils.getDocumentFileByPath(filePath);
pfd = context.getContentResolver().openFileDescriptor(documentFileByPath.getUri(), "rw");
in = new FileInputStream(pfd.getFileDescriptor()).getChannel();
3.6、WritableByteChannel fc = null;//获取方式不能通过path,类似与3.5
3.5和3.6:都属于FileInputStream、FileOutputStream、FileDescriptor、FileChannel的获取方式
以上是目前的进展,简单的做一个总结.