exposé au-delà de l'application via ClipData.Item.getUri


99

J'essaie de résoudre un problème après l'ajout de la nouvelle fonctionnalité dans le système de fichiers Android, mais j'obtiens cette erreur:

android.os.FileUriExposedException: file:///storage/emulated/0/MyApp/Camera_20180105_172234.jpg exposed beyond app through ClipData.Item.getUri()

J'espère donc que quelqu'un pourra m'aider à résoudre ce problème :)

Merci

private Uri getTempUri() {
    // Create an image file name
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    String dt = sdf.format(new Date());
    imageFile = null;
    imageFile = new File(Environment.getExternalStorageDirectory()
            + "/MyApp/", "Camera_" + dt + ".jpg");
    AppLog.Log(
            TAG,
            "New Camera Image Path:- "
                    + Environment.getExternalStorageDirectory()
                    + "/MyApp/" + "Camera_" + dt + ".jpg");
    File file = new File(Environment.getExternalStorageDirectory() + "/MyApp");
    if (!file.exists()) {
        file.mkdir();
    }
    imagePath = Environment.getExternalStorageDirectory() + "/MyApp/"
            + "Camera_" + dt + ".jpg";
    imageUri = Uri.fromFile(imageFile);
    return imageUri;
}

Réponses:


169

Pour SDK 24 et plus, si vous devez obtenir l'URI d'un fichier en dehors du stockage de votre application, vous rencontrez cette erreur.
Les solutions @ eranda.del vous permettent de modifier la politique pour permettre cela et cela fonctionne très bien.

Cependant, si vous souhaitez suivre les directives de Google sans avoir à modifier la politique d'API de votre application, vous devez utiliser un FileProvider.

Au début, pour obtenir l'URI d'un fichier, vous devez utiliser la méthode FileProvider.getUriForFile ():

Uri imageUri = FileProvider.getUriForFile(
            MainActivity.this,
            "com.example.homefolder.example.provider", //(use your app signature + ".provider" )
            imageFile);

Ensuite, vous devez configurer votre fournisseur dans votre manifeste Android:

<application>
  ...
     <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.homefolder.example.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <!-- ressource file to create -->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths">  
        </meta-data>
    </provider>
</application>

(Dans les "autorités", utilisez la même valeur que le deuxième argument de la méthode getUriForFile () (signature d'application + ".provider"))

Et enfin, vous devez créer le fichier de ressources: "file_paths". Ce fichier doit être créé dans le répertoire res / xml (vous devrez probablement créer ce répertoire également):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>

79
"Facilitez la vie des développeurs" - c'est le slogan de chaque nouvelle API, n'est-ce pas Google?
Kirill Karmazin

12
La solution fournie par Brendon est la bonne mais elle n'est pas prête pour le copier-coller, vous devez vérifier si elle répond à vos besoins, par exemple. <external-path ...est utilisé lorsque vous voulez Environment.getExternalStorageDirectory (). et utilisez <files-path ...si vous avez besoin de Context.getFilesDir (). Vous feriez mieux de vérifier d'abord les documents officiels: developer.android.com/reference/android/support/v4/content/…
Kirill Karmazin

9
Un rappel si vous utilisez androidx (nouvel espace de noms de support), vous pouvez trouver ici ( developer.android.com/reference/androidx/core/content/… ) la documentation appropriée.
Rodrirokr

20
Notez qu'il androidxandroid:name="androidx.core.content.FileProvider"
contient

150

Ajouter le bloc de code suivant avant de démarrer la navigation de la caméra ou des fichiers

    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());

Veuillez vous référer au mode strict du lien de parrainage et expliquer tous les détails techniques et d'utilisation.


24
Ce n'est pas la bonne façon de résoudre ce problème, cela supprimera fondamentalement les politiques de mode strict. et ignorera l'avertissement de sécurité
Ahsan Zaheer

Il y a des avantages et des inconvénients à ce sujet. Veuillez vous référer à ce qui suit pour obtenir plus d'informations stackoverflow.com/questions/18100161/…
eranda.del

Cela fonctionne, s'il y a un tirage au sort, veuillez me le faire savoir :)
Hanan

Le code a résolu l'exception pour moi. Cependant, le commentaire du haut ici indique que le code n'est pas la bonne façon de résoudre ce problème. Quelqu'un sait-il alors quelle serait la bonne méthode?
Shn_Android_Dev

Google déteste les programmeurs.
Joubert Vasconcelos

0

Aucune configuration de fournisseur requise dans AndroidManifest, seule l'autorisation de caméra et de stockage doit être autorisée. Utilisez le code suivant pour démarrer la caméra:

final int REQUEST_ACTION_CAMERA = 9;
void openCamra() {
Intent cameraImgIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

cameraImgIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID +".provider",
                new File("your_file_name_with_dir")));
startActivityForResult(cameraImgIntent, REQUEST_ACTION_CAMERA);
}

Après avoir capturé l'image, vous pouvez trouver votre image capturée dans:

"your_file_name_with_dir"

Il est préférable d'expliquer la configuration du fournisseur dans AndroidManifest plutôt que de donner un autre code.
fury.slay
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.