Фон
У меня есть библиотека, основная функция которой заключается в совместном использовании программно снятых снимков экрана с внешними почтовыми приложениями.
Для этого я использую 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
вызывает PackageManager.resolveContentProvider
со строкой полномочий "${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider"
. resolveContentProvider
затем возвращает ноль, что приводит к этому NPE.
Если я вручную вызову resolveContentProvider
во время паузы в этой инструкции и передам либо "${applicationId}.fileprovider"
, либо "${applicationId}.bugshaker.fileprovider"
, resolveContentProvider
вместо этого вернет ненулевой экземпляр ProviderInfo
(который, как представляется, является ожидаемым результатом).
Это различие сбивает меня с толку, потому что
документация по элементу <provider>
element documentation гласит, что поддерживается несколько прав доступа:
Список одного или нескольких полномочий URI, которые идентифицируют данные, предлагаемые поставщиком контента. Несколько авторитетных источников перечисляются путем разделения их названий точкой с запятой. Чтобы избежать конфликтов, имена авторитетов должны использовать соглашение об именах в стиле Java (например, com.example.provider.cartoonprovider). Как правило, это имя подкласса ContentProvider, которое реализует поставщик
Там нет по умолчанию. Должен быть указан как минимум один орган.
Вопросы
- Возможно ли, чтобы одно приложение выставляло
FileProvider
с несколькими правами доступа и путями к файлам?- Если да, что мне нужно изменить, чтобы это работало?
- Если нет, есть ли другие способы настроить общий доступ к файлам в моей библиотеке, чтобы избежать конфликтов, таких как этот?