现在我们要创建一个与上面提到的标签对应的xml文件-->xml/.xml
其中,标签file-path和cache-path代表手机内存中的某个目录,path属性是该目录下的子目录,name属性是假名,会替换path目录的绝对路径
图中涉及到的子标签对应的路径如下:
子标签
子标签对应的绝对路径(不带路径)
子标签对应的绝对路径(添加路径)
笔名
文件路径
app私有存储区下的files目录
(.())
文件目录加路径
(.()/文件)
文件
缓存路径
应用私有目录下的缓存目录
(.())
私有缓存目录加路径
(.()/文件)
缓存
-小路
外部存储根目录
(.
())
外部存储根目录加路径
(.
()
/文件)
-文件路径
外部存储根目录下的文件目录
(.())
文件目录加路径
(.
()/文件)
-缓存路径
外部存储根目录下的缓存目录
(.())
缓存目录加路径
(.
()/文件)
最终结果是外部app获取到的共享目录,不是路径,而是假名
而且,每次添加共享目录时,都需要添加对应的子标签
例如,如果我添加一个新的共享目录,这是外部存储根目录下的文件夹,我添加一个子标签,如下所示:
就是这样
用于获取文件Uri
代码如下所示:
String path = Environment.getExternalStorageDirectory().getPath() + "/Pictures/dongqiudi/1523624189281.jpg";
File file = new File(path);
if (file.exists()) {
Uri uri = FileProvider.getUriForFile(MainActivity.this, "com.example.songzeceng.myFileProvider", file);
Log.i(TAG, "uri:" + uri.toString());
}
代码很简单,但是为了防止出错,我判断了文件是否存在(不存在怎么办,我没试过)
结果
正如您所看到的,它确实替换了我们用假名指定的共享目录路径。 这个uri和之前的路径uri不同,但是不影响使用,仍然会正确找到我们的文件。
通过uri获取文件路径
由于该类只有一个对外开放的()方法,所以如果想通过uri获取文件路径,就需要使用反射。
先说一下思路:
里面有一个类,实现了接口,负责文件uri和文件路径的转换。 通过调用对象自身的私有静态方法()来初始化对象,因此我们可以直接调用该方法来获取初始化后的对象。 然后调用这个对象的()方法获取uri对应的文件对象,最后通过文件对象获取路径。
代码看起来像这样
Class clazz = FileProvider.class;
Class> simplePathStrategyClazz = clazz.getDeclaredClasses()[0];
Method getPathStrategyMethod = clazz.getDeclaredMethod("getPathStrategy", Context.class, String.class);
getPathStrategyMethod.setAccessible(true);
Object simplePathStrategyObject = getPathStrategyMethod.invoke(null, MainActivity.this, "com.example.songzeceng.myFileProvider");
Method method = simplePathStrategyClazz.getDeclaredMethod("getFileForUri", Uri.class);
method.setAccessible(true);
File destFile = (File) method.invoke(simplePathStrategyObject, uri);
Log.i(TAG, "share: file path:" + destFile.getAbsolutePath());
首先获取类和类,我们需要的类就是这两个;
其次,获得()方法对象,方法输入参数是和,这个对象就是我们的身份。 当然,这个方法对象的可访问性应该设置为true;
再次调用()方法,传入上下文对象和标识字符串,获取对象。 这里只能使用类,因为外部不能访问任何类或类;
然后,获取类的()方法对象,以Uri对象作为输入参数,并将方法可访问性设置为true;
最后调用该对象的()方法,输入参数为Uri对象,强制类型转换为File后即可获取绝对路径。
程序运行的输出日志如下图所示
功能是可以实现的,但是反射的消耗非常高,使用时要三思。
结语
这个例子只是一个验证,看看文件uri是否被正确解析和转换,如果程序崩溃了,一切正常,那么我们就可以根据我们的业务使用新生成的uri