android 可以使用多个权限与FileProvider?

7gyucuyw  于 2023-09-29  发布在  Android
关注(0)|答案(2)|浏览(127)

后台

我维护一个library,其核心功能包括将编程捕获的屏幕截图共享给外部电子邮件应用程序。
我使用FileProvider来实现这一点,这意味着我的库的清单包含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>标记,则应该可以允许两个提供者共享文件:

<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使用权限字符串"${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider"调用PackageManager.resolveContentProvider。然后resolveContentProvider返回null,导致此NPE。
如果我手动调用resolveContentProvider,同时在此指令处暂停并传递"${applicationId}.fileprovider" * 或 * "${applicationId}.bugshaker.fileprovider",则resolveContentProvider返回非空的ProviderInfo示例(这似乎是预期的结果)。
这个区别让我很困惑,因为<provider> element documentation声明支持多个授权:
一个或多个URI授权机构的列表,用于标识由内容提供商提供的数据。列出多个授权机构,它们的名称之间用分号分隔。为了避免冲突,中心名称应该使用Java风格的命名约定(例如com.example.provider.cartoonprovider)。通常,它是实现提供程序的ContentProvider子类的名称
没有默认值。必须至少指定一个权限。

问题

  • 是否可以让一个应用程序公开一个具有多个权限和文件路径的FileProvider
  • 如果是这样,我需要做些什么改变才能实现这一目标?
  • 如果没有,是否有其他方法可以在我的库中配置文件共享,以避免像这样的冲突?
gopyfrb3

gopyfrb31#

我对这个问题的解决方案实际上是避免依赖于一个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必须设置

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

但是快速检查the documentation发现了我的错误:
实现内容提供程序的类的名称,它是ContentProvider的子类。这应该是一个完全限定的类名(如“com.example.project.TransportationProvider”)。[...]

x6492ojm

x6492ojm2#

我也面对这个问题,用这个方法来解决。就像我有一个库图像选择器,它使用文件提供程序,当我构建我的应用程序冲突时,我的应用程序也使用文件提供程序。
我提供的文件是

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="org.contentarcadeapps.photoeditor.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>

将其更改为

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="org.contentarcadeapps.photoeditor.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"
                tools:replace="android:resource"/>
        </provider>

相关问题