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" 因为,接收应用程序中的这个错误会影响用户,用户之前不能使用该应用程序并授予必要的权限。或者:
用户以前从未使用过该应用程序,但它仍在尝试与它共享内容,或者
用户通过设置撤销了权限,但没有意识到这会破坏这一点功能
这两个都是小概率事件。
作为发件人,您有两个主要选择:
不再使用 file://
Uri
值,转而使用像 FileProvider
这样的文件服务 ContentProvider
,因此权限为 no不再需要,或
只是生活在角落里
我按照@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);
应该可以解决问题。
我正在分享一张图片,此代码适用于 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" 因为,接收应用程序中的这个错误会影响用户,用户之前不能使用该应用程序并授予必要的权限。或者:
用户以前从未使用过该应用程序,但它仍在尝试与它共享内容,或者
用户通过设置撤销了权限,但没有意识到这会破坏这一点功能
这两个都是小概率事件。
作为发件人,您有两个主要选择:
不再使用
file://
Uri
值,转而使用像FileProvider
这样的文件服务ContentProvider
,因此权限为 no不再需要,或只是生活在角落里
我按照@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);
应该可以解决问题。