javaandroidpdfandroid-intent

How to attach a pdf to intent to send (to email, dropbox, etc) in android


Hey so I save my pdf in external data storage. Eg:

Environment.getExternalStorageDirectory().getPath() + "/file.pdf"

Then, I try to attach it to intent to send:

        File attachment = this.getFileStreamPath(fileDirectory + "/" + fileName);


        Uri uri = Uri.fromFile(attachment);

        Intent emailIntent = new Intent(Intent.ACTION_SEND);
        emailIntent.setDataAndType(Uri.parse("mailto:"), "text/plain"); // I have also tried "application/pdf"

        emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Calc PDF Report");
        emailIntent.putExtra(Intent.EXTRA_TEXT, " PDF Report");

        emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
        startActivity(Intent.createChooser(emailIntent, "Send mail..."));
        finish();

and im getting the error:

 Caused by: java.lang.IllegalArgumentException: File /storage/emulated/0/file.pdf contains a path separator

I am thinking it is something wrong with were I am saving my file, but can't find any examples that are up-to-date.


Solution

  • To share a file as an email attachment using intent, you need to use a FileProvider.

    /**
     * Generate file content and returns uri file
     */
    public static Uri generateFile(Context context) {
      File pdfDirPath = new File(context.getFilesDir(), "pdfs");
      pdfDirPath.mkdirs();
    
      File file = new File(pdfDirPath, "attachment.pdf");
      file.deleteOnExit();
    
      Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".file.provider", file);
      FileOutputStream os = null;
      try {
        Logger.info("Generate file " + file.getAbsolutePath());
        os = new FileOutputStream(file);
        document.writeTo(os);
        document.close();
        os.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
      return uri;
    }
    
    private void share(Context context) {
      Uri uri = generateFile(context);
    
      final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
      emailIntent.setType("text/plain");
    
      emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
      emailIntent.putExtra(EXTRA_SUBJECT, "Send something");
      emailIntent.putExtra(Intent.EXTRA_TEXT, "You receive attachment");
      emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
      startActivity(emailIntent);
    }
    

    In your app add the file provider definition:

    AndroidManifest.xml
    
    <application
      android:name=".DemaApplication"
      android:allowBackup="false"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">
    
      <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.file.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
           android:name="android.support.FILE_PROVIDER_PATHS"
                 android:resource="@xml/provider_paths" />
      </provider>
      ...
    </application>
    
    provider_path.xml
    
    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <files-path
            name="internal_files"
            path="/"/>
        <!--<external-path name="external_files" path="./files"/>-->
    </paths>
    

    At last but not least, you need to specify the file provider path (where are your files). I hope this helps. Here, the official documentation about how to send email and attachment with intent.