android - 如何使用支持 FileProvider 将内容共享给其他应用程序?

标签 android android-contentprovider android-support-library android-fileprovider

我正在寻找一种使用 Android 支持库的 FileProvider 与外部应用程序正确共享(而不是打开)内部文件的方法。 .

按照文档上的示例,

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.android.supportv4.my_files"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/my_paths" />
</provider>

并使用 ShareCompat 将文件共享给其他应用程序,如下所示:

ShareCompat.IntentBuilder.from(activity)
.setStream(uri) // uri from FileProvider
.setType("text/html")
.getIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

不起作用,因为 FLAG_GRANT_READ_URI_PERMISSION 仅授予对 Intent 的 data 上指定的 Uri 的权限,而不是 EXTRA_STREAM 额外的值(由setStream).

我试图通过将提供程序的 android:exported 设置为 true 来破坏安全性,但 FileProvider 在内部检查自身是否已导出,当所以,它会抛出一个异常。

最佳答案

使用支持库中的 FileProvider,您必须手动授予和撤销权限(在运行时),其他应用程序才能读取特定的 Uri。使用Context.grantUriPermissionContext.revokeUriPermission方法。

例如:

//grant permision for app with package "packegeName", eg. before starting other app via intent
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

//revoke permisions
context.revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

作为最后的手段,如果您不能提供包名称,您可以将权限授予所有可以处理特定 Intent 的应用程序:

//grant permisions for all apps that can handle given intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
...
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

根据 documentation 的替代方法:

  • Put the content URI in an Intent by calling setData().
  • Next, call the method Intent.setFlags() with either FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION or both.
  • Finally, send the Intent to another app. Most often, you do this by calling setResult().

    Permissions granted in an Intent remain in effect while the stack of the receiving Activity is active. When the stack finishes, the
    permissions are automatically removed. Permissions granted to one
    Activity in a client app are automatically extended to other
    components of that app.

顺便说一句。如果需要,可以复制source of FileProvider并更改 attachInfo 方法以防止提供者检查它是否已导出。

关于android - 如何使用支持 FileProvider 将内容共享给其他应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18249007/

相关文章:

java - 将文件上传到保管箱(通过同步)

android - FCM接收消息问题

android - Flutter:让 iFame 在 Android 设备上全屏显示

android - Fcm 徽章不显示在 android 中

android - 手动删除数据库时如何强制内容提供者重置

java - 将 Android 短信对话标记为已读。 Sql 查询一次又一次执行。(错误)

android - 更新 Android 项目中的 Gradle 依赖项

android - S 浏览器书签 URI

android - ClassNotFoundException : android. 支持.v4.View.ViewPager

android - 重新显示 Fragment 时,Fragment 中的 ViewPager 会丢失其内容