1 强制过滤 FileUriExposedException 异常
VmPolicy方式 我在调研的时候观察到严格模式的一个方法:StrictMode.VmPolicy.Builder.detectFileUriExposure()。顾名思义,调用这个方法就会检测FileUriExposure这件事。这个方法其实从API18就有了,是不是有可能在API24变成了默认选项呢? 在Application.onCreate加入如下代码,置入一个不设防的VmPolicy:
/**************解决Android 7.0 FileUriExposedException url异常***********************/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
2.通过FileProvider在应用间文件共享
应用开发中遇到调用Intent打开文件地方无法出现选择。以为是个别用户手机上没有此类软件。后查看发现这些用户手机系统都是android7.0,查看7.0对于Intent的使用发现The increased level of file access security offered by a content URI makes FileProvider a key part of Android's security infrastructure.
android7.0之后,安全级别升级了。为了保护源文件,所以限制了其访问权限。使用第三方应用打开文件的时候会通过FileProvider ,生成 content URI允许您使用临时访问权限来授予读取和写入访问权限。关于FileProvider的介绍和使用。
我需要使用的功能是打开 文件
1.配置文件中定义FileProvider
FileProvider是v4包中一个继承ContentProvider的子类,位置是android.support.v4.content,他可以通过File创建一个content://类型的Uri而不是file://类型的Uri.所以我们在使用的使用首先需要在清单文件中注册一个provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="njxx.npc.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
</provider>
这里是直接使用的v4包中的FileProvider,我们也可以直接继承FileProvider类,适当重写重载函数,但不建议如此做。下面来介绍上面的几个设置:
- name:provider的类名,若使用默认的v4的FileProvider可使用”android.support.v4.content.FileProvider”,也可以设置为自定义的继承FileProvider的provider类;
- authorities:一个签名认证,可以自定义,但在获取uri的时候需要保持一致;
grantUriPermissions:使用FileProvider的使用需要我们给流出的URI赋予临时访问权限(READ和WRITE),该设置是允许我们行使该项权力; - meta-data:meta-data配置的是我们可以访问的文件的路径配置信息,需要使用xml文件进行配置,FileProvider会通过解析xml文件获取配置项,其中name名字不可改变为:android.support.FILE_PROVIDER_PATHS,resource为配置路径信息的配置项目。
2.创建file_paths文件
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="npc_files"
path="/njxx/npc/download" />
<external-path
name="npc_apk"
path="/njxx/npc/updated" />
</paths>
3.配置file_paths
路径配置
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
provider 配置信息(authorities)
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="njxx.npc.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
打开文件操作(根据 authorities)
public void openFile(File file, Context context) {
if (Build.VERSION.SDK_INT >= 23) {
Intent intent = new Intent(Intent.ACTION_VIEW);
String type = getMIMEType(file);
Uri uri = FileProvider.getUriForFile(context, "njxx.npc.fileprovider", file);
intent.setDataAndType(uri, type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
context.startActivity(intent);
} catch (Exception var5) {
var5.printStackTrace();
Toast.makeText(context, "没有找到打开此类文件的程序", Toast.LENGTH_SHORT).show();
}
} else {
Intent intent = new Intent(Intent.ACTION_VIEW);
String type = "application/vnd.android.package-archive";
intent.setDataAndType(Uri.fromFile(file), type);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
获取文件类型
public String getMIMEType(File file) {
String var1 = "";
String var2 = file.getName();
String var3 = var2.substring(var2.lastIndexOf(".") + 1, var2.length()).toLowerCase();
var1 = MimeTypeMap.getSingleton().getMimeTypeFromExtension(var3);
return var1;
}