【问题标题】:How to share an image file to WhatsApp and Viber on Android 7.1.1?如何在 Android 7.1.1 上将图像文件共享到 WhatsApp 和 Viber?
【发布时间】:2017-02-07 08:25:41
【问题描述】:

背景

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

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

问题

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

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

我的尝试和发现

1.我开始使用名为“cwac-provider”的库共享应用程序资产文件夹中的文件。除了 WhatsApp 和 Viber 之外,它适用于所有应用程序。

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

02-06 17:05:04.379 24590-24590/com.whatsapp W/Bundle: Key android.intent.extra.STREAM 预期 ArrayList 但值是 android.net.Uri$HierarchicalUri。已返回默认值。 02-06 17:05:04.382 24590-24590/com.whatsapp W/Bundle:尝试投射 生成的内部异常:java.lang.ClassCastException: android.net.Uri$HierarchicalUri 不能转换为 java.util.ArrayList 在 android.os.Bundle.getParcelableArrayList(Bundle.java:916) 在 android.content.Intent.getParcelableArrayListExtra(Intent.java:6357) 在 com.whatsapp.ContactPicker.k(ContactPicker.java:618) 在 com.whatsapp.ContactPicker.onCreate(ContactPicker.java:360) 在 android.app.Activity.performCreate(Activity.java:6688) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2633) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2741) 在 android.app.ActivityThread.-wrap12(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.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.invoke(Native Method) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

2.我被告知 (here) 尝试通过将 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.cwac.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(ActivityManagerNative.java:4213) 在 android.app.ActivityThread.acquireProvider(ActivityThread.java:5526) 在 android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2239) 在 android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1517) 在 android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1131) 在 android.content.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.FutureTask.run(FutureTask.java:237) 在 android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)

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

                                                          at java.lang.Thread.run(Thread.java:761)

3.我也试过把intent的action改成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/ActivityManager: 许可拒绝:开放提供者 com.commonsware.cwac.provider.StreamProvider 来自 ProcessRecord{adbb1ed 5565:com.viber.voip/u0a175} (pid=5565, uid=10175) 不是从 uid 10123 02-07 09:54:07.087 导出的 926-10717/system_process W/ActivityManager:权限拒绝:打开 提供者 com.commonsware.cwac.provider.StreamProvider 来自 ProcessRecord{adbb1ed 5565:com.viber.voip/u0a175} (pid=5565, uid=10175) 不是从 uid 10123 02-07 09:54:07.091 导出的 926-946/system_process W/ActivityManager:权限拒绝:打开 提供者 com.commonsware.cwac.provider.StreamProvider 来自 ProcessRecord{adbb1ed 5565:com.viber.voip/u0a175} (pid=5565, uid=10175) 不是从 uid 10123 导出的

4. 奇怪的是,对于 WhatsApp,在上述所有尝试中,它都会请求存储权限,尽管它不应该(因为无论如何应用程序都会自行提供内容)。

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

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

清单

<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.voip W/Bundle: Key android.intent.extra.STREAM 预期 ArrayList 但值是 android.net.Uri$HierarchicalUri。默认值为 回来。 02-07 10:21:19.285 24043-24043/com.viber.voip W/Bundle: 尝试强制转换生成的内部异常: java.lang.ClassCastException: android.net.Uri$HierarchicalUri 不能 被强制转换为 java.util.ArrayList 在 android.os.Bundle.getParcelableArrayList(Bundle.java:916) 在 android.content.Intent.getParcelableArrayListExtra(Intent.java:6357) 在 com.viber.voip.util.af.f (SourceFile:156) 在 com.viber.voip.util.af.a(源文件:106) 在 com.viber.voip.HomeActivity.i(SourceFile:487) 在 com.viber.voip.HomeActivity.onCreate(SourceFile:317) 在 android.app.Activity.performCreate(Activity.java:6688) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2633) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2741) 在 android.app.ActivityThread.-wrap12(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.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.invoke(本机方法) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.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 共享有什么问题?为什么 Google 相册应用运行良好?

有解决办法吗?

这是应用本身的问题,还是 Android 的问题?

【问题讨论】:

  • 您是否在使用外部存储,您是否请求了使用权限?
  • @AviParshan 您提供的链接仅用于发送文本。我询问了有关发送图像文件的问题。关于存储权限,从特定的 Android 版本(API 19 - Kitkat)开始,您不需要存储权限即可将文件写入您自己应用的专用外部存储(阅读此处:developer.android.com/reference/android/…)。该应用程序可以很好地读写这个文件,我可以通过文件管理器看到它,它成功地这样做了。我试图添加并授予此权限以防万一。它没有帮助。
  • 对于我构建的 meme maker 应用程序,我能够很容易地做到这一点。我将在今天晚些时候的答案中发布代码。它基本上发送共享意图,传递图像和一些文本(可选)。我能够将其发布到whatsapp。奇怪的是它如何处理照片,而不是其他应用程序。你能分享分享意图的图片吗?
  • @AviParshan 看代码。示例应用程序动态创建图像。我在 #7 上也写了一个工作代码(我认为你可能使用过),但它需要 WhatsApp 和 Viber 来获得存储权限,而最初他们不需要它,只要他们使用标准的方式分享内容。

标签: android android-intent whatsapp commonsware-cwac viber


【解决方案1】:

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

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

如果 Viber 尚未授予此权限,则会显示黑屏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    相关资源
    最近更新 更多