44

Here is my code, but this is for a single file solution.

Can I share multiple files & uploads like I do for single files below?

Button btn = (Button)findViewById(R.id.hello);

    btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_SEND);

                String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/pic.png";
                File file = new File(path);

                MimeTypeMap type = MimeTypeMap.getSingleton();
                intent.setType(type.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(path)));

                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
                intent.putExtra(Intent.EXTRA_TEXT, "1111"); 
                startActivity(intent);
            }
        }); 
Michael Celey
  • 12,645
  • 6
  • 57
  • 62
osmund sadler
  • 1,021
  • 2
  • 15
  • 27

4 Answers4

124

Yes but you'll need to use Intent.ACTION_SEND_MULTIPLE instead of Intent.ACTION_SEND.

Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putExtra(Intent.EXTRA_SUBJECT, "Here are some files.");
intent.setType("image/jpeg"); /* This example is sharing jpeg images. */

ArrayList<Uri> files = new ArrayList<Uri>();

for(String path : filesToSend /* List of the files you want to send */) {
    File file = new File(path);
    Uri uri = Uri.fromFile(file);
    files.add(uri);
}

intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, files);
startActivity(intent);

This could definitely be simplified but I left some lines in so you can break down each step that is needed.

UPDATE: Starting in API 24, sharing file URIs will cause a FileUriExposedException. To remedy this, you can either switch your compileSdkVersion to 23 or lower or you can use content URIs with a FileProvider.

UPDATE (to the update): Google recently announced that new apps and app updates would be required to target one of the latest versions of Android for release to the Play Store. That said, targeting API 23 or lower is no longer a valid option if you plan to release the app to the store. You must go the FileProvider route.

Michael Celey
  • 12,645
  • 6
  • 57
  • 62
  • unfortunately this seems not working while sharing multiple picture on facebook. I was able to make it working using the solution described in this post: http://stackoverflow.com/questions/25846496/intent-share-action-send-multiple-facebook-not-working – Lisitso Jan 16 '15 at 10:41
  • What about sending different file types image/* and video/*? – Eftekhari Jul 05 '16 at 20:07
  • 1
    Should work the same way. You'd just have to change the `setType()` call to have the proper data type. – Michael Celey Jul 06 '16 at 06:02
  • 2
    Set the type something like this to send different file types intent.setType("\*/\*"); this would help in a situation where you want to send heterogeneous file types (like sending to Google Drive or Dropbox etc.) – A.B. Dec 05 '16 at 13:51
  • 3
    A trivia for you: file sharing on Android has been designed by the devil himself. – kar Dec 06 '18 at 11:54
  • if you want to send a format about which you are not sure, use `image/*` – Sambhav Khandelwal Mar 11 '22 at 15:24
15

Here is little improved version improvised by MCeley's solution. This could be used to send the heterogeneous file list (like image, document and video at same time), for instance uploading downloaded documents, images at same time.

public static void shareMultiple(List<File> files, Context context){

    ArrayList<Uri> uris = new ArrayList<>();
    for(File file: files){
        uris.add(Uri.fromFile(file));
    }
    final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    intent.setType("*/*");
    intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
    context.startActivity(Intent.createChooser(intent, context.getString(R.string.ids_msg_share)));
}
A.B.
  • 1,554
  • 1
  • 14
  • 21
  • Thanks! It's worth noting that in most cases I've tried you can have a heterogeneous file list.. basically the mime type simply limits app responses to those apps capable of handling the type specified, eg. if you specify "text/*" google photos won't respond. But gmail will respond and the list can include images, which will be correctly handled. – marzetti Jun 19 '20 at 06:18
4

If you are sharing a file with another applications on devices running KitKat and above, you will need to provide Uri permissions.


This is how I handle multiple file sharing pre and post KitKat:

//All my paths will temporarily be retrieve into this ArrayList
//PathModel is a simple getter/setter
ArrayList<PathModel> pathList;
//All Uri's are retrieved into this ArrayList
ArrayList<Uri> uriArrayList = null;
//This is important since we are sending multiple files
Intent sharingIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
//Used temporarily to get Uri references
Uri shareFileUri;

if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

    //My paths are stored in SQLite, I retrieve them first
    SQLiteHelper helper = new SQLiteHelper(this);
    pathList = helper.getAllAttachments(viewholderID);
    helper.close();

    //Create new instance of the ArrayList where the Uri will be stored
    uriArrayList = new ArrayList<>();

    //Get all paths from my PathModel
    for (PathModel data : pathList) {
        //Create a new file for each path
        File mFile = new File(data.getPath());
        //No need to add Uri permissions for pre-KitKat
        shareFileUri = Uri.fromFile(mFile);
        //Add Uri's to the Array that holds the Uri's
        uriArrayList.add(shareFileUri);
    }


} else {

    //My paths are stored in SQLite, I retrieve them first
    SQLiteHelper helper = new SQLiteHelper(this);
    pathList = helper.getAllAttachments(viewholderID);
    helper.close();

    //Create new instance of the ArrayList where the Uri will be stored
    uriArrayList = new ArrayList<>();

    //Get all paths from my PathModel
    for (PathModel data : pathList) {
        //Create a new file for each path
        File mFile = new File(data.getPath());
        //Now we need to grant Uri permissions (kitKat>)
        shareFileUri = FileProvider.getUriForFile(getApplication(), getApplication().getPackageName() + ".provider", mFile);
        //Add Uri's to the Array that holds the Uri's
        uriArrayList.add(shareFileUri);
    }

    //Grant read Uri permissions to the intent
    sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

}

//I know that the files which will be sent will be one of the following
sharingIntent.setType("application/pdf/*|image|video/*");
//pass the Array that holds the paths to the files
sharingIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriArrayList);
//Start intent by creating a chooser
startActivity(Intent.createChooser(sharingIntent, "Share using"));

In my case the paths were stored in SQLite, but the paths can come from wherever.

HB.
  • 4,116
  • 4
  • 29
  • 53
3
/* 
 manifest file outside the applicationTag write these permissions
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> */

    File pictures = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
                            //Get a top-level public external storage directory for placing files of a particular type. 
                            // This is where the user will typically place and manage their own files, 
                            // so you should be careful about what you put here to ensure you don't 
                            // erase their files or get in the way of their own organization...
                            // pulled from Standard directory in which to place pictures that are available to the user to the File object

                            String[] listOfPictures = pictures.list();
                            //Returns an array of strings with the file names in the directory represented by this file. The result is null if this file is not a directory.

                            Uri uri=null; 
                            ArrayList<Uri> arrayList = new ArrayList<>();
                            if (listOfPictures!=null) {
                                for (String name : listOfPictures) {
                                    uri = Uri.parse("file://" + pictures.toString() + "/" + name );
                                    arrayList.add(uri);
                                }
                                Intent intent = new Intent();
                                intent.setAction(Intent.ACTION_SEND_MULTIPLE);
                                intent.putExtra(Intent.EXTRA_STREAM, arrayList);
                                //A content: URI holding a stream of data associated with the Intent, used with ACTION_SEND to supply the data being sent.
                                intent.setType("image/*"); //any kind of images can support.
                                chooser = Intent.createChooser(intent, "Send Multiple Images");//choosers title
                                 startActivity(chooser);
                            }
Emre Kilinc Arslan
  • 2,019
  • 2
  • 16
  • 12