标签: android-fileprovider

FileProvider.getUriForFile 导致 StringIndexOutOfBoundsException

我已经更新了我的项目来实施Providers。整个实现看起来是正确的,但我StringIndexOutOfBoundsExceptionFileProvider课堂上收到异常。

在我的例子中,创建了一个意图,用户可以在其中选择从他的图库中获取图像还是拍摄新照片。

这就是创建我的意图之一的地方,然后将其包含在列表中以创建选择器。

    File file = getTempFile(context);
    if (file != null) {
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        takePhotoIntent.putExtra("return-data", true);
        takePhotoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                FileProvider.getUriForFile(context,                        // line 43
                        BuildConfig.APPLICATION_ID.concat(".fileprovider"),
                        file));
        intentList = addIntentsToList(context, intentList, takePhotoIntent);
    }
Run Code Online (Sandbox Code Playgroud)

getTempFile方法:

private static File getTempFile(Context context) {
    File imageFile = new File(context.getExternalCacheDir(), TEMP_IMAGE_NAME);
    if (imageFile.getParentFile().mkdirs()) {
        return imageFile;
    } else {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

抛出的异常:

java.lang.StringIndexOutOfBoundsException: length=86; index=87
     at java.lang.String.substring(String.java:1939)
     at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:728)
     at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:404)
     at com.project.helper.ImagePicker.getPickImageIntent(ImagePicker.java:43)
Run Code Online (Sandbox Code Playgroud)

在这种情况下我该如何进行?也许这是这个版本的 Provider …

android android-intent android-fileprovider

5
推荐指数
1
解决办法
2573
查看次数

如何在牛轧糖中为 ACTION_VIEW 使用内容 URI?

我有一个生成视频文件的应用程序,它可以放在内部存储或 SD 卡中,需要通过 Intent.ACTION_VIEW 由用户首选的视频播放器应用程序打开。该应用程序在面向 API 22 时按预期工作,但是当我尝试将其升级到 27 时遇到了问题。

该应用程序根据存储位置生成不同类型的 URI。对于内部存储,它使用文件 URI,如下所示:

file:///storage/emulated/0/VideoRecorder/2018_06_22_12_25_50.mp4
Run Code Online (Sandbox Code Playgroud)

对于放置在 SD 卡中的视频,它使用内容 URI:

content://com.android.externalstorage.documents/tree/72D1-C625%3Avideostest%2Ftest2/document/72D1-C625%3Avideostest%2Ftest2%2F2018_06_22_12_41_27.mp4
Run Code Online (Sandbox Code Playgroud)

Nougat 不喜欢 file:// URI,所以我使用 FileProvider(下面的代码)来解决这个问题,将文件 URI 转换为其他应用程序可以使用 ACTION_VIEW 打开的内容 URI。我认为 SD 卡 URI 不需要任何更改,因为它已经是内容 URI,但似乎只有默认照片应用程序可以使用 ACTION_VIEW 意图打开该 URI,而用户安装的应用程序(如 VLC Player)则不能,失败,但出现以下异常:

java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/72D1-C625:videostest/test2/document/72D1-C625:videostest/test2/2018_06_22_12_27_45.mp4 from pid=7809, uid=10022 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
Run Code Online (Sandbox Code Playgroud)

检查了 FileProvider 生成的 URI 后,我想我明白了这个问题。它生成的内容 URI 的格式与我用于 SD 卡视频的内容 URI 的格式完全不同:

content://io.github.androidtests.videorecorder.videosfileprovider/external_files/VideoRecorder/2018_06_22_12_25_50.mp4
Run Code Online (Sandbox Code Playgroud)

我的问题是,SD 卡视频是否也需要通过 FileProvider 共享?我该怎么做,因为我只有内容 URI,没有文件,而且 FileProvider 似乎专门设计用于将文件转换为 URI?

编辑:在测试了更多视频播放器应用程序之后,其中一些似乎能够使用内容 URI,就像照片应用程序一样。这只是一些应用程序不支持内容 URI 的情况吗?

