Android(安卓)9.0 sdCard文件读写
目录
背景描述:
解决方案:
处理过程中遇到的问题(代码中需要替换的点)
结尾:
背景描述:
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);//持久化之后的权限可以通过下面方法获取所有已经获得授权的uriPermissionList persistedUriPermissions = context.getContentResolver().getPersistedUriPermissions();//获取授权的uriUri uri = persistedUriPermissions.get(0).getUri();//根据uri获取DocumentFile对象DocumentFile documentFile= DocumentFile.fromTreeUri(context, parentUri);//创建目录或者文件//获取权限路径之后的未知目录结构 /100MEDIA/VIDEO0001_01.mp4.hyperlapseString 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的获取方式
结尾:
以上是目前的进展,简单的做一个总结.
更多相关文章
- 解决Android(安卓)应用方法数不能超过65K的问题
- drawable(hdpi,ldpi,mdpi)的区别
- Android培训班(73)Dex文件里类定义dvmDefineClass
- google api8
- Android获取视频文件某一帧并设置图片
- Android文件储存
- Android(安卓)Sensor框架简述(三)
- Android培训班(72)Dex文件里类定义dvmDefineClass
- Android(安卓)复制和删除文件夹和文件