可以对FileProvider使用多个权限吗? [英] Possible to use multiple authorities with FileProvider?

查看:111
本文介绍了可以对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?
    • 如果是这样,我需要做出什么改变才能使它正常工作?
    • 如果没有,是否还有其他方法可以在我的库中配置文件共享,从而避免诸如此类的冲突?
    • Questions

      • 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 FileProviders in the manifest must set

          android: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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