web-dev-qa-db-fra.com

FileProvider ne fonctionne pas avec l'appareil photo

J'essaie de faire Camera App pour stocker la sortie sur ma mémoire interne. Je comprends également que les applications tierces ne peuvent pas accéder au stockage interne de mon application [~ # ~] mais [~ # ~] nous pouvons pour ce faire, en exposant le répertoire interne via FileProvider. J'ai suivi le guide ici:

Je précise mon AndroidManifest.xml de la manière suivante:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="com.stackoverflow.test.camerawithfileprovider" >

    <application>
        <activity
            ...
        </activity>

        <provider
            Android:name="Android.support.v4.content.FileProvider"
            Android:authorities="com.stackoverflow.test.camerawithfileprovider.fileprovider"
            Android:exported="false"
            Android:grantUriPermissions="true" >
            <meta-data
                Android:name="Android.support.FILE_PROVIDER_PATHS"
                Android:resource="@xml/file_provider_path" />
        </provider>
    </application>

</manifest>

J'ai créé un fichier xml nommé file_provider_path.xml dans /res/xml/:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <files-path name="image_capture" path="public/" />
</paths>

Voici comment je crée et appelle l'intention de la caméra:

private static final int CAMERA_REQUEST_CODE = 5000;
private static final String CAMERA_FP_AUTHORITY = "com.stackoverflow.test.camerawithfileprovider.fileprovider";

Intent intent = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);

Context context = MainActivity.this;
File imagePath = new File(context.getFilesDir(), "public");
if (!imagePath.exists()) imagePath.mkdirs();
File newFile = new File(imagePath, "tmp.jpg");

Uri imageUri = FileProvider.getUriForFile(context, CAMERA_FP_AUTHORITY, newFile);
//context.grantUriPermission("com.google.Android.GoogleCamera", imageUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d("YouQi", "Image URI Passing to Camera: " + imageUri.toString());

intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CAMERA_REQUEST_CODE);

Lorsque j'exécute l'application, je peux obtenir le résultat Logcat ci-dessous:

    11-11 20:07:39.581 18303-18303/com.stackoverflow.test.camerawithfileprovider D/YouQi: Image URI Passing to Camera: content://com.stackoverflow.test.camerawithfileprovider.fileprovider/image_capture/tmp.jpg

Juste au moment où la caméra se ferme, j'ai frappé l'exception ci-dessous:

com.google.Android.GoogleCamera E/AndroidRuntime: FATAL EXCEPTION: main
com.google.Android.GoogleCamera E/AndroidRuntime: Process: com.google.Android.GoogleCamera, PID: 19420
com.google.Android.GoogleCamera E/AndroidRuntime: Java.lang.SecurityException: Permission Denial: opening provider Android.support.v4.content.FileProvider from ProcessRecord{42e44f70 19420:com.google.Android.GoogleCamera/u0a83} (pid=19420, uid=10083) that is not exported from uid 10312
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.os.Parcel.readException(Parcel.Java:1465)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.os.Parcel.readException(Parcel.Java:1419)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.Java:2882)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.app.ActivityThread.acquireProvider(ActivityThread.Java:4544)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.Java:2274)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.content.ContentResolver.acquireUnstableProvider(ContentResolver.Java:1425)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.Java:906)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.content.ContentResolver.openOutputStream(ContentResolver.Java:669)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.content.ContentResolver.openOutputStream(ContentResolver.Java:645)
com.google.Android.GoogleCamera E/AndroidRuntime:     at com.Android.camera.PhotoModule.onCaptureDone(PhotoModule.Java:1281)
com.google.Android.GoogleCamera E/AndroidRuntime:     at com.Android.camera.PhotoModule$8.onClick(PhotoModule.Java:593)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.view.View.performClick(View.Java:4445)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.view.View$PerformClick.run(View.Java:18446)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.os.Handler.handleCallback(Handler.Java:733)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.os.Handler.dispatchMessage(Handler.Java:95)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.os.Looper.loop(Looper.Java:136)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Android.app.ActivityThread.main(ActivityThread.Java:5146)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Java.lang.reflect.Method.invokeNative(Native Method)
com.google.Android.GoogleCamera E/AndroidRuntime:     at Java.lang.reflect.Method.invoke(Method.Java:515)
com.google.Android.GoogleCamera E/AndroidRuntime:     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:732)
com.google.Android.GoogleCamera E/AndroidRuntime:     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:566)
com.google.Android.GoogleCamera E/AndroidRuntime:     at dalvik.system.NativeStart.main(Native Method)

Quelqu'un peut-il aider à expliquer pourquoi le problème se produit? J'ai créé un exemple de projet de mon problème: http://www.axzae.com/downloads/CameraWithFileProvider.Zip

Quoi qu'il en soit, l'application fonctionnera si je spécifie explicitement:

context.grantUriPermission(
    "com.google.Android.GoogleCamera",
    imageUri,
    Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION
);

Mais cela ne fonctionnera que pour les appareils Nexus/Cyanogen. L'application Appareil photo Samsung peut utiliser un nom de package différent.

45
You Qi
  1. N'essayez pas de mettre exported="true" comme indiqué par pskink, votre application se bloque au moment du chargement. FileProvider n'est pas censé fonctionner dans cet état.

  2. A tenté intent.addFlags solution par CommonsWare. Ne fonctionne pas. ne fonctionnera probablement qu'avec ACTION_SEND sorte d'intention.

  3. J'ai trouvé la réponse dans cet article . Apparemment, le mode d'octroi manuel est la seule solution. Mais nous pouvons toujours parcourir la liste des packages candidats et accorder une autorisation à chacun d'eux.

    List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    for (ResolveInfo resolveInfo : resInfoList) {
        String packageName = resolveInfo.activityInfo.packageName;
        context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
    
106
You Qi

J'ai eu un problème similaire mais plus tard, je découvre qu'il y a une faute de frappe dans mon code. La faute de frappe était dans AndroidManifest.xml, précisément dans la balise à la ligne "autorités".

Pour moi,

Android:authorities="com.stackoverflow.test.camerawithfileprovider.fileprovider"

ne fonctionne pas (lorsque j'appelle l'instance de la caméra, l'application se bloque) mais si je supprime "fichier" et remplace cette chaîne comme suit:

Android:authorities="com.stackoverflow.test.camerawithfileprovider.provider"

mon application fonctionne correctement (l'application prend la photo, la stocke et donne un aperçu de l'activité dans l'application cliente).

Votre application a-t-elle également le même problème?

0