对于Android的一些文件,假如我们要实现和电脑上选择打开方式的话,Android上面提供了比较简便的方式。
首先获取文件类型,即MIME类型
MIME类型表后面附上
/** * 根据文件后缀名获得对应的MIME类型。 * @param file */
private static String getMIMEType(File file) {
String type="*/*";
String fName = file.getName();
//获取后缀名前的分隔符"."在fName中的位置。
int dotIndex = fName.lastIndexOf(".");
if(dotIndex < 0){
return type;
}
/* 获取文件的后缀名 */
String end=fName.substring(dotIndex,fName.length()).toLowerCase();
if(end=="")return type;
//在MIME和文件类型的匹配表中找到对应的MIME类型。
for(int i=0;i<MIME_MapTable.length;i++){ //MIME_MapTable??在这里你一定有疑问,这个MIME_MapTable是什么?
if(end.equals(MIME_MapTable[i][0]))
type = MIME_MapTable[i][1];
}
return type;
}
通过intent调用系统安装的软件打开文件
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//设置intent的Action属性
intent.setAction(Intent.ACTION_VIEW);
//获取文件file的MIME类型
String type = getMIMEType(file);
intent.setDataAndType(/*uri*/Uri.fromFile(file), type);
//跳转
context.startActivity(intent);
以上就是正常情况下打开文件的方法,但是在Android 7.0的机子上回报android.os.FileUriExposedException错误,原因在于Android 7.0的安全策略变了,解决方法是用provider来实现打开文件。
首先是AndroidManifest文件里面注册FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.your.app.provider"
android:exported="false" //必须为false
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> //需要自己编写xml文件
</provider>
provider_paths.xml文件的编写
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>// .表示根目录
</paths>
修改打开文件的方法
Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName()+".provider", file); //android 7.0以上
intent.setDataAndType(fileUri, type);
需要grantUriPermission方法添加权限
private static void grantUriPermission (Context context, Uri fileUri, Intent intent) {
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
最后打开文件的方法为
/** * 打开文件 * @param file */
public static void openFile(Context context, File file){
try {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//设置intent的Action属性
intent.setAction(Intent.ACTION_VIEW);
//获取文件file的MIME类型
String type = getMIMEType(file);
//设置intent的data和Type属性。android 7.0以上crash,改用provider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName()+".provider", file);//android 7.0以上
intent.setDataAndType(fileUri, type);
grantUriPermission(context, fileUri, intent);
}else {
intent.setDataAndType(/*uri*/Uri.fromFile(file), type);
}
//跳转
context.startActivity(intent);
}catch (Exception e){
e.printStackTrace();
showAlert(context, "File corrupted, download again please.");
}
}
最后附上MIME类型表
private static final String[][] MIME_MapTable={
//{后缀名, MIME类型}
{ ".3gp", "video/3gpp"},
{ ".apk", "application/vnd.android.package-archive"},
{ ".asf", "video/x-ms-asf"},
{ ".avi", "video/x-msvideo"},
{ ".bin", "application/octet-stream"},
{ ".bmp", "image/bmp"},
{ ".c", "text/plain"},
{ ".class", "application/octet-stream"},
{ ".conf", "text/plain"},
{ ".cpp", "text/plain"},
{ ".doc", "application/msword"},
{ ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
{ ".xls", "application/vnd.ms-excel"},
{ ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{ ".exe", "application/octet-stream"},
{ ".gif", "image/gif"},
{ ".gtar", "application/x-gtar"},
{ ".gz", "application/x-gzip"},
{ ".h", "text/plain"},
{ ".htm", "text/html"},
{ ".html", "text/html"},
{ ".jar", "application/java-archive"},
{ ".java", "text/plain"},
{ ".jpeg", "image/jpeg"},
{ ".jpg", "image/jpeg"},
{ ".js", "application/x-javascript"},
{ ".log", "text/plain"},
{ ".m3u", "audio/x-mpegurl"},
{ ".m4a", "audio/mp4a-latm"},
{ ".m4b", "audio/mp4a-latm"},
{ ".m4p", "audio/mp4a-latm"},
{ ".m4u", "video/vnd.mpegurl"},
{ ".m4v", "video/x-m4v"},
{ ".mov", "video/quicktime"},
{ ".mp2", "audio/x-mpeg"},
{ ".mp3", "audio/x-mpeg"},
{ ".mp4", "video/mp4"},
{ ".mpc", "application/vnd.mpohun.certificate"},
{ ".mpe", "video/mpeg"},
{ ".mpeg", "video/mpeg"},
{ ".mpg", "video/mpeg"},
{ ".mpg4", "video/mp4"},
{ ".mpga", "audio/mpeg"},
{ ".msg", "application/vnd.ms-outlook"},
{ ".ogg", "audio/ogg"},
{ ".pdf", "application/pdf"},
{ ".png", "image/png"},
{ ".pps", "application/vnd.ms-powerpoint"},
{ ".ppt", "application/vnd.ms-powerpoint"},
{ ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
{ ".prop", "text/plain"},
{ ".rc", "text/plain"},
{ ".rmvb", "audio/x-pn-realaudio"},
{ ".rtf", "application/rtf"},
{ ".sh", "text/plain"},
{ ".tar", "application/x-tar"},
{ ".tgz", "application/x-compressed"},
{ ".txt", "text/plain"},
{ ".wav", "audio/x-wav"},
{ ".wma", "audio/x-ms-wma"},
{ ".wmv", "audio/x-ms-wmv"},
{ ".wps", "application/vnd.ms-works"},
{ ".xml", "text/plain"},
{ ".z", "application/x-compress"},
{ ".zip", "application/x-zip-compressed"},
{ "", "*/*"}
};
按照上面的步骤来操作的话,你就可以实现选择打开方式了,不过要记得修改注册FileProvider和provider_paths.xml文件中对应地方的你的应用包名。