项目中有下载文件的功能,但是有点 low,就是单纯的下载,下载成功提示用户文件下载在哪,需要用户手动去文件管理器找这些文件,不是很人性化,于是决定新增下载文件以后让用户直接能打开文件,友好型会好很多
前言
首先在实现打开指定文件之前,我尝试过打开指定的文件夹,但是并没有成功,研究了大半天的时间,发现是不可行的,这是个坑,希望不要有人再踩这个坑了,(当然,也有可能是我没找到打开文件夹的方法,如果有人知道,希望能够赐教下,先谢谢了)
文末会给出封装好的代码,OpenFileUtils 和 FileProviderUtils 类,可以直接使用。
判断文件类型
我们在打开文件之前,首先得知道文件的类型,才能指定 Intent 的 Data ,才能实现打开文件的功能。
常见的文件类型以及对应的 DataType 如下:
/**
* 声明各种类型文件的dataType
**/
private static final String DATA_TYPE_APK = "application/vnd.android.package-archive";
private static final String DATA_TYPE_VIDEO = "video/*";
private static final String DATA_TYPE_AUDIO = "audio/*";
private static final String DATA_TYPE_HTML = "text/html";
private static final String DATA_TYPE_IMAGE = "image/*";
private static final String DATA_TYPE_PPT = "application/vnd.ms-powerpoint";
private static final String DATA_TYPE_EXCEL = "application/vnd.ms-excel";
private static final String DATA_TYPE_WORD = "application/msword";
private static final String DATA_TYPE_CHM = "application/x-chm";
private static final String DATA_TYPE_TXT = "text/plain";
private static final String DATA_TYPE_PDF = "application/pdf";
/**
* 未指定明确的文件类型,不能使用精确类型的工具打开,需要用户选择
*/
private static final String DATA_TYPE_ALL = "*/*";
然后我们得根据要打开的文件名,获取文件的类型:
// 取得文件扩展名
String end = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length()).toLowerCase();
// 依扩展名的类型决定MimeType
switch (end) {
case "3gp":
case "mp4":
openVideoFileIntent(mContext, file);
break;
case "m4a":
case "mp3":
case "mid":
case "xmf":
case "ogg":
case "wav":
openAudioFileIntent(mContext, file);
break;
case "doc":
case "docx":
commonOpenFileWithType(mContext, file, DATA_TYPE_WORD);
break;
case "xls":
case "xlsx":
commonOpenFileWithType(mContext, file, DATA_TYPE_EXCEL);
break;
case "jpg":
case "gif":
case "png":
case "jpeg":
case "bmp":
commonOpenFileWithType(mContext, file, DATA_TYPE_IMAGE);
break;
case "txt":
commonOpenFileWithType(mContext, file, DATA_TYPE_TXT);
break;
case "htm":
case "html":
commonOpenFileWithType(mContext, file, DATA_TYPE_HTML);
break;
case "apk":
commonOpenFileWithType(mContext, file, DATA_TYPE_APK);
break;
case "ppt":
commonOpenFileWithType(mContext, file, DATA_TYPE_PPT);
break;
case "pdf":
commonOpenFileWithType(mContext, file, DATA_TYPE_PDF);
break;
case "chm":
commonOpenFileWithType(mContext, file, DATA_TYPE_CHM);
break;
default:
commonOpenFileWithType(mContext, file, DATA_TYPE_ALL);
break;
}
根据文件名拿到 DataType 之后,我们就可以把 DataType 传入 Intent 来打开文件了。下面以打开 Video 为例:
/**
* Android打开Video文件
* @param mContext
* @param file
*/
public static void openVideoFileIntent(Context mContext, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
FileProviderUtils.setIntentDataAndType(mContext, intent, DATA_TYPE_VIDEO, file, false);
mContext.startActivity(intent);
}
只要传入 Context 和 File 就可以使用了。
相关代码
上面的代码是不完整的,下面我贴出有关的类的代码:
首先是:OpenFileUtils 类
/**
* @author SmartSean
* @date 17/12/11 16:04
*/
public class OpenFileUtils {
/**
* 声明各种类型文件的dataType
**/
private static final String DATA_TYPE_APK = "application/vnd.android.package-archive";
private static final String DATA_TYPE_VIDEO = "video/*";
private static final String DATA_TYPE_AUDIO = "audio/*";
private static final String DATA_TYPE_HTML = "text/html";
private static final String DATA_TYPE_IMAGE = "image/*";
private static final String DATA_TYPE_PPT = "application/vnd.ms-powerpoint";
private static final String DATA_TYPE_EXCEL = "application/vnd.ms-excel";
private static final String DATA_TYPE_WORD = "application/msword";
private static final String DATA_TYPE_CHM = "application/x-chm";
private static final String DATA_TYPE_TXT = "text/plain";
private static final String DATA_TYPE_PDF = "application/pdf";
/**
* 未指定明确的文件类型,不能使用精确类型的工具打开,需要用户选择
*/
private static final String DATA_TYPE_ALL = "*/*";
/**
* 打开文件
* @param mContext
* @param file
*/
public static void openFile(Context mContext, File file) {
if (!file.exists()) {
return;
}
// 取得文件扩展名
String end = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length()).toLowerCase();
// 依扩展名的类型决定MimeType
switch (end) {
case "3gp":
case "mp4":
openVideoFileIntent(mContext, file);
break;
case "m4a":
case "mp3":
case "mid":
case "xmf":
case "ogg":
case "wav":
openAudioFileIntent(mContext, file);
break;
case "doc":
case "docx":
commonOpenFileWithType(mContext, file, DATA_TYPE_WORD);
break;
case "xls":
case "xlsx":
commonOpenFileWithType(mContext, file, DATA_TYPE_EXCEL);
break;
case "jpg":
case "gif":
case "png":
case "jpeg":
case "bmp":
commonOpenFileWithType(mContext, file, DATA_TYPE_IMAGE);
break;
case "txt":
commonOpenFileWithType(mContext, file, DATA_TYPE_TXT);
break;
case "htm":
case "html":
commonOpenFileWithType(mContext, file, DATA_TYPE_HTML);
break;
case "apk":
commonOpenFileWithType(mContext, file, DATA_TYPE_APK);
break;
case "ppt":
commonOpenFileWithType(mContext, file, DATA_TYPE_PPT);
break;
case "pdf":
commonOpenFileWithType(mContext, file, DATA_TYPE_PDF);
break;
case "chm":
commonOpenFileWithType(mContext, file, DATA_TYPE_CHM);
break;
default:
commonOpenFileWithType(mContext, file, DATA_TYPE_ALL);
break;
}
}
/**
* Android传入type打开文件
* @param mContext
* @param file
* @param type
*/
public static void commonOpenFileWithType(Context mContext, File file, String type) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);
FileProviderUtils.setIntentDataAndType(mContext, intent, type, file, true);
mContext.startActivity(intent);
}
/**
* Android打开Video文件
* @param mContext
* @param file
*/
public static void openVideoFileIntent(Context mContext, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
FileProviderUtils.setIntentDataAndType(mContext, intent, DATA_TYPE_VIDEO, file, false);
mContext.startActivity(intent);
}
/**
* Android打开Audio文件
* @param mContext
* @param file
*/
private static void openAudioFileIntent(Context mContext, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
FileProviderUtils.setIntentDataAndType(mContext, intent, DATA_TYPE_AUDIO, file, false);
mContext.startActivity(intent);
}
}
接下来是洪洋大神写的 Android 7.0 适配类 FileProviderUtils(使用前先需要先了解下 FileProvider 的使用)
/**
* @author SmartSean
* @date 17/12/11 14:23
*/
public class FileProviderUtils {
public static Uri getUriForFile(Context mContext, File file) {
Uri fileUri = null;
if (Build.VERSION.SDK_INT >= 24) {
fileUri = getUriForFile24(mContext, file);
} else {
fileUri = Uri.fromFile(file);
}
return fileUri;
}
public static Uri getUriForFile24(Context mContext, File file) {
Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(mContext,
BuildConfig.APPLICATION_ID + ".provider",
file);
return fileUri;
}
public static void setIntentDataAndType(Context mContext,
Intent intent,
String type,
File file,
boolean writeAble) {
if (Build.VERSION.SDK_INT >= 24) {
intent.setDataAndType(getUriForFile(mContext, file), type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(Uri.fromFile(file), type);
}
}
}
调用
File file = new File(Environment.getExternalStorageDirectory()+"/AA/q.xlsx");
try {
OpenFileUtils.openFile(mContext, file);
} catch (Exception e) {
ToastUtil.toastError(mContext, "无可用打开方式");
e.printStackTrace();
}
这样就可以实现打开文件功能了。
最后
最后,唠叨下,好久没写博客,感觉都不知道怎么写了,慢慢找感觉吧。。。