一披坏、為什么要用第三方軟件打開文件
假如在應(yīng)用中下載下來一個word文件,并把文件保存至指定位置后替劈。用戶想要打開文件蜒滩,不可能讓用戶對照著保存目錄去找滨达,這時候就需要通過指定的方法來調(diào)用對應(yīng)的第三方軟件來打開該文件。
二俯艰、主要方法
intent.setDataAndType(URI date,String Type)
:在Intent中傳入文件的Uri路徑和文件格式對應(yīng)的"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);//給目標文件臨時授權(quán)
}else {
uriForFile = Uri.fromFile(file);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//系統(tǒng)會檢查當(dāng)前所有已創(chuàng)建的Task中是否有該要啟動的Activity的Task;
// 若有画株,則在該Task上創(chuàng)建Activity;若沒有則新建具有該Activity屬性的Task啦辐,并在該新建的Task上創(chuàng)建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和文件類型的匹配表中找到對應(yīng)的MIME類型芹关。
HashMap<String, String> 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<String, String> mapSimple = new HashMap<>();
/**
* 常用"文件擴展名—MIME類型"匹配表续挟。
* 注意,此表并不全侥衬,也并不是唯一的诗祸,就像有人喜歡用瀏覽器打開TXT一樣跑芳,你可以根據(jù)自己的愛好自定義。
*/
public static HashMap<String, String> 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直颅、實現(xiàn)思路
主要思路:通過第三方軟件打開文件時博个,要使用Intent的隱式方式將文件傳送到第三方應(yīng)用。
2.1:FileProvider
- android 7.0 新增私有目錄訪問權(quán)限功偿,Google 官方說明:為了提高私有文件的安全性盆佣,面向 Android 7.0 或更高版本的應(yīng)用私有目錄被限制訪問 (0700)。此設(shè)置可防止私有文件的元數(shù)據(jù)泄漏脖含。所以這里在訪問下載的文件存儲路徑時罪塔,也需要動態(tài)判斷系統(tǒng)版本添加文件讀取權(quán)限,使用FileProvider獲取路徑养葵,否則會觸發(fā) FileUriExposedException異常
- 添加FileProvider:
在AndroidManifest的<application>中添加
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.administrator.timer.fileprovider"
tools:replace="android:authorities"
android:exported="false"
android:grantUriPermissions="true">
<!--指定Uri的共享路徑-->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
在res中新建一個名為xml的Directory。在xml中新建一個file_pahts的xml文件瘩缆。
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_files" path="" />
</paths>
- 通過File來獲取Uri:
Android7.0前
Uri.fromfile(File file) 关拒;Android7.0后
FileProvider.getUriForFile(Context context , String authority,File file);
2.2使用Intent將文件傳遞給第三方應(yīng)用
- 打開文件時,需要給方法傳入當(dāng)前的
Context
和需要打開的File
庸娱。 - 新建一個Intent着绊,傳入
Intent.ACTION_VIEW
。 - 判斷當(dāng)前的系統(tǒng)是Android 7.0之前還是之后熟尉,選擇對應(yīng)的方法讀取讀取File的
Uri
值归露。 -
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
:檢查當(dāng)前所有已創(chuàng)建的Task中是否有該要啟動的Activity的Task.
當(dāng)系統(tǒng)是Android 7.0之后,別忘記了通過intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
給目標文件臨時授權(quán)斤儿。 -
intent.setDataAndType(uri,getMimeTypeFromFile(file))
:傳文件Uri地址和文件類型對應(yīng)的Type剧包。文件的Type可以通過getMimeTypeFromFile
的方法來獲取。最后通過startActivity(intent)就可以實現(xiàn)效果了往果。
2.3 getMimeTypeFromFile:通過File獲取對應(yīng)的類型的Mime值
- MIME(Multipurpose Internet Mail Extensions)多用途互聯(lián)網(wǎng)郵件擴展類型疆液。是設(shè)定某種擴展名的文件用一種應(yīng)用程序來打開的方式類型,當(dāng)該擴展名文件被訪問的時候陕贮,瀏覽器會自動使用指定應(yīng)用程序來打開堕油。
- 獲取文件的數(shù)據(jù)類型,通過getMimeMap()的方法找到對應(yīng)的MimeMap值并將這個值返回肮之。
四掉缺、方法總結(jié)
- 通過
intent.setDataAndType(uri,getMimeTypeFromFile(file))
傳入重要的兩個參數(shù), - 其中通過File獲取Uri值時戈擒,需要判斷是Android的版本眶明,選擇對應(yīng)的方法獲取;
獲取文件的Mime值時,需要獲取到文件類型名后峦甩,在getMimeMap()找到對應(yīng)Mime值并返回赘来。 - 往Intent中傳入相應(yīng)的Flags现喳,Action,最后調(diào)用startActivity(intent)就可以通過相關(guān)的第三方軟件打開文件了犬辰。