2017-07-28 1 views
1

J'ai regardé beaucoup, beaucoup SO postes à trouver une réponse, mais pas de chance ...android envoyer le fichier de stockage public par email

Comment puis-je envoyer un fichier de stockage public en tant que pièce jointe?

La plupart des postes demandent environ interne fichiers de stockage. Donc pour cela, ils utilisent FileProvider (ou quelque chose comme ça). Dans la documentation pour FileProvider, je lis:

... FileProvider facilite le partage sécurisé des fichiers associés à une application ...

Mais le fichier que je veux envoyer est pas associé à mon application . C'est un fichier .csv dans le stockage public dans le dossier Documents. Il semble donc vraiment bizarre pour mon application de configurer un FileProvider avec des autorisations d'accès pour un fichier public. Encore plus étrange d'utiliser mon nom de paquet comme "autorité".

J'ai essayé le code suivant, que je mis en place en fonction des réponses à 1 ou 2 autres postes:

File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS); 
File f = new File(path, _sFileName); 
_sFileDir = f.getCanonicalPath(); 

et dans une autre méthode que j'ai:

Intent i = new Intent(android.content.Intent.ACTION_SEND); 
String Email[] = { "[email protected]" }; 
i.putExtra(android.content.Intent.EXTRA_EMAIL, Email); 
i.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Report"); 
i.setType("plain/text"); 
String sURI = "file:/" + _sFileDir; 
i.putExtra(Intent.EXTRA_STREAM, Uri.parse(sURI)); 
startActivity(i); 

Cela provoque l'application à planter avec le message: "MyApp s'est arrêté"

Lorsque j'ai remplacé "fichier: /" par "contenu: /", l'application ne s'est plus écrasée et l'e-mail a été envoyé, mais aucun fichier n'a été joint.

Mon AndroidManifest.xml contient les autorisations suivantes:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

Voici mon LogCat à partir du moment où je l'utilise "contenu: /":

07-28 17:19:22.528 27809-27809/? I/art: Late-enabling -Xcheck:jni 
07-28 17:19:22.569 27809-27816/? E/art: Failed sending reply to debugger: Broken pipe 
07-28 17:19:22.569 27809-27816/? I/art: Debugger is no longer active 
07-28 17:19:22.569 27809-27816/? I/art: Starting a blocking GC Instrumentation 
07-28 17:19:22.582 27809-27809/? W/ActivityThread: Application com.myorg.myapp is waiting for the debugger on port 8100... 
07-28 17:19:22.583 27809-27809/? I/System.out: Sending WAIT chunk 
07-28 17:19:24.636 27809-27816/com.myorg.myapp I/art: Debugger is active 
07-28 17:19:24.785 27809-27809/com.myorg.myapp I/System.out: Debugger has connected 
07-28 17:19:24.785 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:24.985 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:25.186 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:25.386 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:25.588 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:25.788 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:25.989 27809-27809/com.myorg.myapp I/System.out: waiting for debugger to settle... 
07-28 17:19:26.189 27809-27809/com.myorg.myapp I/System.out: debugger has settled (1454) 
07-28 17:19:26.408 27809-27809/com.myorg.myapp W/System: ClassLoader referenced unknown path: /data/app/com.myorg.myapp-1/lib/arm 
07-28 17:19:26.444 27809-27809/com.myorg.myapp I/InstantRun: starting instant run server: is main process 
07-28 17:19:26.508 27809-27816/com.myorg.myapp I/art: Starting a blocking GC Instrumentation 
07-28 17:19:26.801 27809-27809/com.myorg.myapp W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable 
07-28 17:19:28.471 27809-27814/com.myorg.myapp I/art: Do partial code cache collection, code=14KB, data=23KB 
07-28 17:19:28.471 27809-27814/com.myorg.myapp I/art: After code cache collection, code=14KB, data=23KB 
07-28 17:19:28.471 27809-27814/com.myorg.myapp I/art: Increasing code cache capacity to 128KB 
07-28 17:19:28.475 27809-27814/com.myorg.myapp I/art: Do partial code cache collection, code=14KB, data=42KB 
07-28 17:19:28.476 27809-27814/com.myorg.myapp I/art: After code cache collection, code=14KB, data=42KB 
07-28 17:19:28.476 27809-27814/com.myorg.myapp I/art: Increasing code cache capacity to 256KB 
07-28 17:19:29.036 27809-27814/com.myorg.myapp I/art: Do full code cache collection, code=119KB, data=108KB 
07-28 17:19:29.037 27809-27814/com.myorg.myapp I/art: After code cache collection, code=113KB, data=86KB 
07-28 17:19:29.216 27809-27895/com.myorg.myapp I/Adreno: QUALCOMM build     : 7d18700, I8ee426a9a2 
                     Build Date      : 10/07/16 
                     OpenGL ES Shader Compiler Version: XE031.09.00.03 
                     Local Branch      : mybranch22308589 
                     Remote Branch     : quic/LA.BR.1.3.6_rb1.6 
                     Remote Branch     : NONE 
                     Reconstruct Branch    : NOTHING 
