Can I use multiple permissions with FileProvider?

Background

I have a library whose main function is to share software-captured screenshots with external email applications.

For this, I use FileProvider , which means that my library manifest contains the <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 defined as follows:

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

A user of my library has an application that itself uses FileProvider to exchange files. I expected both providers to be able to share files if the consumer application uses the following manifest <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> 

This manifest entry is:

  • specifies two Provider bodies, ${applicationId}.fileprovider (for sharing the application files) and ${applicationId}.bugshaker.fileprovider (for sharing the library files);
  • refers to the updated filepaths.xml , which contains separate directory definitions for files generated by the application and files generated by the library:
 <paths> <external-path name="redacted" path="" /> <files-path name="bug-reports" path="bug-reports/" /> </paths> 

After creating the application, we confirmed that the correct nodes with these updated values ​​were replaced in the generated manifest.

However, when an application using this configuration is compiled (successfully) and launched, we see a crash on startup:

 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) 

Using the debugger, I see that the FileProvider.parsePathStrategy method calls PackageManager.resolveContentProvider with the permission string "${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider" . resolveContentProvider then returns zero, which results in this NPE.

If I manually call resolveContentProvider during a pause in this statement and pass either "${applicationId}.fileprovider" or "${applicationId}.bugshaker.fileprovider" , resolveContentProvider instead return a non-zero instance of ProviderInfo (which seems to be expected result). This difference baffles me because

The documentation for the <provider> element documentation states that several permissions are supported:

A list of one or more URI credentials that identify data offered by the content provider. Several authoritative sources are listed by separating their names with a semicolon. To avoid conflicts, authority names should use a Java-style naming convention (e.g. com.example.provider.cartoonprovider). Typically, this is the name of the ContentProvider subclass that the provider implements.

There is no default. At least one authority must be indicated.

Questions

  • Is it possible for one application to expose FileProvider with multiple access rights and file paths?
    • If so, what do I need to change for this to work?
    • If not, are there other ways to set up file sharing in my library to avoid conflicts like this?
+33
android android-contentprovider android-manifest
Apr 03 '17 at 0:37
source share
2 answers

My solution to this problem actually was to not rely on a single FileProvider parse multiple authorities. Although this does not directly concern the issue, I am posting it for future generations.




I updated my library to use an empty subclass of FileProvider , so the manifest provider is now updated in the library:

 <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> 

The unified application manifest, which (1) uses the FileProvider stock and (2) uses my library, will now contain both entries shown below (no collisions!):

 <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> 

I did not realize that this was a potential solution until my colleague pointed it out. My assumption previously (and incorrectly) was that all FileProvider in the manifest should set

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

but a quick check of the documentation showed my error:

The name of the class that the content provider implements, a subclass of ContentProvider. This must be the fully qualified name of the class (for example, "com.example.project.TransproductionProvider"). [...]

+33
Apr 17 '17 at 1:59 on
source share

I also run into this problem and use this approach to solve it. as if I have a library image picker that uses a file provider, and also my application uses a file provider when I create a conflict between applications.

my file

 <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> 

change it to

 <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> 
0
Feb 15 '18 at 12:54
source share



All Articles