图像共享意图适用于Gmail,但崩溃FB和Twitter

我试图让用户分享一个图像到设备上的其他应用程序。 该图像位于我的应用内部存储区的文件/子目录中。 它适用于Gmail,但在回应我的意图时,Facebook和Twitter都崩溃了。

编辑:Google+也正常工作。

这里是代码的相关部分。

在Application.xml中

<provider android:name="android.support.v4.content.FileProvider" android:authorities="org.iforce2d.myapp.MyActivity" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> 

XML / filepaths.xml

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

以下是我的活动中的分享代码:

 File imagePath = new File(getContext().getFilesDir(), "shared"); File newFile = new File(imagePath, "snapshot.jpg"); Uri contentUri = FileProvider.getUriForFile(getContext(), "org.iforce2d.myapp.MyActivity", newFile); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setType("image/jpeg"); shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); List<ResolveInfo> resInfos = getPackageManager().queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo info : resInfos) { getContext().grantUriPermission(info.activityInfo.packageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); } startActivity(Intent.createChooser(shareIntent, "Share image...")); 

在logging时, contentUri的值是:

content://org.iforce2d.myapp.MyActivity/shared/snapshot.jpg

我只使用Gmail,Facebook和Twitter作为接收应用程序进行了检查,但结果在各种操作系统版本(从2.2.1到4.4.3)上都非常一致,而且有7款设备包括Kindle。

Gmail的效果很好。 图像缩略图出现在邮件组成中,并在发送时成功附加到邮件。

Twitter和Facebook都崩溃,如下所示。

这里是logcat的堆栈跟踪,显示这两个应用程序有问题,这两个应用程序似乎是同样的问题(这是来自4.4.3,但错误实际上一直回到2.2。 1尽pipe错误信息的措辞略有不同):

 Caused by: java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetString(Native Method) at android.database.CursorWindow.getString(CursorWindow.java:434) at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51) at android.database.CursorWrapper.getString(CursorWrapper.java:114) at com.twitter.library.media.util.fa(Twttr:95) ... Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetString(Native Method) at android.database.CursorWindow.getString(CursorWindow.java:434) at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51) at android.database.CursorWrapper.getString(CursorWrapper.java:114) at com.facebook.photos.base.media.MediaItemFactory.b(MediaItemFactory.java:233) ... 

鉴于在Facebook和Twitter上共享图像是数百万人整天都在做的事情,我感到非常震惊,很难实现:

任何人都可以发现我在这里做错了吗?

Solutions Collecting From Web of "图像共享意图适用于Gmail,但崩溃FB和Twitter"

编辑 – 在这个答案中描述的解决方法工作,但斯蒂芬提供的解决scheme更优雅。 这应该是被接受的答案。

此外,截至2015年1月,Facebook应用程序不再有这个错误(现在与标准FileProvider ),但Twitter仍然如此。 希望将来它会完全消失,而这些都不是必要的。


虽然FileProvider对象在理论上看起来很棒,但在共享许多第三方应用程序(而Google,如G +,Gmail等)时似乎并不奏效。 要么它不公开足够的信息,要么这些应用程序只是假设你正在共享文件,从而崩溃。

真令人沮丧! :/

我发现共享映像文件的唯一可靠方法是将它们复制到外部存储目录(您可以创build一个.nomedia子目录以避免它们出现在Gallery应用程序中)。

例如:

 Bitmap bitmapToShare = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); File pictureStorage = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); File noMedia = new File(pictureStorage, ".nomedia"); if (!noMedia.exists()) noMedia.mkdirs(); File file = new File(noMedia, "shared_image.png"); saveBitmapAsFile(bitmapToShare, file); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); shareIntent.setType("image/png"); startActivity(shareIntent); 

附录:当然,在尝试写入/复制文件之前,还应该检查getExternalStorageState()

Twitter(错误地)假定将有一个MediaStore.MediaColumns.DATA列。 从KitKat开始MediaStore返回null,所以幸运的是,Twitter优雅地处理空值,并做正确的事情。

 public class FileProvider extends android.support.v4.content.FileProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor source = super.query(uri, projection, selection, selectionArgs, sortOrder); String[] columnNames = source.getColumnNames(); String[] newColumnNames = columnNamesWithData(columnNames); MatrixCursor cursor = new MatrixCursor(newColumnNames, source.getCount()); source.moveToPosition(-1); while (source.moveToNext()) { MatrixCursor.RowBuilder row = cursor.newRow(); for (int i = 0; i < columnNames.length; i++) { row.add(source.getString(i)); } } return cursor; } private String[] columnNamesWithData(String[] columnNames) { for (String columnName : columnNames) if (MediaStore.MediaColumns.DATA.equals(columnName)) return columnNames; String[] newColumnNames = Arrays.copyOf(columnNames, columnNames.length + 1); newColumnNames[columnNames.length] = MediaStore.MediaColumns.DATA; return newColumnNames; } }