07-28 17:19:29.229 27809-27895/com.myorg.myapp I/OpenGLRenderer: Initialized EGL, version 1.4 
07-28 17:19:29.229 27809-27895/com.myorg.myapp D/OpenGLRenderer: Swap behavior 1 
07-28 17:19:29.388 27809-27814/com.myorg.myapp I/art: Do partial code cache collection, code=125KB, data=105KB 
07-28 17:19:29.388 27809-27814/com.myorg.myapp I/art: After code cache collection, code=125KB, data=105KB 
07-28 17:19:29.388 27809-27814/com.myorg.myapp I/art: Increasing code cache capacity to 512KB 
07-28 17:19:29.691 27809-27809/com.myorg.myapp W/art: Before Android 4.1, method int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView 
07-28 17:19:29.701 27809-27809/com.myorg.myapp I/Choreographer: Skipped 97 frames! The application may be doing too much work on its main thread. 
07-28 17:19:34.479 27809-27809/com.myorg.myapp I/Choreographer: Skipped 124 frames! The application may be doing too much work on its main thread. 
07-28 17:19:37.417 27809-27809/com.myorg.myapp W/IInputConnectionWrapper: reportFullscreenMode on inexistent InputConnection 
07-28 17:19:37.417 27809-27809/com.myorg.myapp W/IInputConnectionWrapper: finishComposingText on inactive InputConnection 
07-28 17:19:41.841 27809-27814/com.myorg.myapp I/art: Do full code cache collection, code=252KB, data=246KB 
07-28 17:19:41.844 27809-27814/com.myorg.myapp I/art: After code cache collection, code=248KB, data=216KB 
07-28 17:19:45.257 27809-27809/com.myorg.myapp I/Choreographer: Skipped 204 frames! The application may be doing too much work on its main thread. 
07-28 17:19:49.125 27809-27809/com.myorg.myapp W/IInputConnectionWrapper: reportFullscreenMode on inexistent InputConnection 
07-28 17:19:49.126 27809-27809/com.myorg.myapp W/IInputConnectionWrapper: finishComposingText on inactive InputConnection 
07-28 17:19:57.498 27809-27814/com.myorg.myapp I/art: Do partial code cache collection, code=250KB, data=227KB 
07-28 17:19:57.499 27809-27814/com.myorg.myapp I/art: After code cache collection, code=250KB, data=227KB 
07-28 17:19:57.499 27809-27814/com.myorg.myapp I/art: Increasing code cache capacity to 1024KB 
07-28 17:20:12.117 27809-27809/com.myorg.myapp W/IInputConnectionWrapper: reportFullscreenMode on inexistent InputConnection 
07-28 17:20:12.117 27809-27809/com.myorg.myapp W/IInputConnectionWrapper: finishComposingText on inactive InputConnection 

Voici une autre LogCat quand « fichier:/» est utilisé & les accidents app:

07-28 17:43:57.190 30651-30651/com.myorg.myapp D/AndroidRuntime: Shutting down VM 
07-28 17:43:57.232 30651-30651/com.myorg.myapp E/AndroidRuntime: FATAL EXCEPTION: main 
Process: com.myorg.myapp, PID: 30651 
java.lang.IllegalStateException: Could not execute method for android:onClick 
    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293) 
    at android.view.View.performClick(View.java:5612) 
    at android.view.View$PerformClick.run(View.java:22285) 
    at android.os.Handler.handleCallback(Handler.java:751) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6123) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 
    Caused by: java.lang.reflect.InvocationTargetException 
    at java.lang.reflect.Method.invoke(Native Method) 
    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 
    at android.view.View.performClick(View.java:5612)  
    at android.view.View$PerformClick.run(View.java:22285)  
    at android.os.Handler.handleCallback(Handler.java:751)  
    at android.os.Handler.dispatchMessage(Handler.java:95)  
    at android.os.Looper.loop(Looper.java:154)  
    at android.app.ActivityThread.main(ActivityThread.java:6123)  
    at java.lang.reflect.Method.invoke(Native Method)  
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)  
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)  
    Caused by: android.os.FileUriExposedException: file://storage/emulated/0/Documents/Tasks.csv exposed beyond app through ClipData.Item.getUri() 
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1813) 
    at android.net.Uri.checkFileUriExposed(Uri.java:2360) 
    at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832) 
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8957) 
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8942) 
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1583) 
    at android.app.Activity.startActivityForResult(Activity.java:4228) 
    at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:50) 
    at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:79) 
    at android.app.Activity.startActivityForResult(Activity.java:4187) 
    at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:859) 
    at android.app.Activity.startActivity(Activity.java:4515) 
    at android.app.Activity.startActivity(Activity.java:4483) 
    at com.myorg.myapp.MainActivity.onClickSend(ProgSummary.java:209) 
    at java.lang.reflect.Method.invoke(Native Method)  
    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)  
    at android.view.View.performClick(View.java:5612)  
    at android.view.View$PerformClick.run(View.java:22285)  
    at android.os.Handler.handleCallback(Handler.java:751)  
    at android.os.Handler.dispatchMessage(Handler.java:95)  
    at android.os.Looper.loop(Looper.java:154)  
    at android.app.ActivityThread.main(ActivityThread.java:6123)  
    at java.lang.reflect.Method.invoke(Native Method)  
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)  
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 

Quelle est la bonne façon de le faire?

Nouvelles informations:

Quand je "contenu: /", cette fois j'ai vu brièvement un message flash (Toast?) Sur l'application Gmail, en disant "Impossible de joindre le fichier vide". Mais ce n'est pas vide !!!

Plus Nouvelles informations:

J'essayé d'utiliser FileProvider de le faire. Voici le code ...

AndroidManifest.xml:

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

filepaths.xml:

<?xml version="1.0" encoding="utf-8"?> 
<paths> 
    <external-path name="publicdocuments/" path="documents/" /> 
</paths> 

MainActivity.java:

public void onClickSend(View v) { 
    Intent i = new Intent(android.content.Intent.ACTION_SEND); 
    String Email[] = { "[email protected]" }; 
    i.putExtra(android.content.Intent.EXTRA_EMAIL, Email); 
    i.putExtra(android.content.Intent.EXTRA_SUBJECT, "Report"); 
    i.setType("text/plain"); 
    File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS); 
    File f = new File(path, "file.csv"); 
    Uri sUri = FileProvider.getUriForFile(MainActivity.this, "com.myorg.myapp.fileprovider", f); 
    i.setData(sUri); 
    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 

    startActivity(i); 
} 

Le problème est maintenant que cela ne fonctionne pas - encore une fois mes application se bloque sur l'appel à FileProvider.getUriForFile().

Voici la nouvelle LogCat:

