161 votes

Comment utiliser le support FileProvider pour partager du contenu avec d'autres applications ?

Je cherche un moyen de partager correctement (et non d'OUVRIR) un fichier interne avec une application externe en utilisant la bibliothèque de support Android. Fournisseur de fichiers .

En suivant l'exemple de la documentation,

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.android.supportv4.my_files"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/my_paths" />
</provider>

et utiliser ShareCompat pour partager un fichier avec d'autres applications comme suit :

ShareCompat.IntentBuilder.from(activity)
.setStream(uri) // uri from FileProvider
.setType("text/html")
.getIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

ne fonctionne pas, car le FLAG_GRANT_READ_URI_PERMISSION n'accorde l'autorisation que pour l'Uri spécifié dans le champ data de l'intention, et non de la valeur de la EXTRA_STREAM supplémentaire (comme cela a été fixé par setStream ).

J'ai essayé de compromettre la sécurité en mettant android:exported a true pour le fournisseur, mais FileProvider vérifie en interne si elle est exportée. Si c'est le cas, elle lève une exception.

8 votes

+1 ceci semble être une question vraiment originale - il y a rien sur Google ou StackOverflow d'après ce que j'ai pu voir.

0 votes

Voici un post pour mettre en place une configuration de base de FileProvider en utilisant un projet d'exemple minimal sur Github : stackoverflow.com/a/48103567/2162226 . Il indique les étapes à suivre pour copier les fichiers (sans les modifier) dans un projet local autonome.

9voto

Dans mon application, FileProvider fonctionne parfaitement, et je suis en mesure de joindre des fichiers internes stockés dans le répertoire des fichiers à des clients de messagerie comme Gmail, Yahoo, etc.

Dans mon manifeste, comme indiqué dans la documentation Android, j'ai placé :

<provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.package.name.fileprovider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/filepaths" />
    </provider>

Et comme mes fichiers étaient stockés dans le répertoire Root files, les filepaths.xml étaient les suivants :

 <paths>
<files-path path="." name="name" />

Maintenant dans le code :

 File file=new File(context.getFilesDir(),"test.txt");

 Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND_MULTIPLE);

 shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
                                     "Test");

 shareIntent.setType("text/plain");

 shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL,
                                 new String[] {"email-address you want to send the file to"});

   Uri uri = FileProvider.getUriForFile(context,"com.package.name.fileprovider",
                                                   file);

                ArrayList<Uri> uris = new ArrayList<Uri>();
                uris.add(uri);

                shareIntent .putParcelableArrayListExtra(Intent.EXTRA_STREAM,
                                                        uris);

                try {
                   context.startActivity(Intent.createChooser(shareIntent , "Email:").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));                                                      

                }
                catch(ActivityNotFoundException e) {
                    Toast.makeText(context,
                                   "Sorry No email Application was found",
                                   Toast.LENGTH_SHORT).show();
                }
            }

Cela a marché pour moi. J'espère que cela vous aidera :)

1 votes

Vous êtes un vrai MVP pour avoir affiché paths="." Ça a marché pour moi.

0 votes

J'obtiens une erreur comme "Failed to find configured Root that contains /" J'ai utilisé le même code.

6voto

CoolMind Points 11

Si vous obtenez une image à partir de la caméra, aucune de ces solutions ne fonctionne pour Android 4.4. Dans ce cas, il est préférable de vérifier les versions.

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getContext().getPackageManager()) != null) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        uri = Uri.fromFile(file);
    } else {
        uri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".provider", file);
    }
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(intent, CAMERA_REQUEST);
}

1voto

Deepak Singh Points 51

Juste pour améliorer la réponse donnée ci-dessus : si vous obtenez NullPointerEx :

vous pouvez également utiliser getApplicationContext() sans contexte

                List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);
                for (ResolveInfo resolveInfo : resInfoList) {
                    String packageName = resolveInfo.activityInfo.packageName;
                    grantUriPermission(packageName, photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }

1voto

Eric Draven Points 219

Je veux partager quelque chose qui nous a bloqué pendant quelques jours : le code du fileprovider. MUST doit être inséré entre les balises de l'application, et non après. C'est peut-être trivial, mais ce n'est jamais précisé, et j'ai pensé que j'aurais pu aider quelqu'un ! (merci encore à piolo94)

1voto

Phan Van Linh Points 16963

grantUriPermission (extrait du document Android)

Normalement, vous devriez utiliser Intent#FLAG_GRANT_READ_URI_PERMISSION ou Intent#FLAG_GRANT_WRITE_URI_PERMISSION avec l'Intent utilisé pour démarrer une activité au lieu de cette fonction directement. Si vous utilisez cette fonction directement, vous devez vous assurer d'appeler revokeUriPermission(Uri, int) lorsque la cible ne doit plus être autorisée à y accéder.

Donc je teste et je vois ça.

  • Si nous utilisons grantUriPermission avant de commencer une nouvelle activité, nous N'ont pas besoin FLAG_GRANT_READ_URI_PERMISSION o FLAG_GRANT_WRITE_URI_PERMISSION sur Intent pour surmonter SecurityException

  • Si nous n'utilisez pas grantUriPermission . Nous devons utiliser FLAG_GRANT_READ_URI_PERMISSION o FLAG_GRANT_WRITE_URI_PERMISSION pour surmonter SecurityException mais

    • Votre intention MUST contiennent Uri par setData o setDataAndType sinon SecurityException encore jeter . (un intéressant je vois : setData y setType ne peuvent pas fonctionner ensemble, donc si vous avez besoin des deux Uri y type vous avez besoin setDataAndType . Vous pouvez vérifier à l'intérieur Intent actuellement, lorsque vous setType il définira également uri= null et lorsque vous définissez Uri il définira également type=null)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X