Приложение падает, когда я пытаюсь открыть файл. Работает ниже Android Nougat, но на Android Nougat вылетает. Вылетает только при попытке открыть файл с SD-карты, а не из системного раздела. Некоторая проблема с разрешением?
Образец кода:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
Журнал:
android.os.FileUriExposedException: файл: ///storage/emulated/0/test.txt, доступный за пределами приложения через Intent.getData ()
Редактировать:
При таргетинге на Android-нугу file://
URI больше не разрешены. Мы должны использовать content://
URI вместо этого. Тем не менее, мое приложение должно открывать файлы в корневых каталогах. Любые идеи?
android
android-file
android-7.0-nougat
Томас Вос
источник
источник
Ответы:
Если ваш
targetSdkVersion >= 24
, то мы должны использоватьFileProvider
класс, чтобы предоставить доступ к определенному файлу или папке, чтобы сделать их доступными для других приложений. Мы создаем наш собственный класс наследованияFileProvider
, чтобы убедиться, что наш FileProvider не конфликтует с FileProvider, объявленными в импортированных зависимостях, как описано здесь .Шаги по замене
file://
URI наcontent://
URI:Добавьте расширение класса
FileProvider
Добавить FileProvider
<provider>
тегAndroidManifest.xml
под<application>
тегом. Укажите уникальные права доступа дляandroid:authorities
атрибута, чтобы избежать конфликтов, могут указывать импортированные зависимости${applicationId}.provider
и другие часто используемые права доступа.provider_paths.xml
файл вres/xml
папке. Папка может понадобиться для создания, если она не существует. Содержание файла показано ниже. Он описывает, что мы хотели бы поделиться доступом к внешнему хранилищу в корневой папке(path=".")
с именем external_files .Последний шаг - изменить строку кода ниже в
в
Изменить: Если вы используете намерение, чтобы система открыла ваш файл, вам может потребоваться добавить следующую строку кода:
Пожалуйста, обратитесь, полный код и решение было объяснено здесь.
источник
(Build.VERSION.SDK_INT > M)
состояние бесполезно.FileProvider
следует расширять, только если вы хотите переопределить любое поведение по умолчанию, в противном случае используйтеandroid:name="android.support.v4.content.FileProvider"
. См. Developer.android.com/reference/android/support/v4/content/…Помимо решения с использованием
FileProvider
, есть еще один способ обойти это. Проще говоряв
Application.onCreate()
. Таким образом, виртуальная машина игнорируетURI
экспозицию файла .метод
включает проверку экспозиции файла, что также является поведением по умолчанию, если мы не настроили VmPolicy.
Я столкнулся с проблемой, что если я использую
content://
URI
для отправки что-то, некоторые приложения просто не могут этого понять. И понижениеtarget SDK
версии не допускается. В этом случае мое решение полезно.Обновить:
Как упомянуто в комментарии, StrictMode является диагностическим инструментом и не должен использоваться для этой проблемы. Когда я опубликовал этот ответ год назад, многие приложения могут получать только файлы Uris. Они просто вылетали, когда я пытался отправить им FileProvider uri. Сейчас это исправлено в большинстве приложений, поэтому мы должны использовать решение FileProvider.
источник
VmPolicy
.StrictMode.enableDefaults();
, который я запускаю только в своих сборках разработки, предотвращает этот сбой - так что теперь у меня есть производственное приложение, которое вылетает, но не вылетает в процессе разработки. Таким образом, включение диагностического инструмента здесь скрывает серьезную проблему. Спасибо, @hqzxzwb за помощь в разъяснении этого.Если значение
targetSdkVersion
больше 24 , то FileProvider используется для предоставления доступа.Создайте файл XML (путь: res \ xml) provider_paths.xml
Добавить провайдера в AndroidManifest.xml
Если вы используете androidx , путь FileProvider должен быть:
и заменить
в
Изменить: пока вы включаете URI с
Intent
добавлением строки ниже:и ты в порядке. Надеюсь, поможет.
источник
Если ваше приложение предназначено для API 24+, и вы все еще хотите / должны использовать file: // намерения, вы можете использовать хакерский способ отключить проверку во время выполнения:
Метод
StrictMode.disableDeathOnFileUriExposure
скрыт и документирован как:Проблема заключается в том, что мое приложение не хромое, а скорее не хочет наносить вред при использовании контента: // намерения, которые не понятны многим приложениям. Например, открытие mp3-файла со схемой content: // предлагает гораздо меньше приложений, чем при открытии того же поверх схемы file: //. Я не хочу платить за ошибки в дизайне Google, ограничивая функциональность моего приложения.
Google хочет, чтобы разработчики использовали схему контента, но система не готова к этому, поскольку приложения создавались годами для использования файлов, а не «контента», файлы можно редактировать и сохранять обратно, а файлы, обслуживаемые по схеме контента, не могут (могут Они?).
источник
ContentResolver
имеет обаopenInputStream()
иopenOutputStream()
. Менее хакерский способ сделать это - просто настроить правила виртуальной машины самостоятельно и не включатьfile
Uri
правило.Если у вас
targetSdkVersion
24 или выше, вы не можете использоватьfile:
Uri
значенияIntents
на устройствах Android 7.0+ .Ваш выбор:
Сбросьте
targetSdkVersion
до 23 или ниже, илиПоместите свой контент во внутреннее хранилище, а затем используйте его,
FileProvider
чтобы сделать его выборочно доступным для других приложений.Например:
(из этого примера проекта )
источник
/system
разделе? Каждое приложение должно иметь доступ к этому разделу без рута./system
станет читабельным. При этом, я предполагаю, что вы все равно получите это исключение. Я подозреваю, что они просто проверяют схему и не пытаются определить, действительно ли файл доступен для чтения. ТемFileProvider
не менее, это не поможет вам, так как вы не можете научить его служить/system
. Вы можете создать собственную стратегию для меняStreamProvider
или накатить свою собственнуюContentProvider
, чтобы обойти проблему./data
,/system
), из-за этого "хорошего изменения".Сначала вам нужно добавить провайдера в ваш AndroidManifest
Теперь создайте файл в папке ресурсов xml (если вы используете Android Studio, вы можете нажать Alt + Enter после выделения file_paths и выбрать вариант создания ресурса xml).
Далее в файле file_paths введите
Этот пример для внешнего пути вы можете сослаться здесь для получения дополнительной информации. Это позволит вам обмениваться файлами, которые находятся в этой папке и ее подпапке.
Теперь осталось создать намерение следующим образом:
РЕДАКТИРОВАТЬ : я добавил корневую папку SD-карты в file_paths. Я проверил этот код, и он работает.
источник
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
Кроме того, я рекомендую всем, кто ищет ответы, сначала прочитать FileProvider и понять, с чем вы имеете дело здесь с правами доступа к файлам в Android N и выше. Существуют варианты для внутреннего хранилища и внешнего хранилища, а также для обычного пути к файлу и пути кеша.java.lang.IllegalArgumentException: Failed to find configured root ...
и единственное, что сработало, было<files-path path="." name="files_root" />
вместо файла XML<external-path ...
. Мой файл был сохранен во внутреннем хранилище.@palash k ответ правильный и работал для файлов внутреннего хранилища, но в моем случае я хочу открыть файлы и из внешнего хранилища, мое приложение зависло при открытии файла из внешнего хранилища, такого как sdcard и usb, но мне удается решить проблему, изменив provider_paths.xml из принятого ответа
измените provider_paths.xml, как показано ниже
и в классе Java (без изменений, как принятый ответ, только небольшое изменение)
Это поможет мне исправить сбой файлов с внешних хранилищ. Надеюсь, это поможет кому-то, у кого возникла та же проблема, что и у меня :)
источник
<root-path
пожалуйста? Работает.<external-path path="Android/data/${applicationId}/" name="files_root" />
не имел никакого эффекта для открытых файлов из внешнего хранилища.Android/data/${applicationId}/
в SDcard.Мое решение было «Uri.parse» путь к файлу в виде строки, а не с помощью Uri.fromFile ().
Кажется, что fromFile () использует указатель файла, который, я полагаю, может быть небезопасным, когда адреса памяти открыты для всех приложений. Но путь к файлу String никогда никому не причиняет вреда, поэтому он работает без исключения FileUriExposedException.
Проверено на уровнях API от 9 до 27! Успешно открывает текстовый файл для редактирования в другом приложении. Не требует ни FileProvider, ни библиотеки поддержки Android.
источник
Просто вставьте приведенный ниже код в активность onCreate ()
Это будет игнорировать воздействие URI
источник
Просто вставьте приведенный ниже код в активность
onCreate()
.Он будет игнорировать воздействие URI.
Удачного кодирования :-)
источник
Использование fileProvider - путь. Но вы можете использовать этот простой обходной путь:
заменить:
по
источник
Я использовал ответ Палаша, приведенный выше, но он был несколько неполным, я должен был дать такое разрешение
источник
Просто вставьте приведенный ниже код в активность onCreate ()
Это будет игнорировать воздействие URI
источник
добавить эти две строки в onCreate
Поделиться методом
источник
Вот мое решение:
в Manifest.xml
в res / xml / provider_paths.xml
в моем фрагменте у меня есть следующий код:
Это все, что тебе нужно.
Также не нужно создавать
Я тестирую на Android 5.0, 6.0 и Android 9.0, и это успешно работает.
источник
Для загрузки pdf с сервера добавьте приведенный ниже код в свой класс обслуживания. Надеюсь, это полезно для вас.
И да, не забудьте добавить разрешения и провайдера в манифест.
источник
@xml/provider_paths
?Я не знаю почему, я сделал все точно так же, как Pkosta ( https://stackoverflow.com/a/38858040 ), но продолжал получать ошибку:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
Я потратил часы на этот вопрос. Виновник? Котлин.
intent
на самом деле настройкиgetIntent().addFlags
вместо того, чтобы работать на моем недавно объявленном playIntent.источник
Я поставил этот метод, чтобы путь imageuri легко попасть в контент.
источник
Здесь есть 3 основных шага, как указано ниже
Шаг 1: Манифестная запись
Шаг 2. Создайте файл XML res / xml / provider_paths.xml
Шаг 3: Изменения кода
источник
Я знаю, что это довольно старый вопрос, но этот ответ для будущих зрителей. Итак, я столкнулся с подобной проблемой, и после исследования я нашел альтернативу этому подходу.
Ваше намерение здесь, например: для просмотра изображения с вашего пути в Kotlin
Основная функция ниже
Аналогично, вместо изображения вы можете использовать любой другой формат файла, например, pdf, и в моем случае он работал просто отлично.
источник
Я провел почти день, пытаясь понять, почему я получаю это исключение. После долгой борьбы этот конфиг работал отлично ( Kotlin ):
AndroidManifest.xml
file_paths.xml
Сам намерение
Я объясняю весь процесс здесь .
источник
https://stackoverflow.com/a/38858040/395097 этот ответ завершен.
Ответ на этот вопрос - у вас уже есть приложение с таргетингом ниже 24, и теперь вы переходите на targetSDKVersion> = 24.
В Android N изменяется только файл, доступный стороннему приложению. (Не так, как раньше). Поэтому меняйте только те места, где вы делите путь, с помощью стороннего приложения (камера в моем случае)
В нашем приложении мы отправляли Uri в приложение Camera, в этом месте мы ожидаем, что приложение Camera сохранит захваченное изображение.
Теперь у нас есть 2 разных URI для одного файла. # 1 используется совместно с приложением Camera. Если цель камеры - успех, мы можем получить доступ к изображению из # 2.
Надеюсь это поможет.
источник
Xamarin.Android
Примечание . Путь xml / provider_paths.xml (.axml) не может быть разрешен даже после создания папки xml в разделе « Ресурсы» (возможно, его можно поместить в существующее расположение, например « Значения» , не пытаясь), поэтому я прибег к это работает на данный момент. Тестирование показало, что его нужно вызывать только один раз за запуск приложения (что имеет смысл, поскольку оно меняет рабочее состояние виртуальной машины хоста).
Примечание: XML должен быть написан с большой буквы, поэтому Resources / Xml / provider_paths.xml
источник
Ответ @Pkosta - один из способов сделать это.
Помимо использования
FileProvider
, вы также можете вставить файлMediaStore
(особенно для файлов изображений и видео), потому что файлы в MediaStore доступны для каждого приложения:Например, вы можете вставить видеофайл в MediaStore следующим образом:
contentUri
это какcontent://media/external/video/media/183473
, который может быть передан непосредственно вIntent.putExtra
:Это работает для меня, и избавить от хлопот использования
FileProvider
.источник
Просто позвольте ему игнорировать URI Exposure ... Добавьте его после создания
источник
Попробуйте это решение
ОСТАВЬТЕ ЭТИ РАЗРЕШЕНИЯ В МАНИФЕСТ
Намерение захватить изображение
ПОЛУЧИТЬ ИЗОБРАЖЕНИЕ В ONACTIVITYRESULT
СПОСОБ ПОЛУЧЕНИЯ URI ИЗОБРАЖЕНИЯ
источник
В моем случае я избавился от исключения, заменив его
SetDataAndType
простоSetData
.источник