一、为什么要用第三方软件打开文件
假如在应用中下载下来一个word文件,并把文件保存至指定位置后。用户想要打开文件,不可能让用户对照着保存目录去找,这时候就需要通过指定的方法来调用对应的第三方软件来打开该文件。
二、主要方法
intent.setDataAndType(URI date,String Type)
:在Intent中传入文件的Uri路径和文件格式对应的"Type"值。
三、实例
1、代码展示
- FileOpen类
public class FileOpen {
public static void openFile(Context context, File file){
Intent intent = new Intent(Intent.ACTION_VIEW);
//intent.addCategory(Intent.CATEGORY_DEFAULT);
Uri uriForFile;
if (Build.VERSION.SDK_INT > 23){
//Android 7.0之后
uriForFile = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", file);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);//给目标文件临时授权
}else {
uriForFile = Uri.fromFile(file);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//系统会检查当前所有已创建的Task中是否有该要启动的Activity的Task;
// 若有,则在该Task上创建Activity;若没有则新建具有该Activity属性的Task,并在该新建的Task上创建Activity。
intent.setDataAndType(uriForFile,getMimeTypeFromFile(file));
context.startActivity(intent);
}
/**
* 使用自定义方法获得文件的MIME类型
*/
private static String getMimeTypeFromFile(File file) {
String type = "*/*";
String fName = file.getName();
//获取后缀名前的分隔符"."在fName中的位置。
int dotIndex = fName.lastIndexOf(".");
if (dotIndex > 0) {
//获取文件的后缀名
String end = fName.substring(dotIndex, fName.length()).toLowerCase(Locale.getDefault());
//在MIME和文件类型的匹配表中找到对应的MIME类型。
HashMap map = MyMimeMap.getMimeMap();
if (!TextUtils.isEmpty(end) && map.keySet().contains(end)) {
type = map.get(end);
}
}
return type;
}
}
- MyMimeMap
public class MyMimeMap {
private static final HashMap mapSimple = new HashMap<>();
/**
* 常用"文件扩展名—MIME类型"匹配表。
* 注意,此表并不全,也并不是唯一的,就像有人喜欢用浏览器打开TXT一样,你可以根据自己的爱好自定义。
*/
public static HashMap getMimeMap() {
if (mapSimple.size() == 0) {
mapSimple.put(".3gp", "video/3gpp");
mapSimple.put(".apk", "application/vnd.android.package-archive");
mapSimple.put(".asf", "video/x-ms-asf");
mapSimple.put(".avi", "video/x-msvideo");
mapSimple.put(".bin", "application/octet-stream");
mapSimple.put(".bmp", "image/bmp");
mapSimple.put(".c", "text/plain");
mapSimple.put(".chm", "application/x-chm");
mapSimple.put(".class", "application/octet-stream");
mapSimple.put(".conf", "text/plain");
mapSimple.put(".cpp", "text/plain");
mapSimple.put(".doc", "application/msword");
mapSimple.put(".docx", "application/msword");
mapSimple.put(".exe", "application/octet-stream");
mapSimple.put(".gif", "image/gif");
mapSimple.put(".gtar", "application/x-gtar");
mapSimple.put(".gz", "application/x-gzip");
mapSimple.put(".h", "text/plain");
mapSimple.put(".htm", "text/html");
mapSimple.put(".html", "text/html");
mapSimple.put(".jar", "application/java-archive");
mapSimple.put(".java", "text/plain");
mapSimple.put(".jpeg", "image/jpeg");
mapSimple.put(".jpg", "image/jpeg");
mapSimple.put(".js", "application/x-javascript");
mapSimple.put(".log", "text/plain");
mapSimple.put(".m3u", "audio/x-mpegurl");
mapSimple.put(".m4a", "audio/mp4a-latm");
mapSimple.put(".m4b", "audio/mp4a-latm");
mapSimple.put(".m4p", "audio/mp4a-latm");
mapSimple.put(".m4u", "video/vnd.mpegurl");
mapSimple.put(".m4v", "video/x-m4v");
mapSimple.put(".mov", "video/quicktime");
mapSimple.put(".mp2", "audio/x-mpeg");
mapSimple.put(".mp3", "audio/x-mpeg");
mapSimple.put(".mp4", "video/mp4");
mapSimple.put(".mpc", "application/vnd.mpohun.certificate");
mapSimple.put(".mpe", "video/mpeg");
mapSimple.put(".mpeg", "video/mpeg");
mapSimple.put(".mpg", "video/mpeg");
mapSimple.put(".mpg4", "video/mp4");
mapSimple.put(".mpga", "audio/mpeg");
mapSimple.put(".msg", "application/vnd.ms-outlook");
mapSimple.put(".ogg", "audio/ogg");
mapSimple.put(".pdf", "application/pdf");
mapSimple.put(".png", "image/png");
mapSimple.put(".pps", "application/vnd.ms-powerpoint");
mapSimple.put(".ppt", "application/vnd.ms-powerpoint");
mapSimple.put(".pptx", "application/vnd.ms-powerpoint");
mapSimple.put(".prop", "text/plain");
mapSimple.put(".rar", "application/x-rar-compressed");
mapSimple.put(".rc", "text/plain");
mapSimple.put(".rmvb", "audio/x-pn-realaudio");
mapSimple.put(".rtf", "application/rtf");
mapSimple.put(".sh", "text/plain");
mapSimple.put(".tar", "application/x-tar");
mapSimple.put(".tgz", "application/x-compressed");
mapSimple.put(".txt", "text/plain");
mapSimple.put(".wav", "audio/x-wav");
mapSimple.put(".wma", "audio/x-ms-wma");
mapSimple.put(".wmv", "audio/x-ms-wmv");
mapSimple.put(".wps", "application/vnd.ms-works");
mapSimple.put(".xml", "text/plain");
mapSimple.put(".xls", "application/vnd.ms-excel");
mapSimple.put(".xlsx", "application/vnd.ms-excel");
mapSimple.put(".z", "application/x-compress");
mapSimple.put(".zip", "application/zip");
mapSimple.put("", "*/*");
}
return mapSimple;
}
}
2、实现思路
主要思路:通过第三方软件打开文件时,要使用Intent的隐式方式将文件传送到第三方应用。
2.1:FileProvider
- android 7.0 新增私有目录访问权限,Google 官方说明:为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问 (0700)。此设置可防止私有文件的元数据泄漏。所以这里在访问下载的文件存储路径时,也需要动态判断系统版本添加文件读取权限,使用FileProvider获取路径,否则会触发 FileUriExposedException异常
- 添加FileProvider:
在AndroidManifest的中添加
在res中新建一个名为xml的Directory。在xml中新建一个file_pahts的xml文件。
- 通过File来获取Uri:
Android7.0前
Uri.fromfile(File file) ;Android7.0后
FileProvider.getUriForFile(Context context , String authority,File file);
2.2使用Intent将文件传递给第三方应用
- 打开文件时,需要给方法传入当前的
Context
和需要打开的File
。 - 新建一个Intent,传入
Intent.ACTION_VIEW
。 - 判断当前的系统是Android 7.0之前还是之后,选择对应的方法读取读取File的
Uri
值。 -
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
:检查当前所有已创建的Task中是否有该要启动的Activity的Task.
当系统是Android 7.0之后,别忘记了通过intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
给目标文件临时授权。 -
intent.setDataAndType(uri,getMimeTypeFromFile(file))
:传文件Uri地址和文件类型对应的Type。文件的Type可以通过getMimeTypeFromFile
的方法来获取。最后通过startActivity(intent)就可以实现效果了。
2.3 getMimeTypeFromFile:通过File获取对应的类型的Mime值
- MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。
- 获取文件的数据类型,通过getMimeMap()的方法找到对应的MimeMap值并将这个值返回。
四、方法总结
- 通过
intent.setDataAndType(uri,getMimeTypeFromFile(file))
传入重要的两个参数, - 其中通过File获取Uri值时,需要判断是Android的版本,选择对应的方法获取;
获取文件的Mime值时,需要获取到文件类型名后,在getMimeMap()找到对应Mime值并返回。 - 往Intent中传入相应的Flags,Action,最后调用startActivity(intent)就可以通过相关的第三方软件打开文件了。