Пользовательское действие выбора: SecurityException UID n не имеет разрешения на содержимое:// uri
Я создаю приложение Chooser, которое заменяет родной диалог Android Share. Он работает нормально, за исключением случаев, когда я пытаюсь поделиться изображением из Chrome через longpress image > поделиться изображением.
Я обнаружил, что Google+ не ловит исключение (оно вылетает), поэтому я могу посмотреть на него через Logcat:
- Сделайте поиск изображений в Google.
- Выберите изображение (это должно показать предварительный просмотр)
- Лонгпресс изображение
- Выберите "Поделиться изображением"
- Мой выбор деятельности всплывает
- Выберите 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 через селектор, вы должны указать разрешения, которые будут предоставлены в намерении ACTION_CHOOSER в дополнение к EXTRA_INTENT внутри. Это означает использование setClipData(ClipData) для указания URI, которые должны быть предоставлены, а также FLAG_GRANT_READ_URI_PERMISSION и / или FLAG_GRANT_WRITE_URI_PERMISSION в зависимости от ситуации.
Я не совсем уверен, что это то, что мое приложение должно делать, или это ответственность приложения, которое вызвало действие выбора - но я бы предположил, что это последнее. Мое приложение не может установить разрешения URI для намерений, которые оно получает, не так ли?
Во всяком случае, если я проверю дополнительные и флаги на mIntent
а также mPayloadIntent
Я получил:
У 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 content: //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
но не намерен. Согласно документам это должно быть.
Я читал, что, возможно, мое приложение использует разрешение URI, поэтому я попытался кэшировать файл сам, но как только я пытаюсь получить доступ к URI через ContentResolver, я получаю - как вы уже догадались - ошибку разрешения.
Затем я понял, что мне, вероятно, не нужно кэшировать файл, так как родная Android- функция Chooser Activity, похоже, тоже этого не делает. Так вот где я сейчас. Возвращается на круги своя.
Это ошибка Chrome? Ошибка Android? Или я что-то не так делаю?
Я бы с радостью обвинил Chrome и подал отчет об ошибке, но кто-то, кто работает над похожим проектом (и столкнулся с той же проблемой), сказал мне, что у Whatsapp есть похожая проблема. Он также делится изображениями через контент:// uri.
Для полноты я тестирую это на Pixel 2016 с Android 8.1. Я понятия не имею, что использует другой парень (который столкнулся с той же проблемой с WA).
1 ответ
Это ошибка Chrome? Ошибка Android? Или я что-то не так делаю?
Я предполагаю, что это ошибка на стороне клиента, исходящая от людей, создающих ACTION_CHOOSER
Intent
объекты напрямую, а не через Intent.createChooser()
, Intent.createChooser()
Похоже, он принимает флаги от того, что вы назвали mPayloadIntent
и добавляет их в mIntent
,
Вы должны быть в состоянии проверить это самостоятельно. Создайте приложение для записок, которое создает ACTION_SEND
Intent
с EXTRA_STREAM
указывая на какой-то кусок контента (например, обслуживаемый FileProvider
). Затем попробуйте вызвать вашего выбора тремя способами:
Обернуть
Intent
с помощьюIntent.createChooser()
Обернуть
Intent
черезACTION_CHOOSER
Intent
где вы следите за тем, что говорят документы, и ставите флаги наIntent
объектыОбернуть
Intent
черезACTION_CHOOSER
Intent
где вы пропускаете флаги наACTION_CHOOSER
Intent
Если я прав, № 1 и № 2 будут работать, а № 3 не сработает с тем же основным режимом отказа, который вы видите.
Если моя теория верна, попробуйте снова запустить три приложения, но на этот раз используйте систему выбора системы. Я предполагаю, что система выбора действительно получает некоторые особые преимущества, будучи частью основной ОС, и все три будут работать. В противном случае разработчики Chrome и WhatsApp столкнулись бы с этой проблемой при тестировании и исправили бы ее.
И, если вся эта теория справедлива... вы немного облажались. Я бы предположил, что больше людей используют Intent.createChooser()
чем использовать ACTION_CHOOSER
прямо, как Intent.createChooser()
проще И некоторое подмножество людей, которые используют ACTION_CHOOSER
может на самом деле следовать документации...
ха-ха-ха-ха-ха-ха-ха... вздох... ха-ха-ха-ха-ха-ха-ха-ха!
... и для тех, ты в порядке. И некоторые люди, использующие ACTION_CHOOSER
может иметь Uri
в EXTRA_STREAM
это доступно для чтения всему миру (что не очень хорошая идея, но здесь это работает в вашу пользу). Это будет только для глючных клиентов, которые создают ACTION_CHOOSER
вручную, не удается установить Intent
помечать правильно, но защищать их содержимое должным образом, чтобы вы не смогли правильно обработать Intent
,