代码:

Uri uri …
Run Code Online (Sandbox Code Playgroud)

android uri android-fileprovider android-7.0-nougat

5
推荐指数
0
解决办法
450
查看次数

是否可以在 FileProvider 中提供一个并不真正存在的文件的压缩文件?

背景

我希望能够通过FileProvider将一些文件(通过发送意图)共享为单个压缩文件,但无需实际创建该文件。

对于意图,您所做的就是添加ArrayList<Uri>作为参数,如下所示:

ArrayList<Uri> uris = MyFileProvider.prepareFileProviderFiles(...)
sharingIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
Run Code Online (Sandbox Code Playgroud)

问题

FileProvider 可用于将真实文件传递给外部应用程序。

我不想让我的应用程序中的一些垃圾文件(压缩的文件,仅用于共享)毫无目的地保留下来,以防使用它们的应用程序因某种原因完成、崩溃或停止。

我发现了什么

根据 FileProvider 的 API,我应该实现真正的文件处理:

默认情况下,FileProvider 自动返回与 content:// Uri 关联的文件的 ParcelFileDescriptor。要获取 ParcelFileDescriptor,请调用 ContentResolver.openFileDescriptor。要重写此方法,您必须提供您自己的 FileProvider 子类。

所以它返回一个 ParcelFileDescriptor ,但是根据创建 ParcelFileDescriptor 的所有函数,我需要一个真实的文件:

问题

  1. 是否有可能让它提供一个并不真正存在的文件,但实际上是不同文件的压缩文件?也许是压缩文件的流?

  2. 如果这是不可能的,有什么办法可以避免这些垃圾文件吗?这意味着我可以确定删除我过去共享的压缩文件是安全的吗?

  3. 如果连这都不可能,我如何决定何时可以删除它们?只是将它们放在缓存文件夹中吗?我记得操作系统并没有真正自动很好地处理缓存文件夹,而是在需要时删除旧文件。不还是正确的吗?

由于我尝试了很长时间,所以我只会接受我可以自己测试的可行解决方案。


编辑:根据下面的答案,我在这里做了一个小样本。这是它的代码:

显现

...
    <provider
        android:name=".ZipFilesProvider"
        android:authorities="${applicationId}.zip_file_provider"
        android:exported="false"
        android:grantUriPermissions="true"/>
Run Code Online (Sandbox Code Playgroud)

ZipFilesProvider.kt

import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.content.pm.ProviderInfo
import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import android.os.Build
import android.os.ParcelFileDescriptor
import android.provider.MediaStore
import …
Run Code Online (Sandbox Code Playgroud)

android-intent android-fileprovider

5
推荐指数
1
解决办法
1284
查看次数

无法使用 FileProvider 以编程方式将文件附加到电子邮件意图

我正在创建电子邮件意图并附加文件(使用 FileProvider),但 Gmail 客户端报告“无法附加文件”。

我以前有这个工作,但现在坏了。我没有更改我的代码(我知道),但已经更新了操作系统和 Gmail 客户端。

// Build email Intent
Uri mailToUri = Uri.fromParts("mailto", "", null);
Intent emailIntent = new Intent(Intent.ACTION_SEND, mailToUri);
emailIntent.setType("text/plain");
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "A subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "A body");

// Build the attachment URI
File attachFile = new File(aDirectory, aFileName);
Uri attachmentUri = FileProvider.getUriForFile(this,
                        FILE_PROVIDER_AUTHORITY, attachFile);
emailIntent.putExtra(Intent.EXTRA_STREAM, attachmentUri);

// Start the share activity
startActivity(emailIntent);

// Alternative methods for creating the URI 
// Uri attachmentUri = Uri.parse("file://" 
//                   + attachFile.getAbsolutePath());
// Uri attachmentUri = Uri.parse("content://" 
//                   + FILE_PROVIDER_AUTHORITY
// …
Run Code Online (Sandbox Code Playgroud)

