如何在 Android 7.1.1 上将图像文件共享到 WhatsApp 和 Viber?

2024-01-15

背景

类似于我最近在共享/打开 APK 文件时遇到的问题(here https://stackoverflow.com/q/41160353/878126, here https://stackoverflow.com/q/41085950/878126 and here https://stackoverflow.com/q/40941709/878126),我现在遇到了将图像文件(在资产、res/raw 甚至从 URL 中)发送到特定应用程序的问题:WhatsApp 和 Viber。

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

问题

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

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

我尝试并发现了什么

1.我开始使用名为“的库”从应用程序的资产文件夹共享文件CWAC 提供商 https://github.com/commonsguy/cwac-provider“。除了 WhatsApp 和 Viber 之外,它适用于所有应用程序。

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

02-06 17:05:04.379 24590-24590/com.whatsapp 附带捆绑包:钥匙 android.intent.extra.STREAM 期望 ArrayList 但值是 android.net.Uri$HierarchicalUri。返回默认值。 02-06 17:05:04.382 24590-24590/com.whatsapp 包含捆绑包:尝试投射 生成的内部异常: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(本机方法) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

2.有人告诉我(here https://github.com/commonsguy/cwac-provider/issues/28#issuecomment-277853514)尝试通过放置一个来分享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.我还尝试将意图的动作更改为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.我发现的另一个奇怪的事情是即使图像来自服务器,也可以很好地与这些应用程序共享图像。它将文件下载到某个地方并共享它。但我看不到它在哪里下载文件。我认为它会位于应用程序的外部存储路径 ("/.../Android/data/com.google.android.apps.photos/...") 上,但它不在那里。

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

manifest

<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>

code:

    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 附带捆绑包:钥匙 android.intent.extra.STREAM 期望 ArrayList 但值是 android.net.Uri$HierarchicalUri。默认值为 回。 02-07 10:21:19.285 24043-24043/com.viber.voip 包含捆绑包: 尝试强制转换生成的内部异常: 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(源文件:156) 在 com.viber.voip.util.af.a(源文件:106) 在 com.viber.voip.HomeActivity.i(源文件:487) 在 com.viber.voip.HomeActivity.onCreate(源文件: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 Photos 应用为何运行良好?

有解决方法吗?

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


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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Android 7.1.1 上将图像文件共享到 WhatsApp 和 Viber? 的相关文章

随机推荐

  • vuex 未加载用 vuex-module-decorators 装饰的模块

    当尝试将带有 vuex module decorators 的存储模块加载到初始化程序中时 我收到此错误 vuex esm js 2f62 261 未捕获类型错误 无法读取属性 Array forEach 的 eval vuex esm j
  • 在 SQL Server 中存储大量 XML 类型数据的最佳实践

    是否有人可以分享有关在 SQL Server 2008 中存储 XML 字段类型数据的最佳实践 我们有很多小型 XML 结构 但也有一些较大 gt 50MB 我们发现删除时速度有点慢 任何建议 战争故事将不胜感激 我发现到目前为止大多数答案
  • SELECT 语句中有多个条件?

    首先 我没有 ABAP 经验 我在这里只是猜测 我想向现有报表中的 SELECT 添加条件 现有代码如下所示 SELECT SINGLE FROM EKPO WHERE EBELN GT MSEG EBELN AND EBELP GT MS
  • 更改PostgreSQL 9.6中某种数据类型表中的所有列

    似乎几个月前我遇到了一个涉及此问题的问题 但现在我似乎找不到了 基本上 我想做两件事 首先 制作了许多表格 其中有几列numeric 20 2 我想把它们全部改为numeric 对于一列来说 该语句很简单 ALTER TABLE table
  • 如何更改 Visual Studio Code 中的 UI 语言?

    如何更改 UI 语言视觉工作室代码 https code visualstudio com 1 0 于 2016 年 4 月发布 打开VScode 按 F1 并输入 显示 选择 配置显示语言 选择你的语言 上面是已安装的语言 下面是其他语言
  • 如何用Java连接MySQL?

    我已经安装了MYSQL服务器5 1 然后我安装了 mysql connector java 3 0 8 stable bin jar 并将其放入驱动器 c 中 文件夹 core 为 C core 然后在计算机的属性中 我创建带有变量名 CL
  • Three.js 鼠标滚轮用于向上/向下移动相机而不是放大/缩小

    你怎么做到这一点 我使用创建了一个场景三 js编辑器 https threejs org editor 并使用 发布 选项下载该项目 我编辑了 app js 文件以导入 OrbitControls 因此现在我可以使用鼠标滚轮 或者在我的情况
  • 从 pod minikube kubernetes 中的容器公开端口

    我是 K8s 新手 我将尝试使用以下命令在 pod 中运行 2 个容器的 minikube kubectl apply f deployment yaml 和这个deployment yml apiVersion v1 kind Pod m
  • 将图像从图像控件存储到 StorageFile

    如何从 Windows 应用商店应用程序中的图像控件将图像存储到 StorageFile 中 我正在使用以下链接 但这对我来说没有用 StorageFile file await StorageFile CreateStreamedFile
  • 当 Perl 内存不足时,是否有标准的行为方式?

    Perl 解释器 又名 perl 在内存不足时是否有标准的行为方式 是否以任何方式记录 指定 以某种统一的方式编码 我对任何表示为正在运行的 Perl 代码契约的标准特别感兴趣 例如 将die叫做 将要END块被执行 ETC 我对这两个 理
  • 如何使discord.py中的数据以表格形式显示?

    您好 我正在创建一个可以制作积分表 排行榜的机器人 下面是效果非常好的代码 def check ctx return lambda m m author ctx author and m channel ctx channel async
  • Angularjs:如何将范围变量传递给指令?

    我正在尝试使用指令创建多个标签并将其附加到 div 如下所示 module directive createControl function return function scope element attrs console log a
  • 在 R 中添加进度条以复制功能

    我在用replicate经营我自己的analyse函数多次 analyse返回一个列表 results lt replicate reps analyse 有没有办法添加进度条 显示当前完成的复制百分比 我尝试过txtProgressBar
  • 如何自定义 chrome devtools elements 面板上的右键单击

    devtools 元素面板右键单击 https i stack imgur com sufm3 png 看上面的图片 右键单击任何节点都会显示选项菜单 例如 添加属性 和 编辑属性 等 我希望能够扩展右键菜单来添加自定义事件 例如 我需要获
  • 使用 gsub 从字符串中删除模式

    我正在努力删除字符串中下划线之前的子字符串 我想使用 通配符 作为下划线之前的位可以变化 a lt c foo 5 bar 7 a lt gsub a perl TRUE 结果应该如下所示 gt a 1 5 7 我也尝试过类似 or 但并没
  • android:如何在折叠工具栏中添加带有文本的按钮

    如何实现如下布局 我可以在没有添加按钮的情况下实现 但是如何添加ADD按钮和添加按钮在向上滚动时应该随着图像的视差而消失 我发现浮动操作按钮无法添加文本 我必须只使用按钮 我的 xml 布局没有添加按钮
  • 创建 HTML5 画布图案并用它们填充内容

    我有困难 createPattern image repeat 我可以用我自己创建的图案填充一个正方形吗 toDataURL and createPattern 我可以用当前画布上的图案填充一个正方形吗 var canvas documen
  • 您最喜欢的低级代码优化技巧是什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 实体框架 6.0 和 Microsoft.Data.SqlClient

    我们正在将本地数据库迁移到 Azure 我们的应用程序使用实体框架 6 安装 ADALSQL dll 后 使用 System Data SqlClient 使用身份验证 Microsoft Active Directory 密码一切正常 当
  • 如何在 Android 7.1.1 上将图像文件共享到 WhatsApp 和 Viber?

    背景 类似于我最近在共享 打开 APK 文件时遇到的问题 here https stackoverflow com q 41160353 878126 here https stackoverflow com q 41085950 8781