如何在Android 7.1.1上与WhatsApp和Viber共享图像文件



背景

与我最近在共享/打开APK文件(此处这里和此处)时遇到的问题类似,我现在也遇到了将图像文件(以资产、res/raw甚至从URL)发送到特定应用程序的问题:WhatsApp和Viber。

我需要能够与所有应用程序共享图像文件,尤其是WhatsApp和Viber等流行应用程序。

问题

当我尝试在Andorid 7.1.1上共享图像文件时,WhatsApp和Viber都有问题。在其他应用程序和以前版本的Android上,它运行良好。

在我尝试过的所有测试中,它们要么显示黑屏(没有图像),要么关闭自己。

我尝试并发现了什么

1.我开始使用名为">cwac provider"的库从应用程序的assets文件夹共享一个文件。除了WhatsApp和Viber,它在所有应用程序中都运行良好。

在WhatsApp上,我得到了这个日志(与我为Viber得到的日志非常相似):

02-06 17:05:04.379 24590-24590/com.whatsapp W/捆绑包:密钥android.intent.extra.STREAM应为ArrayList,但值为android.net.Uri$HierarchicalUri。返回默认值。2006年2月17:05:04.382 24590-24590/com.whatsapp W/捆绑包:尝试投射生成内部异常:java.lang.ClassCastException:android.net.Uri$HierarchicalUri不能强制转换为java.util.ArrayList位于android.os.Bundle.getParcelableArrayList(Bundle.java:916)android.content.Interent.getParcelableArrayListExtra(Intent.java:6357)网址:com.whatsapp.ContactPicker.k(ContactPicker.java:618)com.whatsapp.ContactPicker.onCreate(ContactPicker.java:360)android.app.Activity.performCreate(Activity.java:6668)android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)在android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2633)在android.app.ActivityThread.handleLaunchActivity(ActivityThreads.java:2741)在android.app.ActivityThread.-wrap12(ActivityThreads.java)android.app.ActivityThread$H.handleMessage(ActivityThreads.java:1488)在android.os.Handler.dispatchMessage(Handler.java:102)android.os.Looper.loop(Looper.java:154)android.app.ActivityThread.main(ActivityThread.java:6169)位于的java.lang.reflect.Method.ioke(本机方法)com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)网址:com.android.internal.os.ZygoteInit.main(ZygoteNit.java:778)

2.我被告知(此处)通过将ArrayList<Uri>放入EXTRA_STREAM:来尝试共享

ArrayList<Uri> uriArrayList=new ArrayList<>();
uriArrayList.add(getUri());
share.putExtra(Intent.EXTRA_STREAM, uriArrayList);

它没有起作用,WhatsApp的日志显示:

Caused by: java.lang.SecurityException: Permission Denial: opening provider

com.commonsware.cac.provider.StreamProvider来自ProcessRecord{9405e93 12914:com.whatsapp/u0a210}(pid=12914,uid=10210),而不是从uid 10123导出在android.os.Parcel.readException(Parcel.java:1684)在android.os.Parcel.readException(Parcel.java:1637)位于android.app.ActivityManagerProxy.getContentProvider(ActivityManager Native.java:4213)在android.app.ActivityThread.acquisiteProvider(ActivityThreads.java:5526)在android.app.ContextImpl$ApplicationContentResolver.acquisiteUntableProvider(ContextImpl.java:2239)在android.content.ContentResolver.acquisiteUntableProvider(ContentResolver.java:1517)位于android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1131)位于android.ContentResolver.openAssetFileDescriptor(ContentResolver.java:984)在android.content.ContentResolver.openInputStream(ContentResolver.java:704)网址:com.whatsapp.util.ah.b(MediaFileUtils.java:1290)网址:com.whatsapp.util.ah.a(MediaFileUtils.java:1498)网址:com.whatsapp.util.ah.a(MediaFileUtils.java:1543)网址:com.whatsapp.gallerypicker.ImagePreview$b$1.a(ImagePreview.java:901)网址:com.whatsapp.gallerypicker.ImagePreview$b$1.doInBackground(ImagePreview.java:896)在android.os.AsyncTask$2.call上(AsyncTask.java:305)位于java.util.concurrent.FFutureTask.run(FutureTask.java:237)在android.os.AsyncTask$SerialExecutor$1.run上(AsyncTask.java:243)位于java.util.concurrent.ThreadPoolExecutiator.runWorker(ThreadPoolExecutiator.java:1133)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)

3.我还试图将意图的动作更改为ACTION_SEND_MULTIPLE:

Intent share = new Intent(Intent.ACTION_SEND_MULTIPLE);
...
ArrayList<Uri> uriArrayList=new ArrayList<>();
uriArrayList.add(getUri());
share.putExtra(Intent.EXTRA_STREAM, uriArrayList);

但它也没有帮助,显示了Viber的日志(看不到WhatsApp的任何特别内容):

