Intereting Posts
BitmapFactory OOM заставляет меня гайки Уведомление о стилизации InboxStyle Как использовать Notification.deleteIntent ListView: setItemChecked работает только со стандартным ArrayAdapter – НЕ работает при использовании настраиваемого ArrayAdapter? Интеграция Google кошелька в приложение для Android Есть ли способ сделать номер телефона кликабельным на iphone или Android-телефоне, чтобы позвонить в HTML? Установить фокус активности в теме, используя стиль? Что такое onPrepareOptionsMenu? Отключение сна при определенной активности Как я могу изменить MenuItem в меню опций на Android? Могу ли я написать приложение в javascript / HTML / CSS и продать его в магазине приложений, в Google Play и в магазине мобильных приложений для Microsoft? Как сохранить GPS-координаты в данных exif на Android? Добавить индикатор загрузки / индикатор выполнения в экран заставки Android Phonegap Android Webview multitouch touchstart не работает с более чем двумя пальцами Уровень API Android <19 и «попытка использования автоматического управления ресурсами»

Можно использовать несколько полномочий с помощью FileProvider?

Задний план

Я поддерживаю библиотеку , основная функциональность которой заключается в совместном использовании программно захваченных скриншотов для внешних почтовых приложений.

Я использую FileProvider для выполнения этого, что означает, что манифест моей библиотеки содержит <provider> :

 <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> 

filepaths.xml определяется следующим образом:

 <paths> <files-path path="bug-reports/" name="bug-reports" /> </paths> 

У потребителя моей библиотеки есть приложение, которое самостоятельно использует FileProvider для обмена файлами. Мое предположение заключалось в том, что должно быть возможно разрешить обоим провайдерам обмениваться файлами, если прикладное приложение использует следующий манифест <provider> :

 <provider android:authorities="${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="android.support.v4.content.FileProvider" tools:replace="android:authorities"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" tools:replace="android:resource" /> </provider> 

Эта манифестация:

  • Указывает два Provider , ${applicationId}.fileprovider (для совместного использования файлов приложений) и ${applicationId}.bugshaker.fileprovider (для совместного использования файлов);
  • Ссылается на обновленный filepaths.xml , который содержит отдельные определения каталогов для файлов, созданных приложением, и файлы, созданные библиотекой:
 <paths> <external-path name="redacted" path="" /> <files-path name="bug-reports" path="bug-reports/" /> </paths> 

После создания приложения мы подтвердили, что сгенерированный манифест заменил правильные узлы этими обновленными значениями.

Однако, когда приложение, использующее эту конфигурацию, собирается (успешно) и запускается, мы видим крах при запуске:

 E: FATAL EXCEPTION: main Process: com.stkent.bugshakertest, PID: 11636 java.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference at android.app.ActivityThread.installProvider(ActivityThread.java:5856) at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384) at android.app.ActivityThread.-wrap2(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:583) at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:557) at android.support.v4.content.FileProvider.attachInfo(FileProvider.java:375) at android.app.ActivityThread.installProvider(ActivityThread.java:5853) at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384) at android.app.ActivityThread.-wrap2(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Используя отладчик, я могу видеть, что метод FileProvider.parsePathStrategy вызывает FileProvider.parsePathStrategy с строкой полномочий "${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider" . resolveContentProvider затем возвращает null, что приводит к этому NPE.

Если я вручную вызову resolveContentProvider , приостановив эту инструкцию и "${applicationId}.fileprovider" или "${applicationId}.bugshaker.fileprovider" , resolveContentProvider вместо этого возвращает ненулевой экземпляр ProviderInfo (который, казалось бы, был ожидаемым результат).

Эта разница меня смущает, потому что в документации элемента <provider> указано, что поддерживаются несколько полномочий:

Список одного или нескольких органов URI, которые идентифицируют данные, предлагаемые поставщиком контента. Несколько полномочий перечислены путем разделения их имен точкой с запятой. Чтобы избежать конфликтов, имена полномочий должны использовать соглашение об именах в стиле Java (например, com.example.provider.cartoonprovider). Как правило, это имя подкласса ContentProvider, который реализует поставщика

По умолчанию нет. Необходимо указать хотя бы один орган.

Вопросов

  • Возможно ли, чтобы одно приложение обнаружило FileProvider с несколькими полномочиями и файловыми путями?
    • Если да, то что мне нужно изменить, чтобы сделать эту работу?
    • Если нет, существуют ли другие способы настройки совместного использования файлов в моей библиотеке, чтобы избежать конфликтов, таких как этот?

Поддерживающие ссылки

  • Оригинальная проблема GitHub
  • Пример приложения, демонстрирующий крах при запуске

Solutions Collecting From Web of "Можно использовать несколько полномочий с помощью FileProvider?"

Мое решение этой проблемы состояло в том, чтобы не полагаться на то, что один FileProvider анализирует несколько полномочий. Хотя это прямо не затрагивает вопрос, как указано, я отправляю его для потомков.


Я обновил свою библиотеку, чтобы использовать пустой подкласс FileProvider , так что теперь обновленная запись поставщика манифеста библиотеки теперь:

 <provider android:name=".flow.email.screenshot.BugShakerFileProvider" android:authorities="${applicationId}.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/library_file_paths" /> </provider> 

Объединенный манифест приложения, в котором (1) использует FileProvider и (2), потребляет мою библиотеку, теперь будет содержать обе записи, показанные ниже (без столкновения!):

 <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.consuming.application.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/application_file_paths" /> </provider> <provider android:name="com.github.stkent.bugshaker.flow.email.screenshot.BugShakerFileProvider" android:authorities="com.consuming.application.bugshaker.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/library_file_paths" /> </provider> 

Я не понимал, что это было потенциальное решение, пока коллега не указал на это! Мое предположение ранее (и неправильно) заключалось в том, что все FileProvider s в манифесте должны установить

 android:name="android.support.v4.content.FileProvider" 

Но быстрая проверка документации показала мою ошибку:

Имя класса, реализующего поставщика контента, подкласс ContentProvider. Это должно быть полное имя класса (например, «com.example.project.TransportationProvider»). […]