android通过电子邮件发送公共存储文件

时间:2017-07-28 21:01:46

标签: android email-attachments

我看了很多很多SO帖子来找到答案,但没有运气......

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

大多数帖子都在询问内部存储文件。因此,他们使用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[] = { "my.name@gmail.com" };
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已停止"

当我改变"文件:/"到"内容:/"该应用程序不再崩溃,并且已发送电子邮件,但未附加任何文件。

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

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

以下是我使用&#34;内容时的LogCat:/&#34;:

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

这是&#34;文件中的另一个LogCat:/&#34;使用&amp;应用程序崩溃:

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)

这样做的正确方法是什么?

新信息:

当我使用&#34;内容:/&#34;时,我这次在Gmail应用上看到一条消息(Toast?)短暂闪烁,说&#34;无法附加空文件&#34; ;。但它不是空的!!!

更多新信息:

我尝试使用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[] = { "my.address@gmail.com" };
    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,但我不知道为什么......

其他信息:在FileProvider.getUriForFile()中使用v.getContext()替换MainActivity.this会产生相同的结果。

1 个答案:

答案 0 :(得分: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