--------- beginning of crash 
07-29 13:45:27.116 10397-10397/com.myorg.myapp E/AndroidRuntime: FATAL EXCEPTION: main 
    Process: com.myorg.myapp, PID: 10397 
    java.lang.IllegalStateException: Could not execute method for android:onClick 
     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293) 
     at android.view.View.performClick(View.java:5612) 
     at android.view.View$PerformClick.run(View.java:22285) 
     at android.os.Handler.handleCallback(Handler.java:751) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:154) 
     at android.app.ActivityThread.main(ActivityThread.java:6123) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 
    Caused by: java.lang.reflect.InvocationTargetException 
     at java.lang.reflect.Method.invoke(Native Method) 
     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 
     at android.view.View.performClick(View.java:5612)  
     at android.view.View$PerformClick.run(View.java:22285)  
     at android.os.Handler.handleCallback(Handler.java:751)  
     at android.os.Handler.dispatchMessage(Handler.java:95)  
     at android.os.Looper.loop(Looper.java:154)  
     at android.app.ActivityThread.main(ActivityThread.java:6123)  
     at java.lang.reflect.Method.invoke(Native Method)  
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)  
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)  
    Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Documents/Tasks.csv 
     at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711) 
     at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400) 
     at com.myorg.myapp.MainActivity.onClickSend(MainActivity.java:214) 
     at java.lang.reflect.Method.invoke(Native Method)  
     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)  
     at android.view.View.performClick(View.java:5612)  
     at android.view.View$PerformClick.run(View.java:22285)  
     at android.os.Handler.handleCallback(Handler.java:751)  
     at android.os.Handler.dispatchMessage(Handler.java:95)  
     at android.os.Looper.loop(Looper.java:154)  
     at android.app.ActivityThread.main(ActivityThread.java:6123)  
     at java.lang.reflect.Method.invoke(Native Method)  
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)  
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 

Comme vous pouvez le voir, il y a un InvocationTargetException, mais je ne sais pas pourquoi ...

Informations supplémentaires: Remplacement MainActivity.this avec v.getContext() dans FileProvider.getUriForFile() donne le même résultat.

+0

Jetez un oeil à la LogCat Stacktrace – creativecreatorormaybenot

+0

Je pense que vous avez oublié une autorisation d'utilisation pour lire le stockage externe .. et vérifiez si vous avez l'autorisation de stockage activé dans les paramètres de l'application .. – mmmatey

+0

Merci, @mmmatey, j'ai mis à jour mon code (ci-dessus) pour inclure les autorisations. –

Répondre

0

Il semble vraiment bizarre pour mon application à mettre en place un FileProvider avec des autorisations d'accès à un dossier public

L'appli que vous essayez de l'envoyer par ne peut pas avoir accès au stockage externe. Par conséquent, FileProvider est toujours le modèle recommandé.

Cela provoque l'application crash avec le message: "MyApp a arrêté"

Use LogCat to examine the Java stack trace associés à l'accident quelle que soit l'application "MyApp" est. En outre, veuillez noter que plain/text n'est pas un type MIME valide. Vraisemblablement, vous voulez dire text/plain.

Et, étant donné un File, utilisez Uri.fromFile() pour générer un Uri pour cela. Gardez à l'esprit que votre application peut se bloquer sur Android 7.0+ pour utiliser un schéma file, ce qui est une autre raison d'utiliser FileProvider.

Quelle est la bonne façon de procéder?

Utilisez FileProvider.

+0

_L'application à laquelle vous essayez de l'envoyer ne dispose peut-être pas d'un accès au stockage externe._ Je ne pense pas que Gmail devrait avoir ce problème ... –

+0

_En outre, veuillez noter que le format plain/text n'est pas un type MIME valide. Vraisemblablement, vous voulez dire texte/plain._ Hmmm ... impair - je l'ai obtenu à partir d'un exemple dans un autre post. Quoi qu'il en soit, j'ai changé, comme vous le suggérez. –

+0

_Utilisez FileProvider._ En fait, j'ai commencé à le faire avant de poster cette question, mais j'ai arrêté et reculé mes changements parce que je ne pouvais pas voir mon chemin en avant. Donc, dans mon fichier manifeste je devrais avoir: android: autorités = "com.myorg.myapp.fileprovider" ' ou quoi? Encore une fois, mon application devrait-elle avoir autorité sur un fichier créé par Excel sur l'ordinateur portable de quelqu'un ...? –