可以对FileProvider使用多个权限吗? [英] Possible to use multiple authorities with FileProvider?
问题描述
我维护了一个库,其核心功能涉及与外部电子邮件应用程序共享以编程方式捕获的屏幕截图.
I maintain a library whose core functionality involves sharing programmatically-captured screenshots to external email applications.
我使用FileProvider
完成此操作,这意味着我的库清单中包含
I use a FileProvider
to accomplish this, which means my library's manifest contains a <provider>
tag:
<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>
标记,应该允许两个提供者共享文件:
A consumer of my library has an application which itself uses a FileProvider
to share files. My expectation was that it should be possible to allow both providers to share files if the consuming application used the following manifest <provider>
tag:
<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
,其中包含应用程序生成的文件和库生成的文件的单独目录定义:
- specifies two
Provider
authorities,${applicationId}.fileprovider
(for application file sharing) and${applicationId}.bugshaker.fileprovider
(for library file sharing); - references an updated
filepaths.xml
, which contains separate directory definitions for application-generated files and library-generated files:
<paths>
<external-path
name="redacted"
path="" />
<files-path
name="bug-reports"
path="bug-reports/" />
</paths>
构建应用程序后,我们已经确认生成的清单已将正确的节点替换为这些更新的值.
After building the application, we have confirmed that the generated manifest has had the correct nodes replaced with these updated values.
但是,使用该配置的应用程序组装(成功)并运行时,我们会在启动时看到崩溃:
However, when the application using this configuration is assembled (successfully) and run, we see a crash on launch:
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
调用. resolveContentProvider
然后返回null,导致此NPE.
Using the debugger, I am able to see that the method FileProvider.parsePathStrategy
invokes PackageManager.resolveContentProvider
with the authority string "${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider"
. resolveContentProvider
then returns null, leading to this NPE.
如果我在此指令暂停时手动调用resolveContentProvider
并传递了"${applicationId}.fileprovider"
或 "${applicationId}.bugshaker.fileprovider"
,则resolveContentProvider
会返回一个非null的ProviderInfo
实例(这似乎达到预期的结果.
If I manually call resolveContentProvider
while paused at this instruction and pass either "${applicationId}.fileprovider"
or "${applicationId}.bugshaker.fileprovider"
, resolveContentProvider
instead returns a non-null ProviderInfo
instance (which would seem to be the expected result).
这种差异使我感到困惑,因为 <provider>
元素文档指出支持多个权限:
This difference confuses me because the <provider>
element documentation states that multiple authorities are supported:
标识内容提供商提供的数据的一个或多个URI授权的列表.通过使用分号分隔名称来列出多个权限.为避免冲突,授权机构名称应使用Java样式的命名约定(例如com.example.provider.cartoonprovider).通常,实现提供程序的是ContentProvider子类的名称
A list of one or more URI authorities that identify data offered by the content provider. Multiple authorities are listed by separating their names with a semicolon. To avoid conflicts, authority names should use a Java-style naming convention (such as com.example.provider.cartoonprovider). Typically, it's the name of the ContentProvider subclass that implements the provider
没有默认值.必须至少指定一个权限.
There is no default. At least one authority must be specified.
问题
- 是否可以使单个应用程序公开具有多个权限和文件路径的
FileProvider
?- 如果是这样,我需要做出什么改变才能使它正常工作?
- 如果没有,是否还有其他方法可以在我的库中配置文件共享,从而避免诸如此类的冲突?
- Is it possible to have a single application expose a
FileProvider
with multiple authorities and file paths?- If so, what do I need to change to make that work?
- If not, are there other ways to configure file sharing within my library that avoid conflicts such as this one?
推荐答案
我对此问题的解决方法实际上是避免依赖单个
FileProvider
解析多个权限.尽管这并不能直接解决上述问题,但我还是将其发布以供后代参考.My solution to this problem has actually been to avoid relying on a single
FileProvider
parsing multiple authorities. While this doesn't directly address the question as stated, I'm posting it for posterity.我更新了库以利用
FileProvider
的空子类,因此库的更新清单提供程序条目现在为:I updated my library to leverage an empty subclass of
FileProvider
, so that the library's updated manifest provider entry is now:<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)消耗了我的库的应用程序的合并清单现在将包含下面显示的两个条目(不冲突!):The merged manifest of an application that (1) uses a stock
FileProvider
and (2) consumes my library will now contain both of the entries shown below (no collision!):<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
必须设置I didn't realize that this was a potential solution until a coworker pointed it out. My assumption had previously (and incorrectly) been that all
FileProvider
s in the manifest must setandroid:name="android.support.v4.content.FileProvider"
但是对文档的快速检查发现了我的错误:
but a quick check of the documentation revealed my error:
实现内容提供程序的类的名称,它是ContentProvider的子类.这应该是完全合格的类名称(例如"com.example.project.TransportationProvider"). [...]
The name of the class that implements the content provider, a subclass of ContentProvider. This should be a fully qualified class name (such as, "com.example.project.TransportationProvider"). [...]
这篇关于可以对FileProvider使用多个权限吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
Questions