将可绘制图像正确共享到其他应用程序(在没有 FileProvider 的情况下将 PNG 共享到 Whatsapp 失败)

Posted

技术标签:

【中文标题】将可绘制图像正确共享到其他应用程序(在没有 FileProvider 的情况下将 PNG 共享到 Whatsapp 失败)【英文标题】:Share drawable image to other apps properly (sharing PNG to Whatsapp fails without FileProvider) 【发布时间】:2018-12-29 20:59:20 【问题描述】:

我正在创建一个 android 应用程序,用户可以在其中选择要共享的多个图像之一(存储在 drawable 文件夹中),并且该应用程序会打开一个标准 ACTION_SEND 选择器以允许他们将其共享到任何应用程序支持 PNG,如下所示:

Uri imageUri = Uri.parse("android.resource://com.owlswipe.imagesharer/" + getImage());

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
sendIntent.setType("image/png");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(sendIntent, "share to an app"));

public int getImage() 
return R.drawable.firstimage;

但是,如果用户选择将其分享给 Whatsapp,它就无法正常工作:它不会将其解释为图像(就像您通常将照片分享给 Whatsapp),它认为这是一个名为“无标题”的文档,并且不显示为图像。

在计算机上打开此无标题文档会发现它名为DOC-20180721-WA0012.,没有文件扩展名!手动在文件名末尾添加png 会显示正确的图像。

让这个更奇怪(但绝对可以以某种方式解决!):

如果用户选择在短信应用中打开图片,例如,图片会正常显示。

这种情况发生在多台设备上(P beta 上的 Pixel 2 和 7.1.1 上的 Nokia 2)

此问题不会发生在其他应用程序中,在这些应用程序中,PNG 可以像普通图像一样通过 Whatsapp 发送(尽管它们似乎确实被 Whatsapp 自动转换为 JPEG)。


我可以做些什么来确保 Whatsapp 将我的图片视为正确的 PNG 文件?或者,如何正确共享我的应用中的预加载图像,以便每个应用都能正确解释它?

【问题讨论】:

【参考方案1】:

我通过正确实现 FileProvider 解决了这个问题! This guide helped me so much,不过我在这里做一个简单的总结。

在 Manifest 的 application 标记内,开始像这样声明新的 FileProvider:

<provider
android:name="android.support.v4.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="$applicationId">

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_provider_paths"/>

</provider>

然后,创建一个名为 xml 的新目录(在 Android Studio 中按住 Control 单击您的 res 并转到新建 > 目录)。然后,在xml 中创建一个名为file_provider_paths 的新文件(按住Control 单击新的xml 目录,然后转到New > File,并将其命名为file_provider_paths.xml)。将此代码添加到新的 xml 文件中:

<paths>
    <cache-path name="cache" path="/" />
    <files-path name="files" path="/" />
</paths>

最后,在您的 MainActivity 或类似的地方使用它:

// create new Intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);

// set flag to give temporary permission to external app to use your FileProvider
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// generate URI, I defined authority as the application ID in the Manifest, the last param is file I want to open
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, imageFile);
intent.putExtra(Intent.EXTRA_STREAM, uri);

// Set type to only show apps that can open your PNG file
intent.setType("image/png");

// start activity!
startActivity(Intent.createChooser(intent, "send"));

为了从我的drawable 目录中的图像中获取imageFile,我首先将其转换为位图,然后转换为文件对象,如下所示:

// create file from drawable image
Bitmap bm = BitmapFactory.decodeResource(this.getResources(), R.drawable.yourbeautifulimage);

File filesDir = getApplicationContext().getFilesDir();
File imageFile = new File(filesDir, "ABeautifulFilename.png");

OutputStream os;
try 
    os = new FileOutputStream(imageFile);
    bm.compress(Bitmap.CompressFormat.PNG, 100, os); // 100% quality
    os.flush();
    os.close();
 catch (Exception e) 
    Log.e(getClass().getSimpleName(), "Error writing bitmap", e);

大功告成,现在每个应用都可以看到您共享的图片了!

【讨论】:

以上是关于将可绘制图像正确共享到其他应用程序(在没有 FileProvider 的情况下将 PNG 共享到 Whatsapp 失败)的主要内容,如果未能解决你的问题,请参考以下文章

将可绘制资源图像转换为位图

java 将可绘制图像转换为BitmapDrawable

如何将可绘制的形状与图像一起使用?

如何将图像从 Android 中的 Drawable 附加到彩信?

将可放置的 div 拖到背景图像上的特定点

如何将可点击的图像添加到 UIPickerView 行?