【问题标题】:How to get content URI for Android 12 for document files(pdf, doc, word)?如何为 Android 12 获取文档文件(pdf、doc、word)的内容 URI?
【发布时间】:2022-08-24 04:51:32
【问题描述】:

对不起,很长的帖子。

我想使用 API 从 Android 将不同类型的文件上传到我们的服务器。

我正在使用以下代码进行文件选择

Intent pickDocument = new Intent(Intent.ACTION_GET_CONTENT);
pickDocument.addCategory(Intent.CATEGORY_OPENABLE);
pickDocument.setType(\"*/*\");
activity.startActivityForResult(Intent.createChooser(pickDocument, \"ChooseFile\"), requestCode);

我正在使用下面的类从 URI 获取文件路径。

public class UriUtils {
    private static Uri contentUri = null;
    private static MimeTypeMap mimeType = MimeTypeMap.getSingleton();

    @SuppressLint(\"NewApi\")
    public static String getPathFromUri(final Context context, final Uri uri) {
        // check here to is it KITKAT or new version
        final boolean isKitKatOrAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        String selection = null;
        String[] selectionArgs = null;

        // DocumentProvider
        if (isKitKatOrAbove && DocumentsContract.isDocumentUri(context, uri)) {

            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(\":\");
                final String type = split[0];

                String fullPath = getPathFromExtSD(split);
                if (fullPath != \"\") {
                    return fullPath;
                } else {
                    return null;
                }
            } else if (isDownloadsDocument(uri)) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    final String id;
                    Cursor cursor = null;
                    try {
                        cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
                        if (cursor != null && cursor.moveToFirst()) {
                            String fileName = cursor.getString(0);
                            String path = Environment.getExternalStorageDirectory().toString() + \"/Download/\" + fileName;
                            if (!TextUtils.isEmpty(path)) {
                                return path;
                            }
                        }
                    } finally {
                        if (cursor != null)
                            cursor.close();
                    }
                    id = DocumentsContract.getDocumentId(uri);
                    if (!TextUtils.isEmpty(id)) {
                        if (id.startsWith(\"raw:\")) {
                            return id.replaceFirst(\"raw:\", \"\");
                        }
                        String[] contentUriPrefixesToTry = new String[]{
                                \"content://downloads/public_downloads\",
                                \"content://downloads/my_downloads\"
                        };
                        for (String contentUriPrefix : contentUriPrefixesToTry) {
                            try {
                                final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
                                return getDataColumn(context, contentUri, null, null);
                            } catch (NumberFormatException e) {
                                //In Android 8 and Android P the id is not a number
                                return uri.getPath().replaceFirst(\"^/document/raw:\", \"\").replaceFirst(\"^raw:\", \"\");
                            }
                        }
                    }
                } else {
                    final String id = DocumentsContract.getDocumentId(uri);
                    if (id.startsWith(\"raw:\")) {
                        return id.replaceFirst(\"raw:\", \"\");
                    }
                    try {
                        contentUri = ContentUris.withAppendedId(
                                Uri.parse(\"content://downloads/public_downloads\"), Long.valueOf(id));
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                    }
                    if (contentUri != null) {
                        return 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];

                selection = \"_id=?\";
                selectionArgs = new String[]{split[1]};

                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;
                } 

                return getDataColumn(context, contentUri, selection, selectionArgs);
            } else if (isGoogleDriveUri(uri)) {
                return getDriveFilePath(uri, context);
            }
        } else if (\"content\".equalsIgnoreCase(uri.getScheme())) {
            if (isGooglePhotosUri(uri)) {
                return uri.getLastPathSegment();
            }
            if (isGoogleDriveUri(uri)) {
                return getDriveFilePath(uri, context);
            }
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
                return getMediaFilePathForN(uri, context);
            } else {
                return copyFromSource(uri, context);
            }
        } else if (\"file\".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
        return null;
    }

    private static boolean fileExists(String filePath) {
        File file = new File(filePath);
        return file.exists();
    }

    private static String getPathFromExtSD(String[] pathData) {
        final String type = pathData[0];
        final String relativePath = \"/\" + pathData[1];
        String fullPath = \"\";

        if (\"primary\".equalsIgnoreCase(type)) {
            fullPath = Environment.getExternalStorageDirectory() + relativePath;
            if (fileExists(fullPath)) {
                return fullPath;
            }
        }

        fullPath = System.getenv(\"SECONDARY_STORAGE\") + relativePath;
        if (fileExists(fullPath)) {
            return fullPath;
        }

        fullPath = System.getenv(\"EXTERNAL_STORAGE\") + relativePath;
        if (fileExists(fullPath)) {
            return fullPath;
        }

        return fullPath;
    }

    private static String getDriveFilePath(Uri uri, Context context) {
        Uri returnUri = uri;
        Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);

        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
        returnCursor.moveToFirst();
        String name = (returnCursor.getString(nameIndex));
        String size = (Long.toString(returnCursor.getLong(sizeIndex)));
        File file = new File(context.getCacheDir(), name);
        try {
            InputStream inputStream = context.getContentResolver().openInputStream(uri);
            FileOutputStream outputStream = new FileOutputStream(file);
            int read = 0;
            int maxBufferSize = 1 * 1024 * 1024;
            int bytesAvailable = inputStream.available();

            //int bufferSize = 1024;
            int bufferSize = Math.min(bytesAvailable, maxBufferSize);
            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                outputStream.write(buffers, 0, read);
            }
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file.getPath();
    }

    private static String getMediaFilePathForN(Uri uri, Context context) {
        Uri returnUri = uri;
        Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);

        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
        returnCursor.moveToFirst();
        String name = (returnCursor.getString(nameIndex));
        String size = (Long.toString(returnCursor.getLong(sizeIndex)));
        File file = new File(context.getFilesDir(), name);
        try {
            InputStream inputStream = context.getContentResolver().openInputStream(uri);
            FileOutputStream outputStream = new FileOutputStream(file);
            int read = 0;
            int maxBufferSize = 1 * 1024 * 1024;
            int bytesAvailable = inputStream.available();

            //int bufferSize = 1024;
            int bufferSize = Math.min(bytesAvailable, maxBufferSize);
            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                outputStream.write(buffers, 0, read);
            }
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file.getPath();
    }


    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        Cursor cursor = null;
        final String column = \"_data\";
        final String[] projection = {column};
        try {
            cursor = context.getContentResolver().query(uri, projection,
                    selection, selectionArgs, null);

            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }

        return null;
    }

    private static String copyFromSource(Uri uri, Context context) {

        ContentResolver contentResolver = context.getContentResolver();
        String fileExtension = getFileExtension(uri, contentResolver);

        String fileName = queryName(uri, contentResolver);
        if (fileName == null)
            fileName = getFileName(fileExtension);

        // the file which will be the new cached file
        File filePath = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
        File outputFile = new File(filePath, fileName);
        try {
            InputStream inputStream = context.getContentResolver().openInputStream(uri);
            FileOutputStream outputStream = new FileOutputStream(outputFile);
            int read = 0;
            int maxBufferSize = 1 * 1024 * 1024;
            int bytesAvailable = inputStream.available();

            //int bufferSize = 1024;
            int bufferSize = Math.min(bytesAvailable, maxBufferSize);

            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                outputStream.write(buffers, 0, read);
            }
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return outputFile.getAbsolutePath();
    }

    @SuppressLint(\"Recycle\")
    private static String queryName(Uri uri, ContentResolver contentResolver) {
        Cursor returnCursor = contentResolver.query(uri, null, null, null, null);
        if (returnCursor == null)
            return null;

        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        if (nameIndex == -1)
            return null;

        returnCursor.moveToFirst();
        String name = returnCursor.getString(nameIndex);
        returnCursor.close();
        return name;
    }

    private static String getFileExtension(Uri uri, ContentResolver contentResolver) {
        return mimeType.getExtensionFromMimeType(contentResolver.getType(uri));
    }

    private static String getFileName(String fileExtension) {
        return System.currentTimeMillis() + fileExtension + \"\";
    }

    private static boolean isExternalStorageDocument(Uri uri) {
        return \"com.android.externalstorage.documents\".equals(uri.getAuthority());
    }

    private static boolean isDownloadsDocument(Uri uri) {
        return \"com.android.providers.downloads.documents\".equals(uri.getAuthority());
    }

    private static boolean isMediaDocument(Uri uri) {
        return \"com.android.providers.media.documents\".equals(uri.getAuthority());
    }

    private static boolean isGooglePhotosUri(Uri uri) {
        return \"com.google.android.apps.photos.content\".equals(uri.getAuthority());
    }

    private static boolean isGoogleDriveUri(Uri uri) {
        return \"com.google.android.apps.docs.storage\".equals(uri.getAuthority()) || \"com.google.android.apps.docs.storage.legacy\".equals(uri.getAuthority());
    }
}

此代码工作正常安卓 10及以下。但我在 Android 12 中遇到问题

如果我选择一个文件文档(doc、pdf、excel、txt)除了图像、视频和音频,我得到路径空.

在 Android 12(Pixel 3)中,我得到了低于 URI

content://com.android.providers.media.documents/document/document%3A27958 

所以根据上面的代码, 这是媒体文件.

private static boolean isMediaDocument(Uri uri) {
    return \"com.android.providers.media.documents\".equals(uri.getAuthority());
}

如果文件是媒体,我只处理 3 种类型的文件

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;
}

如果有文档文件(doc、excel、pdf、txt),如何获取 contentUri?

  • \"我正在使用下面的类从 URI 获取文件路径\" - 删除它。 \"如果我选择的文件是除图像、视频和音频之外的文档(doc、pdf、excel、txt),我的路径为空。\" - 你会因为很多 Uri 值而失败,包括比 12 更早的 Android 版本。Uri 不是文件。有很多 Uri 值的来源不会映射到文件系统路径,更不用说您可以使用的文件系统路径了。所选内容可能在 Google Drive 或其他云存储提供商中,或在网络文件服务器上,或在加密文​​档存储中等。
  • 我知道你会添加你的输入@CommonsWare :)。我花了一个多星期的时间在这上面。如果我删除您提到的上述内容。如何为所有 Android 版本和所有类型的文件(即图像、音频、视频和其他文件)获取正确的文件路径?
  • \"如何为所有 Android 版本获取正确的文件路径\" - 你不知道。尽可能按照设计使用Uri,例如通过ContentResolver 上的openInputStream()/openOutputStream()。对于流不足的情况(例如,SQLite 数据库),您需要制作内容的副本。您的问题中隐藏了代码,但是制作内容的副本也具有用户体验影响(例如,导入/导出或备份/恢复语义)。

标签: android android-file


【解决方案1】:

Olá foi resolvido seu problema? Estou com o mesmo problema, o ID não está retornando o caminho mas sim um código msf:58090, uso o android 12, se conseguiu solucionar se possível adicionar o código por青睐。

【讨论】:

    猜你喜欢
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多