2017-07-28 72 views
1

发送公共存储文件我已经看过很多很多的SO职位找到答案,但没有运气...的Android通过电子邮件

如何发送公共存储文件作为电子邮件的附件?

大多数帖子都在询问内部的存储文件。所以为此,他们使用FileProvider(或类似的东西)。在文档的FileProvider,我读:

FileProvider ...便于与应用程序相关的文件安全共享...

但我要发送的文件是不是与我的应用程序相关联。它是公用存储在Documents文件夹中的.csv文件。所以对于我的应用程序来说,为公共文件设置具有访问权限的FileProvider似乎非常奇怪。使用我的软件包名称作为“权威”更加奇怪。

我尝试下面的代码,这是我放在一起基于在1个或2个其他职位的答案:

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

和在另一种方法中,我有:

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); 

这使得该应用崩溃消息:“MyApp已停止”

当我将“file:/”更改为“content:/”时,应用程序不再崩溃,并且发送了电子邮件,但没有附加任何文件。

我AndroidManifest.xml中包含以下权限:

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

这里是从时间我logcat的,当我使用 “的内容:/”:

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 

这里的另一个logcat的时候“文件: /”用于&应用程序崩溃:

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) 

什么是做到这一点的正确方法?

新信息:

当我用“的内容:/”,这时候我看到一个消息(吐司?)一闪而过的Gmail应用程序,称“无法附加空文件”。但它不是空的!

更多新品信息:

我试着用FileProvider做到这一点。下面的代码...

的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); 
} 

现在的问题是,它不工作 - 在电话会议上再次我的应用程序崩溃到FileProvider.getUriForFile()

这里是新的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) 

正如你可以看到,有一个的InvocationTargetException,但我不知道为什么...

附加信息:与更换MainActivity.this FileProvider.getUriForFile()中的v.getContext()给出了相同的结果。

+0

看看LogCat Stacktrace – creativecreatorormaybenot

+0

我想你忘了使用权限来读取外部存储..并检查是否有权限在应用程序设置中启用存储.. – mmmatey

+0

谢谢@mmmatey我已更新我的代码(上面)包含权限。 –

回答

0

如此看来真的奇怪的我的应用程序设置了访问权限的FileProvider为公共文件

您试图通过发送它可能没有外部存储访问的应用程序。因此,FileProvider仍然是推荐的模式。

这会导致应用程序与消息崩溃:“MyApp的已停止”

Use LogCat to examine the Java stack trace在任何应用程序“MyApp的”是崩溃有关。

另请注意,plain/text不是有效的MIME类型。推测你的意思是text/plain

并且,如果是File,则使用Uri.fromFile()为其生成Uri。请记住,使用file方案时,您的应用可能会在Android 7.0+上崩溃,这是使用FileProvider的另一个原因。

什么是正确的方法来做到这一点?

使用FileProvider

+0

_您试图通过它发送的应用可能没有外部存储访问权限._我不相信Gmail应该有这个问题... –

+0

_另请注意,纯文本/文本不是有效的MIME类型。大概你的意思是文字/ plain._嗯......奇怪 - 我从另一篇文章中的例子中得到了这一点。无论如何,我已经改变了它,正如你所建议的那样。 –

+0

_使用FileProvider._实际上,在我发布这个问题之前,我开始这样做了,但我停止并退出了我的更改,因为我看不到前进的方向。所以,在我的清单文件中,我应该有:'android:authorities =“com.myorg.myapp.fileprovider”' 或者什么?同样,我的应用程序是否应该对某人笔记本电脑上由Excel创建的文件拥有权限......? –