做這個(gè)功能時(shí)在網(wǎng)上找了無數(shù)篇例子,有些方法是有問題的,故自己寫一篇完整實(shí)現(xiàn)的總結(jié),作備忘也作案例。順便說一句,Android對(duì)存儲(chǔ)權(quán)限的給予真的越來越嚴(yán)格
目錄
1.Uri轉(zhuǎn)為路徑String以獲得文件名?
2.獲取文件后綴名
3.通過后綴名獲取文件MIME類型?
4.設(shè)置Intent的Uri與權(quán)限并打開文件?
1.Uri轉(zhuǎn)為路徑String以獲得文件名?
有一種方法是使用ContentResolver對(duì)象查詢Uri對(duì)應(yīng)的Cursor對(duì)象然后獲取文件名,這個(gè)方法只適用于文件位于應(yīng)用公共目錄,在此不多贅述。我這里的需求是用第三方應(yīng)用打開某個(gè)文件,本身有目標(biāo)路徑。如果要把Uri轉(zhuǎn)成路徑來獲得文件名就要用到convertUriToFilePath方法,類似方法網(wǎng)上雜七雜八的好多,大部分都用不了或者只能獲取圖片路徑。我分享一個(gè)自己一直用的,使用時(shí)傳入兩個(gè)參數(shù):Context和Uri
public static String convertUriToFilePath(final Context context, final Uri uri) {
String path = null;
if (DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
path = Environment.getExternalStorageDirectory() + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
}
final Uri contentUri = ContentUris
.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
path = getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = MediaStore.Audio.Media._ID + "=?";
final String[] selectionArgs = new String[]{
split[1]
};
path = getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(uri.getScheme())) {
path = getDataColumn(context, uri, null, null);
} else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(uri.getScheme())) {
path = uri.getPath();
}
if (path != null) {
try {
return URLDecoder.decode(path, "UTF-8");
} catch (Exception e) {
return null;
}
}
return null;
}
以下是使用示例:
Uri uri = data.getData(); //data是傳入的Intent。你可以將data.getData()替換為你需要的其他uri
String filePath = convertUriToFilePath(getApplicationContext(), uri); //調(diào)用方法
2.獲取文件后綴名
這里我使用File中的file.getName()來獲取文件名,再用截取字符串獲取文件后綴名
File file = new File(filePath);
String fName = file.getName();
String end = "";
int dotIndex = fName.lastIndexOf(".");
if (dotIndex > 0) {
//獲取文件的后綴名
end = fName.substring(dotIndex, fName.length()).toLowerCase(Locale.getDefault());
}
3.通過后綴名獲取文件MIME類型?
網(wǎng)上有人專門為了獲得MIME類型做了個(gè)MimeMap,其實(shí)有自帶的android.webkit.MimeTypeMap中的方法
String mimetype = "";
mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(end);
4.設(shè)置Intent的Uri與權(quán)限并打開文件?
如果你是有Uri的,那你就跳過這里直接看Intent的做法。如果你跳過了第一步,像我一樣是從路徑來打開的,那么你需要先得到Uri。SDK23以上需要擁有fileProvider授權(quán)來獲取uri。
在AndroidManifest.xml中添加provider(注意將“你應(yīng)用的包名”更改為你的實(shí)際包名)
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="你應(yīng)用的包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
在res/xml中(沒有xml文件夾就新建一個(gè))新建file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
<root-path
name="external_files"
path="" />
</paths>
將File加載為Uri(注意將“你應(yīng)用的包名”更改為你的實(shí)際包名)
Uri uri;
if (Build.VERSION.SDK_INT > 23) {
//Android 7.0之后
uri = FileProvider.getUriForFile(context, "你應(yīng)用的包名.fileprovider", file);
} else {
uri = Uri.fromFile(file);
}
?新建Intent并啟動(dòng)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(uriForFile, mimetype);
//檢查context是否不是Activity的實(shí)例
if (!(context instanceof Activity)) {
//若不是Activity則將活動(dòng)作為新任務(wù)棧的一部分啟動(dòng)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 最重要的一句,網(wǎng)上很多版本沒有。該語(yǔ)句授予Intent的組件臨時(shí)讀取URI的權(quán)限
startActivity(intent);
解釋Intent.FLAG_ACTIVITY_NEW_TASK:當(dāng)使用Intent啟動(dòng)一個(gè)活動(dòng)時(shí),如果當(dāng)前Context是一個(gè)服務(wù)或其他類型的Context,那么需要添加FLAG_ACTIVITY_NEW_TASK標(biāo)志。因?yàn)橹挥谢顒?dòng)的Context才能直接啟動(dòng)新的活動(dòng),而其他類型的上下文無法直接啟動(dòng)活動(dòng)。添加FLAG_ACTIVITY_NEW_TASK標(biāo)志可以告訴系統(tǒng)將這個(gè)活動(dòng)作為新任務(wù)棧的一部分啟動(dòng),從而繞過這個(gè)限制。
注意,務(wù)必加上intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),否則其他應(yīng)用沒有權(quán)限讀你的Uri。但是目前已知WPS和MT管理器可以繞開此限制,不知道他們是如何繞開的。
本文完
若對(duì)文章內(nèi)容出現(xiàn)疑問,歡迎私信交流,歡迎共同進(jìn)步
致謝以下文章:
Android調(diào)用外部應(yīng)用打開文件_android打開文件-CSDN博客
【基礎(chǔ)筆記】Android如何用第三方軟件打開文件 - 簡(jiǎn)書文章來源:http://www.zghlxwxcb.cn/news/detail-827822.html
解決 Android N 上報(bào)錯(cuò):android.os.FileUriExposedException: file:///storage/emulated/0/_file:///storage/emulated/0/hwbrowser/.picview_temp-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-827822.html
到了這里,關(guān)于Android將Uri轉(zhuǎn)為路徑字符串(適配安卓全版本)并使用第三方應(yīng)用打開文件(適配Android7.0+)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!