Android:如何将相机结果保存到私有文件?

7

我正在尝试从相机获取图像,并直接保存到我的应用程序的私有文件目录中。出于安全考虑,该图像不应在任何时候公开访问。

一般来说,授予对私有文件的临时访问权限的方法是使用ContentProvider并在Intent中设置GRANT_WRITE_URI_PERMISSION标志。根据FileProvider中的文档,我已经完成了以下步骤:

AndroidManfiest.xml

<manifest> 
    ...
    <application>
        ...
        <provider
            android:authorities="com.my.domain"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        ...

res/xml/file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
</paths>

当启动相机活动时,我从一个活动中执行以下操作:

File imageFile = getInternalImageFile();
Uri captureUri = FileProvider.getUriForFile(this, "com.my.domain", imageFile);

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

// grant temporary access to the file
intent.setData(captureUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

// tell the camera where to save the file
intent.putExtra(MediaStore.EXTRA_OUTPUT, captureUri);

startActivityForResult(intent, IMAGE_CAPTURE_REQUEST_CODE);

然而,这会导致相机应用程序立即返回而不执行任何操作。我怀疑是因为它没有预料到意图(Intent.setData())上有任何数据。

以上策略效果不佳。那么,我该如何将从相机拍摄的图像安全地直接保存到我的应用程序的私有文件目录中?


问题在于,授予访问私有文件的权限只有在应用程序实际使用它时才有效。在您的情况下,我建议先将文件保存在任何地方,然后再将其移动到私有存储中。 - njzk2
@njzk2,这实际上是我应用程序目前所做的事情,但是已经确定将文件保存到外部存储器(或任何公开可访问的地方)在任何时间段内都存在安全风险。因此需要将其直接保存到内部存储器。 - Nathan Taylor
您可以在应用程序中重新实现相机活动。 - njzk2
2个回答

10

我曾经遇到同样的问题,但是通过使用clipData解决了它。

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setClipData(ClipData.newRawUri(null, contentUri));
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);

http://developer.android.com/reference/android/content/Intent.html#setClipData(android.content.ClipData)

Intent中的ClipData不用于匹配Intent或其他类似操作。从语义上讲,它像extras一样,用于传输与Intent相关的附加数据。使用这个功能而不是使用extras传递数据的主要特点是FLAG_GRANT_READ_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSION将在剪贴板数据中包含的任何URI项上操作。这在特定情况下非常有用,例如,您希望传输一个Intent,其中包含多个content: URI,接收者可能没有全局访问内容提供程序的权限。

希望这可以帮助你。

Pd:对于我的英语,抱歉。 :)


4
你好,我希望你能帮我翻译以下内容:Hi, I am having difficulty with setting contentURI, is it similar to captureUri as in the question ? A bit of code about defining contectURI would really be a great help。你好,我在设置contentURI时遇到了困难,它是否类似于问题中的captureUri? 有关定义contentURI的代码片段将非常有帮助。 - Deepak Negi
这是一个很好的答案。我已经搜索了几个小时,没有看到任何关于setClipData()的文档或示例。没有它,我总是会得到一个SecurityException(“Permission Denial:opening provider…”)。我仍然需要弄清楚如何访问通过我的相机存储的文件,但至少它似乎已经被存储在某个地方了 ;) - TheOperator

1
所以,我该如何将从相机拍摄的图像安全地保存到我的应用程序的私有文件目录中? 使用android.hardware.Camera自己拍照。不能保证用户会有一个相机应用程序可用,知道如何保存数据到content://Uri路径。它们应该支持它们,但并非所有应用都支持。例如,Google Camera应用在2016年6月之前不支持ACTION_VIDEO_CAPTUREcontent://Uri

请再次阅读javadoc,EXTRA_OUTPUT需要一个内容Uri。 - sergio91pt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接