02-07 09:54:07.084 926-10718/system_process W/活动经理:拒绝权限:打开提供程序com.commonsware.cac.provider.StreamProvider来自ProcessRecord{adbb1ed 5565:com.viber.wvoip/u0a175}(pid=5565,uid=10175),未从uid 10123 02-07 09:54:07.087导出926-10717/system_process W/ActivityManager:拒绝权限:打开provider com.commonsware.cvac.provider.StreamProvider来自ProcessRecord{adbb1ed 5565:com.viber.wvoip/u0a175}(pid=5565,uid=10175),未从uid 10123 02-07 09:54:07.091导出926-946/system_process W/ActivityManager:拒绝权限:打开provider com.commonsware.cvac.provider.StreamProvider来自ProcessRecord{adbb1ed 5565:com.viber.wvoip/u0a175}(pid=5565,uid=10175),而不是从uid 10123 导出

4.奇怪的是,对于WhatsApp来说,在上述所有尝试中,它都要求获得存储权限,尽管它不应该这样做(因为该应用程序无论如何都是自己提供内容的)。

5.我发现的另一件奇怪的事情是,谷歌照片应用程序可以很好地将图像共享到这些应用程序,即使图像来自服务器。它将文件下载到某个地方并共享。但是我看不到它在哪里下载文件。我以为它会在应用程序的外部存储路径上("/…/Android/data.com/google.Android.apps.photos/…"),但它不在那里。

6.我试图通过使用支持库的FileProvider(我已经知道如何从共享APK文件中使用)来创建从外部存储共享文件的POC:

清单

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>

res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>

代码:

final File bitmapFile = new File(getExternalFilesDir(null), "test.jpg");
if (!bitmapFile.exists()) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), android.R.drawable.sym_def_app_icon);
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(bitmapFile));
}
Intent intent = new Intent(Intent.ACTION_SEND);
Uri fileUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", bitmapFile);
intent.setType(MimeTypeMap.getSingleton().getMimeTypeFromExtension("jpg"));
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

但它只适用于WhatsApp,而不适用于显示日志的Viber

02-07 10:21:19.285 24043-24043/com.viber.wip W/捆绑包:密钥android.intent.extra.STREAM应为ArrayList,但值为android.net.Uri$HierarchicalUri。默认值为返回。02-07 10:21:19.285 24043-24043/com.viber.wip W/捆绑包:尝试强制转换生成的内部异常:java.lang.ClassCastException:android.net.Uri$HierarchicalUri不能强制转换为java.util.ArrayList位于android.os.Bundle.getParcelableArrayList(Bundle.java:916)位于android.content.Interent.getParcelableArrayListExtra(Intent.java:6357)网址:com.viber.wvoip.util.af.f(源文件:156)网址:com.viber.wvoip.util.af.a(源文件:106)网址:com.viber.evop.HomeActivity.i(源文件:487)网址:com.viber.evop.HomeActivity.onCreate(源文件:317)在android.app.Activity.performCreate(Activity.java:6668)在android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)在android.app.ActivityThread.performLaunchActivity(ActivityThreads.java:2633)在android.app.ActivityThread.handleLaunchActivity(ActivityThreads.java:2741)在android.app.ActivityThread.-wrap12(ActivityThreads.java)在android.app.ActivityThread$H.handleMessage(ActivityThreads.java:1488)在android.os.Handler.dispatchMessage(Handler.java:102)在android.os.Looper.loop(Looper.java:154)在android.app.ActivityThread.main(ActivityThreads.java:6169)位于java.lang.reflect.Method.ioke(本机方法)网址:com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)网址:com.android.internal.os.ZygoteInit.main(ZygoteNit.java:778)

我试图执行我在#2和#3上所做的操作,但在Viber上仍然不起作用。

7.我尝试使用旧的方法从外部存储共享文件,这应该被FileProvider:取代

startActivityForResult(Intent.createChooser(prepareIntentToSharePhoto(bitmapFile.getAbsolutePath(), "title",
"body"), "choose"), 1);
public static Intent prepareIntentToSharePhoto(String imagePath, String title, String body) {
Intent sharingIntent = new Intent(Intent.ACTION_SEND).setType("image/*")
.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + imagePath)).putExtra(android.content.Intent.EXTRA_SUBJECT, title)
.putExtra(android.content.Intent.EXTRA_TEXT, body);
return sharingIntent;
}

它适用于这两个应用程序,但只有当它们都被授予存储权限时才有效。对于Viber,如果它没有存储权限,它会显示一个黑色图像,而对于WhatsApp,它会要求用户授予它。

问题

为什么以上任何一项都不起作用?

我应该如何正确地将图像文件共享到这些应用程序?通过FileProvider进行共享有什么问题?为什么谷歌照片应用程序运行良好?

有解决办法吗?

这是应用程序本身的问题,还是安卓系统的问题?

现在我将使用解决方案#7,但它并不完美,因为它需要Viber和;WhatsApp应用程序在能够访问文件之前(向自己)授予存储权限。

遗憾的是,我认为它需要对选择器上的所有应用程序都有此权限。

如果Viber还没有获得此权限,它将显示一个黑屏。

最新更新