5

我正在构建一个替换原生 Android 共享对话框的选择器应用程序。它工作正常,除非我尝试通过长按图像 > 共享图像从 Chrome 共享图像。

我发现 Google+ 没有捕捉到异常(它崩溃了),所以我可以通过 Logcat 查看它:

  • 在 Google 上进行图片搜索。
  • 选择一个图像(这应该显示预览)
  • 长按图片
  • 选择“分享图片”
  • 我的选择器活动弹出
  • 选择谷歌+
  • Google+ 因以下错误而崩溃:

java.lang.SecurityException:UID 10130 没有对内容的权限://com.android.chrome.FileProvider/images/screenshot/15307295588677864462883877407218.jpg [用户 0]

我的代码(简化):

@Override
public void onCreate() {
    handleIntent();
}

private void handleIntent() {

    // Get intent and payload
    mIntent = getIntent();
    mPayloadIntent = (Intent) mIntent.getParcelableExtra(Intent.EXTRA_INTENT);

    // Nullify some things for queryIntentActivities (or no results will be found)
    mPayloadIntent.setComponent(null);
    mPayloadIntent.setPackage(null);

    // Retrieve a list of targets we can send mPayloadIntent to..
    List<ResolveInfo> targets = context.getPackageManager().queryIntentActivities(mPayloadIntent, 0);
    // etc...

}

private void onClickTarget(ResolveInfo target) {

    // Prepare..
    ComponentName compName = new ComponentName(
                target.activityInfo.applicationInfo.packageName,
                target.activityInfo.name);

    // Build a 'new' shareIntent
    Intent shareIntent = new Intent(mPayloadIntent);
    shareIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
    shareIntent.setComponent(compName);

    // Start the targeted activity with the shareIntent
    startActivity(shareIntent);
    finish();

}

AndroidManifest.xml:

<activity
    android:name=".ActShareReplace"
    android:label="Sharedr"
    android:theme="@style/AppTheme.TransparentActivity"
    >
    <intent-filter>
        <action android:name="android.intent.action.CHOOSER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

如果我查看Intent.ACTION_CHOOSER的文档,它会说:

如果需要通过选择器授予 URI 权限,除了里面的 EXTRA_INTENT 之外,还必须在 ACTION_CHOOSER Intent 上指定要授予的权限。这意味着使用 setClipData(ClipData) 来指定要授予的 URI 以及 FLAG_GRANT_READ_URI_PERMISSION 和/或 FLAG_GRANT_WRITE_URI_PERMISSION (视情况而定)。

我不完全确定这是否是我的应用程序必须做的事情,或者它是否是调用选择器活动的应用程序的责任 - 但我认为是后者。我的应用无法为其接收的意图设置 URI 权限,可以吗?

无论如何,如果我检查额外的和标志mIntentmPayloadIntent我会得到:

mIntent 只有附加功能,没有标志(据我所知):

android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER IntentSender{4fa3901: android.os.BinderProxy@3aec3a6} (android.content.IntentSender)

android.intent.extra.INTENT Intent { act=android.intent.action.SEND typ=image/jpeg flg=0x80001 clip={image/jpeg U:content://com.android.chrome.FileProvider/images/screenshot/ 15307316967108618905323381238187.jpg}(有附加功能)}(android.content.Intent)

android.intent.extra.TITLE 通过 (java.lang.String) 共享

mPayloadIntent:

android.intent.extra.STREAM 内容://com.android.chrome.FileProvider/images/screenshot/1530731945132897653908815339041.jpg (android.net.Uri$HierarchicalUri)

  • FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
  • FLAG_ACTIVITY_NEW_DOCUMENT
  • FLAG_GRANT_READ_URI_PERMISSION

mPayloadIntent 确实有,FLAG_GRANT_READ_URI_PERMISSION但mIntent没有。根据文档,它应该。

我已经读到我的应用程序可能使用了 URI 权限,所以我尝试自己缓存文件,但是当我尝试通过 ContentResolver 访问 URI 时,我得到 - 你猜对了 - 权限错误。

然后我意识到我可能不应该缓存文件,因为 Android 的原生选择器活动似乎也没有这样做。这就是我现在所处的位置。回到原点。

这是 Chrome 错误吗?安卓漏洞?还是我做错了什么?

我很乐意责怪 Chrome 并提交错误报告,但从事类似项目(并遇到相同问题)的人告诉我 Whatsapp 也有类似问题。它也通过 content:// uri 共享图像。

为了完整起见,我正在使用 Android 8.1 的 Pixel 2016 上进行测试。我不知道其他人(遇到与 WA 相同的问题)正在使用什么。

4

1 回答 1

4

这是 Chrome 错误吗?安卓漏洞?还是我做错了什么?

我的猜测是这是一个客户端错误,来自人们ACTION_CHOOSER Intent直接创建对象而不是通过Intent.createChooser(). Intent.createChooser()看起来它正在从您调用的内容中获取标志mPayloadIntent并将它们添加到mIntent.

你应该可以自己测试一下。创建一个剪贴应用程序,该应用程序创建一个 指向某些内容(例如,由 服务)的ACTION_SEND Intentwith 。然后,尝试以三种方式调用您的选择器:EXTRA_STREAMFileProvider

  1. 包裹Intent通孔Intent.createChooser()

  2. 包装Intentvia an ACTION_CHOOSER Intent,您可以按照文档所说的并将标志放在两个Intent对象上

  3. 包装Intentvia an ACTION_CHOOSER Intent,您可以在其中跳过标志ACTION_CHOOSER Intent

如果我是正确的,#1 和#2 将起作用,而#3 将失败,并出现与您看到的相同的基本故障模式。

如果到目前为止我的理论成立,请尝试再次运行这三个应用程序,但这次使用系统选择器。我的猜测是,系统选择器确实从作为核心操作系统的一部分中获得了一些特殊的好处,并且所有三个都可以工作。否则,Chrome 和 WhatsApp 的开发人员会在测试中遇到这个问题并修复它。

而且,如果所有这些理论都成立......你有点搞砸了。我会假设更多的人使用Intent.createChooser()而不是ACTION_CHOOSER直接使用,因为Intent.createChooser()更简单。而且,一些使用的人ACTION_CHOOSER可能实际上会遵循文档......

哈哈哈哈哈哈哈……喘不过气来……哈哈哈哈哈哈!

...对于那些,你没事。而且,有些人使用的ACTION_CHOOSER内容可能是世界可读的(这不是一个好主意,但它在这里对你有利)。它仅适用于手动创建、未能正确设置标志、但正确保护其内容的错误客户端,您将无法正确处理.UriEXTRA_STREAMACTION_CHOOSERIntentIntent

于 2018-07-04T20:07:06.560 回答