欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于android7.0的FileProvider获取File路径

程序员文章站 2022-04-15 22:06:41
...

关于FileProvider的使用,网上随便搜索一下,都有一堆使用的教程说明,但这些说明,都只是告诉我们配置FileProvider,使系统认识这个FileProvider. 但是在我的项目中需要的是获取文件的绝对路径,于是就有了这个文章.

说明


Android 7.0的新特性规定,对于android 7.0应用(仅仅对于android 7.0版本的sdk而言,若是编译版本低于25仍然不会受到影响),android框架使用StrictMode Api禁止我们的应用对外部(跨越应用分享)公开file://,若使用file://格式共享文件则会报FileUriExposedException异常,android 7.0应用间的文件共享需要使用content://类型的URI分享,并且需要为其提供临时的文件访问权限 
(Intent.FLAG_GRANT_READ_URI_PERMISSION和Intent.FLAG_GRANT_WRITE_URI_PERMISSION),对此,官方给我们的建议是使用FileProvider类进行分享.

由于android7.0的处理,

Uri uri = intent.getData();

我们使用这句话获取到的uri是一个content类型的uri,而不是file类型了,这与我们需要的(文件路径)是不一样的,在网上查询无果后,开始自己查看源码FileProvider

值得我们注意的是

public class FileProvider extends ContentProvider
这个FileProvider 继承自我们的ContentProvider,
 interface PathStrategy {
        Uri getUriForFile(File var1);

        File getFileForUri(Uri var1);
    }

还有这个接口 这个接口看起来就是用来封装uri和File的,

查看源码发现我们对我们开放的只有获取uri的方法并没有获取file的方法

public static Uri getUriForFile(Context context, String authority, File file) {
        FileProvider.PathStrategy strategy = getPathStrategy(context, authority);
        return strategy.getUriForFile(file);
    }
于是想到了使用反射大法:

  直接贴上代码  当然这代码中我们必须要先拿到一个uri才行


List<PackageInfo> packs = this.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
if (packs != null) {

   String fileProviderClassName = FileProvider.class.getName();
   for (PackageInfo pack : packs) {
      ProviderInfo[] providers = pack.providers;
      if (providers != null) {
         for (ProviderInfo provider : providers) {

            if (uri.getAuthority().equals(provider.authority)){
               if (provider.name.equalsIgnoreCase(fileProviderClassName)) {
                  Class<FileProvider> fileProviderClass = FileProvider.class;
                  try {
                     Method getPathStrategy = fileProviderClass.getDeclaredMethod("getPathStrategy", Context.class , String.class);
                     getPathStrategy.setAccessible(true);
                     Object invoke = getPathStrategy.invoke(null, this, uri.getAuthority());
                     if (invoke != null) {
                        String PathStrategyStringClass = FileProvider.class.getName()+"$PathStrategy";
                        Class<?> PathStrategy = Class.forName(PathStrategyStringClass);
                        Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
                        getFileForUri.setAccessible(true);
                        Object invoke1 = getFileForUri.invoke(invoke, uri);
                        if (invoke1 instanceof File) {
                           filePath = ((File) invoke1).getAbsolutePath();
                          
                        }
                     }


                  } catch (NoSuchMethodException e) {
                     e.printStackTrace();
                  } catch (InvocationTargetException e) {
                     e.printStackTrace();
                  } catch (IllegalAccessException e) {
                     e.printStackTrace();
                  } catch (ClassNotFoundException e) {
                     e.printStackTrace();
                  }

                  break;
               }
               Log.e(provider);
               break;
            }
         }

      }

   }
}

这样我们就能拿到了 File对象进而拿到绝对路径了

有什么没考虑到的地方欢迎指出


文笔不好 哪里看不明白可以评论提问