将可绘制图像正确共享到其他应用程序(如果没有 FileProvider,将 PNG 共享到 Whatsapp 会失败)
Share drawable image to other apps properly (sharing PNG to Whatsapp fails without FileProvider)
我正在创建一个 Android 应用程序,用户可以在其中 select 要共享的几张图片之一(存储在 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;
}
但是,如果用户 selects 将其分享到 Whatsapp,它就无法正常工作:它不会将其解释为图像(就像您通常将照片分享到 Whatsapp 一样)认为它是名为 "Untitled" 的文档,未显示为图像。
在计算机上打开此无标题文档会发现它名为 DOC-20180721-WA0012.
,没有文件扩展名!在文件名末尾手动添加 png
会显示正确的图像。
使这个更奇怪(但绝对可以以某种方式解决!):
如果用户选择在短信应用中打开图像,例如,图像正常显示。
多台设备都发生过这种情况(P beta 上的 Pixel 2 和 7.1.1 上的 Nokia 2)
其他应用程序不会发生此问题,在这些应用程序中,PNG 可以像普通图像一样通过 Whatsapp 发送(尽管它们似乎确实会被 Whatsapp 自动转换为 JPEG)。
我该怎么做才能确保 Whatsapp 将我的图像视为正确的 PNG 文件?或者,如何正确地从我的应用程序中分享 pre-loaded 图片,以便每个应用程序都能正确解释它?
我通过正确实现 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
的新目录(按住 Control 键并单击 Android Studio 中的 res
,然后转到新建 > 目录)。然后,在 xml
中创建一个名为 file_provider_paths
的新文件(按住 Control 键并单击新的 xml
目录,然后转到新建 > 文件,并将其命名为 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);
}
大功告成,现在每个应用程序都可以看到您共享的图片了!
我正在创建一个 Android 应用程序,用户可以在其中 select 要共享的几张图片之一(存储在 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;
}
但是,如果用户 selects 将其分享到 Whatsapp,它就无法正常工作:它不会将其解释为图像(就像您通常将照片分享到 Whatsapp 一样)认为它是名为 "Untitled" 的文档,未显示为图像。
在计算机上打开此无标题文档会发现它名为 DOC-20180721-WA0012.
,没有文件扩展名!在文件名末尾手动添加 png
会显示正确的图像。
使这个更奇怪(但绝对可以以某种方式解决!):
如果用户选择在短信应用中打开图像,例如,图像正常显示。
多台设备都发生过这种情况(P beta 上的 Pixel 2 和 7.1.1 上的 Nokia 2)
其他应用程序不会发生此问题,在这些应用程序中,PNG 可以像普通图像一样通过 Whatsapp 发送(尽管它们似乎确实会被 Whatsapp 自动转换为 JPEG)。
我该怎么做才能确保 Whatsapp 将我的图像视为正确的 PNG 文件?或者,如何正确地从我的应用程序中分享 pre-loaded 图片,以便每个应用程序都能正确解释它?
我通过正确实现 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
的新目录(按住 Control 键并单击 Android Studio 中的 res
,然后转到新建 > 目录)。然后,在 xml
中创建一个名为 file_provider_paths
的新文件(按住 Control 键并单击新的 xml
目录,然后转到新建 > 文件,并将其命名为 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);
}
大功告成,现在每个应用程序都可以看到您共享的图片了!