目录

 

背景描述:

解决方案:

处理过程中遇到的问题(代码中需要替换的点)

结尾:


背景描述:

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的获取方式

结尾:

以上是目前的进展,简单的做一个总结. 

更多相关文章

  1. 解决Android(安卓)应用方法数不能超过65K的问题
  2. drawable(hdpi,ldpi,mdpi)的区别
  3. Android培训班(73)Dex文件里类定义dvmDefineClass
  4. google api8
  5. Android获取视频文件某一帧并设置图片
  6. Android文件储存
  7. Android(安卓)Sensor框架简述(三)
  8. Android培训班(72)Dex文件里类定义dvmDefineClass
  9. Android(安卓)复制和删除文件夹和文件

随机推荐

  1. Android 高德地图 Native method not fou
  2. Android Material Design: NavigationVie
  3. android UI小结(二)
  4. AIDL——Android接口描述语言
  5. anroid的RelativeLayout的一些xml配置
  6. 【Android】Android 广播大全
  7. Android程序开发中关于设置全屏无效问题
  8. android去除ImageButton白色边框
  9. Android API中文文档系列Manifest
  10. Android利用sqlite制作简单登录界面