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?