由于缺少URI权限,重新发送意图失败

时间:2017-03-03 13:40:54

标签: android android-intent android-activity

在我的应用中,所有活动都受到登录保护:
每个活动都会检查其onCreate / onShow - 回调用户是否已登录。如果是,则不会发生任何特殊情况。但是,如果用户未登录,则这些回调会将用户重定向到LoginActivity并完成当前活动:

Intent loginIntent = new Intent(this, LoginActivity.class);
loginIntent.putExtra(EXTRA_ORIGINAL_INTENT, getIntent());
finish();
startActivity(loginIntent);

如上面的行所示,用于启动当前活动的原始Intent会添加到loginIntent的附加内容中。因此,LoginActivity可以在成功登录后重新发送Intent ...理论上。但是,这并不总是有效。

从启动器启动时有效:

Intent with ACTION_MAIN --> MainActivity --> Redirect to LoginActivity -->
Redirect back to MainActivity after successful login

在Chrome上使用共享按钮时无效:

Intent with ACTION_SEND --> SendActivity --> Redirect to LoginActivity -->
Redirect back to SendActivity after successful login

问题是上次重定向尝试重新发送用于初始启动Intent的原始SendActivity

// Resend original intent
startActivity((Intent) getIntent().getExtra(EXTRA_ORIGINAL_INTENT));

失败并出现异常:

Caused by: java.lang.SecurityException: Uid 10075 does not have permission to uri 0 @ content://com.android.chrome.FileProvider/images/screenshot/6471932623902346234.jpg

现在我的问题:
如何在不导致该权限例外的情况下重新发送Intent? 如何传递所需的权限?

注意:我真的想要重定向行为,完成当前活动并重新发送Intent。不能简单地将活动(MainActivitySendActivity)保留在堆栈上,并由于各种原因从LoginActivity返回它们。

2 个答案:

答案 0 :(得分:1)

如果权限沿Intent / LoginActivity链传递,则重新发送Activity中的原始Intent。这可以通过以下方式实现:

  1. 重定向 - Intents是原始Intent
  2. 的副本
  3. 重新发送之前,Intent已明确显示。
  4. 例如SomeActivity使用用于启动LoginActivity的{​​{1}}的副本重定向到Intent

    SomeActivity

    现在,成功登录后,Intent loginIntent = new Intent(getIntent()); // copy ... loginIntent.setClass(this, LoginActivity.class); // ... explicit now // maybe loginIntent.setAction(...) etc. loginIntent.putExtra(EXTRA_ORIGINAL_INTENT, getIntent()); finish(); startActivity(loginIntent); 可以重定向回LoginActivity

    SomeActivity

答案 1 :(得分:0)

一般来说,您遗失的是FLAG_GRANT_READ_URI_PERMISSION

当您从外线方(例如,UriEXTRA_STREAM)获得ACTION_SEND时,您应该被授予至少阅读{{1}标识的内容的权限}。这本身就是is a bit tricky to set up

但是,该权限授予仅适用于收到Uri的组件(例如,您对Intent做出响应的活动)。如果您尝试将工作委托给其他任何事件(其他活动,服务等),该组件将没有权限。

所以,你有几个选择:

一种方法是将您的身份验证/授权内容转换为可以 in situ 使用的片段或其他UI,而不是启动其他活动。这样您就可以将用户全部保存在一个位置,并且该位置具有对内容的读取权限。

另一种方法是在将用户重定向到ACTION_SEND之前使用内容。

另一种方法是不LoginActivity原始活动,并使用finish() FLAG_ACTIVITY_REORDER_TO_FRONT将原始活动的现有实例带回前台。从理论上讲,它应该仍然具有对内容的读取权限。您的问题来自于您正在销毁原始实例并创建一个新实例,并且新实例没有读取权限。

另一种方法是尝试在LoginActivity FLAG_GRANT_READ_URI_PERMISSION以及稍后通过LoginActivity传递的Intent上添加Intent额外。我猜这是行不通的。

上述主题的变体不仅是将原始EXTRA_ORIGINAL_INTENT放入Intent,而且还提取其EXTRA_ORIGINAL_INTENT以及{{1}的数据方面的内容}} Uri

LoginActivity

Intent可能还需要在Intent loginIntent = new Intent(this, LoginActivity.class); loginIntent.putExtra(EXTRA_ORIGINAL_INTENT, getIntent()); loginIntent.setData(getIntent().getData()); loginIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); LoginActivity上拨打addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

基本上,在后一种情况下,您希望原始活动为Intent授予读取权限,只是为了EXTRA_ORIGINAL_INTENT可以将读取权限授予原始活动的新实例

最后,您使用的原始活动的任何实例都需要具有对内容的读取权限,并且由您授予访问权限,以确保实例具有该访问权限取决于您从...开始。