Possible d'utiliser de multiples autorités FileProvider?

Fond

Je maintenir un bibliothèque dont la fonctionnalité principale est le partage de la par programme-captures d'écran à l'externe des applications de messagerie électronique.

- Je utiliser un FileProvider pour ce faire, ce qui signifie que ma bibliothèque est manifeste contient un <fournisseur> de la balise:

<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 est définie comme suit:

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

Un consommateur de ma bibliothèque dispose d'une application qui utilise elle-même un FileProvider pour partager des fichiers. Mon espoir était qu'il devrait être possible de permettre à la fois aux fournisseurs de partager des fichiers si la demande de consommation utilisé le manifeste suivantes <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>

Ce manifeste entrée:

  • spécifie deux Provider autorités, ${applicationId}.fileprovider (pour l'application de partage de fichiers) et ${applicationId}.bugshaker.fileprovider (pour la bibliothèque de partage de fichiers);
  • fait référence à une mise à jour filepaths.xml, qui contient le répertoire distinct des définitions pour l'application des fichiers générés et de la bibliothèque des fichiers générés:
<paths>
    <external-path
        name="redacted"
        path="" />
    <files-path
        name="bug-reports"
        path="bug-reports/" />
</paths>

Après la construction de l'application, nous avons confirmé que le manifeste a eu la bonne nœuds remplacé avec ces valeurs mises à jour.

Toutefois, lorsque l'application en utilisant cette configuration est assemblé (avec succès) et de l'exécution, nous voyons un crash lors du lancement:

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) 

De l'utilisation du débogueur, je suis capable de voir que la méthode FileProvider.parsePathStrategy appelle PackageManager.resolveContentProvider avec l'autorité de la chaîne de "${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider". resolveContentProvider puis renvoie la valeur null, conduisant à ce NPE.

Si j'manuellement appel resolveContentProvider en pause à cette instruction, et passer "${applicationId}.fileprovider" ou "${applicationId}.bugshaker.fileprovider", resolveContentProvider au lieu de cela renvoie une valeur non nulle ProviderInfo instance (qui semble être le résultat attendu).

Cette différence me confond, car la <fournisseur> de l'élément de documentation stipule que plusieurs autorités sont pris en charge:

Une liste d'un ou plusieurs URI autorités à identifier les données offertes par le fournisseur de contenu. Plusieurs autorités sont répertoriés par la séparation de leurs noms par un point-virgule. Pour éviter les conflits, l'autorité de noms à utiliser un Java-style de la convention d'affectation de noms (comme com.exemple.fournisseur de.cartoonprovider). Généralement, c'est le nom de la ContentProvider sous-classe qui implémente le fournisseur

Il n'y a pas de valeur par défaut. Au moins une autorité doit être spécifié.

Questions

  • Est-il possible d'avoir une seule application exposer un FileProvider avec de multiples autorités et les chemins d'accès aux fichiers?
    • Si oui, que dois-je modifier pour faire ce travail?
    • Si non, existe-il d'autres façons de configurer le partage de fichiers au sein de ma bibliothèque que d'éviter les conflits comme celui-ci?

L'Appui Des Liens

  • "Je suis capable de voir que la méthode PackageItemInfo.loadXmlMetaData est invoqué avec l'autorité chaîne "${identificateur applicationid}.fileprovider;${identificateur applicationid}.bugshaker.fileprovider" -- vous ne fournissez pas de l'autorité de la chaîne de loadXmlMetaData(), et je ne vois pas que, dans le FileProvider code source. Une autorité est fourni à resolveContentProvider() sur la ligne précédente. C'est ce que tu veux dire? Si oui, ProviderInfo est de fournir le point-virgule-liste délimitée par des virgules, et FileProvider ne semble pas gérer ça.
  • Au-delà, en regardant le code dans FileProvider, il semblerait qu'ils ne sont pas de la manipulation de multiples autorité scénario. Ils ont des crochets pour avoir de chemin d'accès multiples stratégies de l'autorité, mais ils ne semblent jamais à analyser le point-virgule-liste délimitée par des virgules. Probablement pas été testé. Je code en mon StreamProvider qui ne parse la liste, mais je ne l'ai pas testé non plus. 🙁
  • Ok, mis à jour. Il semble étrange que parsePathStrategy récupère une nouvelle ProviderInfo exemple à tous lorsque l'on est à la attachInfo méthode qui l'appelle. Je vois que ContentProvider ne séparent les autorités attachInfo et que FileProvider appels de super, mais les multiples autorités champ à l'intérieur de ContentProvider ne semble pas être accessible à des sous-classes à tous.
  • Peut-être une question de base, mais ce n'des applications qui nécessitent différents types de fournisseurs de contenu normalement dans le manifeste? Sont-ils nécessaires pour créer une "base" fournisseur de contenu et le délégué de manière appropriée?
  • Dernier commentaire pour la nuit; je vais tester StreamProvider dans mon exemple d'application au début de cette semaine et de faire un rapport...
  • "ce n'des applications qui nécessitent différents types de fournisseurs de contenu normalement dans le manifeste?" - habituellement, ils sont tout à fait différentes classes. Quelques bibliothèques livrées avec un ContentProvider; encore moins peut être nécessaire dans le béton (c'est à dire, inscrite dans le manifeste) par 2+ bibliothèques ou 1 autre de la bibliothèque et de l'application elle-même. Donc, je ne pense pas qu'il y est une "normalement". Dans ce cas, FileProvider (et StreamProvider) s'appuient sur un static cache de données pour gérer plusieurs autorités, et donc, juste à l'aide d'un simple sous-classe de FileProvider/StreamProvider serait insuffisant.
  • Lors de l'utilisation de la StreamProvider je reçois toujours un crash lors du lancement: Attempt to read from field 'android.os.Bundle android.content.pm.PackageItemInfo.metaData' on a null object reference. Des sons similaires.
  • De garder un oeil sur ce problème.

InformationsquelleAutor stkent | 2017-04-03