Android6:不能共享文件了?

Android 6: cannot share files anymore?

我正在分享一张图片,此代码适用于 Android 6:

之前的设备
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
Uri uri = Uri.fromFile(new File(mFilename));
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
mContext.startActivity(Intent.createChooser(shareIntent, mChooserTitle));

但是,当我尝试使用 Android 6.

进行共享时,我收到 toast 错误“无法附加空文件

我确认该文件存在并且它不是零长度的。

有人对此有解决方案吗?

Android6.0 运行时权限系统的一个限制是会出现导致问题的极端情况。您遇到的是一个:尝试将外部存储上的文件共享到没有针对特定 UI 路径进行运行时权限检查的应用程序。

我说这是一个 "corner case" 因为,接收应用程序中的这个错误会影响用户,用户之前不能使用该应用程序并授予必要的权限。或者:

  • 用户以前从未使用过该应用程序,但它仍在尝试与它共享内容,或者

  • 用户通过设置撤销了权限,但没有意识到这会破坏这一点功能

这两个都是小概率事件。

作为发件人,您有两个主要选择:

  1. 不再使用 file:// Uri 值,转而使用像 FileProvider 这样的文件服务 ContentProvider,因此权限为 no不再需要,或

  2. 只是生活在角落里

我按照@CommonsWare

的建议通过实施FileProvider解决了这个问题

您首先需要配置一个FileProvider:

  • 首先,将 <provider> 添加到您的文件清单 XML

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.myfileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_paths" />
    </provider>
    
  • 其次,在单独的XML文件中定义你的文件路径,我称之为“file_provider_paths.xml

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="share" path="/" />
    </paths>
    

你可以在这个documentation page

中找到完整的解释

在 XML 中设置文件提供程序后,这是共享图像文件的代码:

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
Uri fileUri = FileProvider.getUriForFile(mContext, "com.myfileprovider", new File(mFilename));
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
mContext.startActivity(Intent.createChooser(shareIntent, mChooserTitle));

我用来解决此问题的另一种方法是在将文件写入 public 目录后立即使用 MediaScannerConnection 获取内容提供商样式 URI:

        MediaScannerConnection.scanFile(context, new String[] {imageFile.toString()}, yourMimeType, new OnScanCompletedListener() {
            @Override
            public void onScanCompleted(String path, Uri uri) {
                //uri = "content://" style URI that is safe to attach to share intent
            }
        });

这可能是满足您需求的更短的解决方案。

或者,您不需要 ContentProvider / FileProvider 。您可以简单地添加授予对共享的 uri 的读取权限的标志。 具体来说,share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 应该可以解决问题。