android android-fileprovider

5
推荐指数
1
解决办法
1347
查看次数

如何在 Android 中检索并打开通过 MediaStore API 保存下载的 PDF 文件?

我正在从服务器下载 PDF 文件并将响应正文字节流传递到下面的函数中,该函数将 PDF 文件成功存储在用户下载文件夹中。

@RequiresApi(Build.VERSION_CODES.Q)
fun saveDownload(pdfInputStream: InputStream) {
    val values = ContentValues().apply {
        put(MediaStore.Downloads.DISPLAY_NAME, "test")
        put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
        put(MediaStore.Downloads.IS_PENDING, 1)
    }

    val resolver = context.contentResolver
    val collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    val itemUri = resolver.insert(collection, values)
    if (itemUri != null) {
        resolver.openFileDescriptor(itemUri, "w").use { parcelFileDescriptor ->
            ParcelFileDescriptor.AutoCloseOutputStream(parcelFileDescriptor)
                .write(pdfInputStream.readBytes())
        }
        values.clear()
        values.put(MediaStore.Downloads.IS_PENDING, 0)
        resolver.update(itemUri, values, null, null)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,一旦该函数返回,我想打开保存的 PDF 文件。我尝试了多种方法来使其正常工作,但选择器总是说没有任何内容可以打开文件。我认为要么仍然存在权限问题(也许我使用的 FileProvider 错误?),要么路径错误,或者可能完全是其他问题。

以下是我尝试过的几个示例:

fun uriFromFile(context: Context, file: File): Uri {
    return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file)
}
Run Code Online (Sandbox Code Playgroud)

A)

val openIntent …
Run Code Online (Sandbox Code Playgroud)

java android android-intent kotlin android-fileprovider

5
推荐指数
1
解决办法
2463
查看次数

与FileProvider共享Android照片

我已经阅读了关于这个论点的所有答案,但我总是收到收到我的照片的应用程序的错误.
不仅如此方式工作对我来说,所有的应用程序,是这样的(它的工作原理,因为SD卡的文件都是公开的所有应用程序):

final File tmpFile = new File(context.getExternalCacheDir(), "exported.jpg");
Uri tmpFileUri = Uri.fromFile(tmpFile);

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setDataAndType(tmpFileUri, "image/jpeg");
shareIntent.putExtra(Intent.EXTRA_STREAM, tmpFileUri);
context.startActivity(Intent.createChooser(shareIntent, context.getString(R.string.share_image)));
Run Code Online (Sandbox Code Playgroud)



现在,我坚持如何共享位于私人文件夹中的文件.我使用了google文档提供的代码:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.test.myapp.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true" >
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>
...
...
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="internal_files" path="/"/>
    <cache-path name="internal_cache" path="/" />
</paths>
Run Code Online (Sandbox Code Playgroud)


这是使用该文件共享文件的代码,FileProvider但不适用于任何应用程序,除非是最新的:

final File tmpFile = new File(context.getCacheDir(), "exported.jpg");
Uri tmpFileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", tmpFile);
//Remove the uri permission because we overwrite …
Run Code Online (Sandbox Code Playgroud)

java android android-sharing android-fileprovider

4
推荐指数
1
解决办法
4321
查看次数

从FileProvider创建的Uri获取文件路径

我使用这种方法从Uri获取文件路径https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java#L257

但是当我传递Uri时会抛出异常("_data"列未找到),如下所示:

public static Uri uriFromFile(Context context, String path) {
    if (path == null) return null;
    return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", new File(path));
}
Run Code Online (Sandbox Code Playgroud)

我只需要在我的活动之间传递文件路径..

android uri android-fileprovider

4
推荐指数
1
解决办法
5690
查看次数

使用Android意图打开PDF文件

所以这是场景:

我正在从网络下载 PDF 并将其保存在/0/Download/NSIT - Notices/"fileName".pdf

