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;
}
JonathanNet
la source

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>
Brendon
la source
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.

eranda.del
la source
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"
Hemraj Patel
la source
Il est préférable d'expliquer la configuration du fournisseur dans AndroidManifest plutôt que de donner un autre code.
fury.slay