提问人:alexandr kozlovskiy 提问时间:11/1/2023 更新时间:11/1/2023 访问量:47
如何在 android 14 和 hier 中没有特定权限的情况下从 uri 获取 pdf 文件的路径
How to get path to pdf file from uri without specific permissions in android 14 and hier
问:
我想获取 pdf 文件的路径,我从意图操作ACTION_OPEN_DOCUMENT中获取作为 uri,但是如果 uri 的媒体类型是文档,我该如何获取它(通过调试我理解,我的代码第 126 行有什么问题)。对于图像,我没有任何问题,有权限read_media_images或read_external_storage(适用于android 12及更低版本),但是对于pdf文档,我有这个问题。我不想获得对外部存储的完全访问权限,因为这可能是google play的问题,所以是否有可能在没有特殊权限的情况下获取pdf文件的路径,这些路径在api 30中使用,并且更高以获得对外部存储的完全访问权限。非常感谢您的帮助。
package maximsblog.blogspot.com.visionsender;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import androidx.loader.content.CursorLoader;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
class AndroidUtilities {
static class IOUtils {
private static final int BUFFER_SIZE = 1024 * 2;
static int copy(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
BufferedInputStream b = new BufferedInputStream(input, BUFFER_SIZE);
BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
int count = 0;
int n = 0;
try {
while((n =input.read(buffer, 0, BUFFER_SIZE))!= -1) {
out.write(buffer, 0, n);
count += n;
}
out.flush();
} finally {
try {
out.close();
} catch (IOException e) {
}
try {
input.close();
} catch (IOException e) {
}
}
return count;
}
}
static boolean isWhatsappUri(Uri uri) {
return "com.whatsapp.provider.media".equals(uri.getAuthority());
}
static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs, String columnName) {
Cursor cursor =null;
if (columnName == null)
columnName = "_data";
try {
cursor = context.getContentResolver().query(
uri, new String[] {columnName}, selection, selectionArgs,null);
if (cursor == null) return uri.getPath();
if (cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(columnName);
if (columnName.equals("_data"))
return cursor.getString(column_index);
else
return uri.toString() + "/" + cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
return getDataColumn(context, uri, selection, selectionArgs, null);
}
@SuppressLint("NewApi")
static String getRealPathFromURI_API19(Context context, Uri uri) {
String result = null;
if (DocumentsContract.isDocumentUri(context, uri)) {
String[] split =null;
String docId=null;
if (isExternalStorageDocument(uri)) {
docId = DocumentsContract.getDocumentId(uri);
String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {
docId = DocumentsContract.getDocumentId(uri);
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
return getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {
docId = DocumentsContract.getDocumentId(uri);
split = docId.split(":");
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;
}
else if("document".equals(type)) { //in this line (126) we have a problems. How to get path of file for this case?
//contentUri =MediaStore.getDocumentUri(context,uri); //crash,when we call this method.
}
String selection = "_id=?";
return getDataColumn(context, contentUri, selection, new String[] {split[1]});
}
}
else if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
} else if (isWhatsappUri(uri)) {
return getDataColumn(context, uri, null, null, "_display_name");
}
return null;
}
@SuppressLint("NewApi")
static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
if (isWhatsappUri(contentUri)) {
return new File(contentUri.getPath()).getAbsolutePath();
}
String[] proj = new String[] {MediaStore.Images.Media.DATA};
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
contentUri, proj, null, null, null
);
Cursor cursor = cursorLoader.loadInBackground();
if (cursor != null) {
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
}
cursor.close();
return result;
}
static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) {
if (isWhatsappUri(contentUri)) {
return new File(contentUri.getPath()).getAbsolutePath();
}
Cursor cursor = context.getContentResolver().query(contentUri, new String[] {MediaStore.Images.Media.DATA}, null, null, null);
cursor.moveToFirst();
String result = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
cursor.close();
return result;
}
static String getRealPath(Context context, Uri uri) {
if(Build.VERSION.SDK_INT < 11) return getRealPathFromURI_BelowAPI11(context, uri);
else if(Build.VERSION.SDK_INT < 19) return getRealPathFromURI_API11to18(context, uri);
else return getRealPathFromURI_API19(context, uri);
}
static String getFileName(String Fpath) {
String[] result=Fpath.split("/");
return result[result.length-1];
}
static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(
srcUri);
FileOutputStream outputStream = new FileOutputStream(dstFile);
IOUtils.copy(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
static String getFilePathFromURI(Context context, Uri contentUri) {
String fileName = getFileName(contentUri.getPath());
if (!TextUtils.isEmpty(fileName)) {
File copyFile = new File(context.getCacheDir().toString() + "/" + fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
}
答:
1赞
CommonsWare
11/1/2023
#1
如何获取此文件的文件名
调用 DocumentFile.fromSingleUri()
以获取表示由 .然后调用 getName()
以获取显示名称。这可能是也可能不是“文件名”,但它应该是用户可识别的名称。DocumentFile
Uri
DocumentFile
评论
0赞
alexandr kozlovskiy
11/2/2023
但在这种情况下,我们无法获取文件的路径。无论如何,我查看了源 DocumentFile 类并了解了它从光标列_display_name获取文件名的内容,就像我在获取文件路径时所做的那样。无论如何,非常感谢你。这对我来说非常令人惊讶,但我没有发现任何问题,当我看到 stackoverflow 对类似问题的回答时。
0赞
CommonsWare
11/2/2023
@alexandrkozlovskiy:“但是在这种情况下,我们无法获取文件的路径”——这是因为根本不要求所选文档是文件,更不用说您可以访问的文件了。
评论
ACTION_OPEN_DOCUMENT
Uri
Uri
ContentResolver
openInputStream()
DocumentsProvider