Proper way to share an Image (using Intents)

2019-06-22 14:49发布

问题:

I create images in my app and want to share these social networks (facebook), mail apps (gmail), and other apps that can "receive" images.

The origin of the problem (I think) is that I don't want to use the external storage as a base for my images. I want to either use my data folder or my cache folder since neither of these require any permission to access.

The code which I use to write my image to file (and I specify the MODE_WORLD_READABLE so that other apps can read them):

FileOutputStream fos = null;
try {
    fos = context.openFileOutput("image.jpg", Context.MODE_WORLD_READABLE);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
} finally {
    if (fos != null)
        fos.close();
}

And this is the code where I share the image:

File internalFile = context.getFileStreamPath("image.jpg");

Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(internalFile));
intent.setType("image/jpeg");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

context.startActivity(Intent.createChooser(intent, "share"));

This solution is very easy and works fine for apps like facebook but not for example gmail which failes with:

file:// attachment paths must point to file:///mnt/sdcard

There are a number of "hacks" (see below) to get it to work with gmail but I leaves me asking myself if there is an even better way to share images that works without hacks, something I overlooked. So, to the questions:

  • What is the best way to share images? (external storage?)
  • Is there any more apps that (mis-)behave just like gmail? (I have seen some trouble with google+)
  • If there is no other way: Can I write special intents for sharing to specific apps. I have a default way of sharing and override it when the user selects an app on my watch list?

Hacks

  1. Using a path-hack by simply pointing the Uri to:

    file:///mnt/sdcard/../../my/package/name/...

    This solution doesn't feel right.

  2. Using a ContentProvider as described here. But quoted from the link:

    Warning: the method described in the post works well for Gmail, but apparently has some issues with other ACTION_SEND handlers (e.g. the MMS composer).

    (Issue: It crashes the MMS composer)

回答1:

Did you try ParecelableFileDescriptor?

http://developer.android.com/reference/android/os/ParcelFileDescriptor.html

Create with static ParcelFileDescriptor open(File file, int mode, Handler handler, ParcelFileDescriptor.OnCloseListener listener) Create a new ParcelFileDescriptor accessing a given file. static ParcelFileDescriptor open(File file, int mode) Create a new ParcelFileDescriptor accessing a given file.

Receiver side like this: Returning an Input Stream from Parcel File Descriptor using Androids DownloadManager



回答2:

You should to make 3 steps.
Take picture.

public Bitmap takeScreenshot() {
    View rootView = findViewById(android.R.id.content).getRootView();
    rootView.setDrawingCacheEnabled(true);
    return rootView.getDrawingCache();
}

Save picture.

public String saveBitmap(Bitmap bitmap) {

File imagePath = new File(Environment.getExternalStorageDirectory() + “/screenshot.png”);
    FileOutputStream fos;
    try {
        fos = new FileOutputStream(imagePath);
        bitmap.compress(CompressFormat.PNG, 100, fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        Log.e(“GREC”, e.getMessage(), e);
    } catch (IOException e) {
        Log.e(“GREC”, e.getMessage(), e);
    }

    return imagePath.getAbsolutePath();
} 

Share to social network.