现在发送 Intent 像这样:

private void openPDF(String fileName) {
    Log.d(TAG, "openPDF: called");
    Intent intent = new Intent(Intent.ACTION_VIEW);File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download", "NSIT - Notices");
    File myPDF = new File(Environment.getExternalStorageDirectory() + "/Download/NSIT - Notices", fileName + ".pdf");
    Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", myPDF);
    Log.d(TAG, "openPDF: intent with uri: " + uri);
    intent.setDataAndType(uri, "application/pdf");
    context.startActivity(Intent.createChooser(intent, "Open with..."));
}
Run Code Online (Sandbox Code Playgroud)

现在任何 PDF 阅读器(Google Drive PDF 阅读器、系统 PDF 查看器)都在说

The File Does Not Exist
Run Code Online (Sandbox Code Playgroud)

图像: 在此输入图像描述

谷歌没有做任何事情(这就是为什么不包括它的图像)

Mainfest.xml

<provider
        android:name="android.support.v4.content.FileProvider" …
Run Code Online (Sandbox Code Playgroud)

pdf android android-intent android-fileprovider android-storage

4
推荐指数
1
解决办法
8287
查看次数

在 onActivityResult 中收到“content://”Uri 后从 MediaStore 获取 PDF?

我开始一个ACTION_GET_CONTENT意图来选择 PDF:

override fun routeToFilePicker() {
    val intent = Intent()
    intent.type = MediaType.PDF.toString()
    intent.action = Intent.ACTION_GET_CONTENT
    activity.startActivityForResult(
        Intent.createChooser(intent, "Select PDF"),
        REQUEST_CODE_PDF_PICKER
    )
}
Run Code Online (Sandbox Code Playgroud)

然后onActivityResult我尝试从 Uri ( ) 创建 PDF content//:path

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_PDF_PICKER ) {
        data?.data?.let { pdfUri: Uri ->
            val pdfFile: File = pdfUri.toFile() <-- chrash
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

pdfUri.toFile()导致致命异常:

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1003, result=-1, data=Intent …
Run Code Online (Sandbox Code Playgroud)

android uri mediastore kotlin android-fileprovider

4
推荐指数
1
解决办法
2646
查看次数

Android“存储”和“重用”获取的 URI

我的应用程序通过 ACTION_PICK Intent 收集媒体以获取 android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI

内容类型。当我检索我想要的内容的 URI 时,效果很好,我可以使用以下命令查看它:

val intent = Intent(Intent.ACTION_VIEW, myURI)
intent.setDataAndType(myURI,contentResolver.getType(myURI))
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
Run Code Online (Sandbox Code Playgroud)

我使用方法存储 Uri Uri.toString,一旦关闭活动并再次打开它,就会收到以下错误:

java.lang.SecurityException: UID 10315 does not have permission to content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FVID_20200814_214253.mp4 [user 0]
Run Code Online (Sandbox Code Playgroud)

再往下还有:

Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermission(UriGrantsManagerService.java:1192)
    at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermissionFromIntent(UriGrantsManagerService.java:579)
    at com.android.server.uri.UriGrantsManagerService.grantUriPermissionFromIntent(UriGrantsManagerService.java:618)
    at com.android.server.uri.UriGrantsManagerService$LocalService.grantUriPermissionFromIntent(UriGrantsManagerService.java:1392)
Run Code Online (Sandbox Code Playgroud)

理想情况下,我会获取媒体的文件路径并通过 fileProvider 从文件生成 URI,但我还没有找到从 ContentURI 获取绝对路径的方法。

通读https://commonsware.com/blog/2016/08/10/uri-access-lifetime-shorter-than-you-might-think.html,它更好地解释了正在发生的事情,那么我如何重用或存储我通过 URI 检索到的文件?我可以通过某种方式检索文件路径而不是 URI 吗?

android uri android-permissions android-fileprovider

4
推荐指数
1
解决办法
1200
查看次数