6

In my Andoroid app I want to let the user send a file that my app has generated using whatever sending method the user prefers (e.g. Email, Skype, Viber, Bluetooth, etc) I am using Intent.ACTION_SEND as follows:

File readF = new File(fullFileName);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.some_subject));
intent.putExtra(Intent.EXTRA_TEXT, getResources().getString(R.string.some_message_body));
Uri uri = FileProvider.getUriForFile(this, "my.package.fileprovider", readF);
intent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, getResources().getString(R.string.some_info_message));

Which successfully sends files over Gmail, and Bluetooth, just as expected.

But when the user chooses Skype, the file is sent, but its name is changed

When the user chooses Viber nothing is sent.

If I change only the way I construct the Uri:

Uri uri = Uri.fromFile(new File("/some/publicly/available/file"));

Then the file is successfully sent both over Skype, and Viber, and the name is preserved.

So what is the difference in using FileProvider vs directly using a public file in Intent.

Jeni
  • 1,088
  • 12
  • 30

1 Answers1

4

I am using Intent.ACTION_SEND as follows:

I recommend that you add Intent.FLAG_GRANT_READ_URI_PERMISSION to that Intent.

Then the file is successfully sent both over Skype, and Viber, and the name is preserved.

Only until your targetSdkVersion climbs to 24 or higher, and you start running your app on Android 7.0+. Then, your app crashes with a FileUriExposedException.

Then the file is successfully sent both over Skype, and Viber, and the name is preserved.

For now, perhaps. The authors of those apps, and any others, are not obligated to maintain your filenames. They can do whatever they want, as it is their apps, not yours.

So what is the difference in using FileProvider vs directly using a public file in Intent.

FileProvider is roughly analogous to a Web server. It allows an app to share content to other apps, without those apps necessarily having direct access to the underlying files. Google is trying to get away from having external storage be a dumping ground for random crap in support of things like ACTION_SEND, and so on Android 7.0+, StrictMode is set up "out of the box" to crash the app if you try passing a file Uri (e.g., Uri.fromFile()).

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks! I have added Intent.FLAG_GRANT_READ_URI_PERMISSION to be on the safe side. I understand FileProvider is the correct way, and I understand Skype and Viber can do whatever they want with my file, BUT what bothers me is I thought it should be TRANSPARENT to them what way I am sending the file, as long as they have read permissions. And the difference in behavior is what I don't fully understand. – Jeni Mar 15 '17 at 06:11
  • 2
    @Jeni: "I thought it should be TRANSPARENT to them" -- ideally, it would be. Since `FileProvider` uses the filename as the "filename" part of the `content` `Uri`, and since `openInputStream()` on `ContentResolver` handles both `file` and `content`, ideally Skype and Viber would treat both forms of `Uri` equally. Apparently, they do not. There is nothing that you can really do about this, other than to get a job at those firms and try to fix their code from within. – CommonsWare Mar 15 '17 at 11:51