專案中有下載檔案的功能,但是有點 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();
}
複製程式碼
這樣就可以實現開啟檔案功能了。
最後
最後,嘮叨下,好久沒寫部落格,感覺都不知道怎麼寫了,慢慢找感覺吧。。。
你可以通過以下方式關注我: