Sharing a local image on Android 7.x fails with a FileExposedException

android
image
twitterkit

#1

I am trying to share a local image using the TweetComposer builder and using the instructions provided (https://docs.fabric.io/android/twitter/compose-tweets.html).

I have attempted to use Uri.fromFile to share a local image, but with Android 7.1.1 I am required to use a FileProvider to expose the image externally otherwise I get an android.os.FileExposedException. This documentation on the Android site recommends that you do not use Uri.fromFile when sharing files between apps, and it seems they have made that a requirement with the Exception being thrown.

When I attempt to provide the TweetComposer builder with a content:\\ URI from my FileProvider, the image fails to load in the Twitter app (it gives a generic unable to load image Toast).

I saw a post from May 2015 that talked about the SDK not accepting content:\\ URI’s. Have there been any updates that make it possible to use FileProvider with the TweetComposer? If not I am not sure how else to share an image with the FIleExposedException being thrown every time.


#2

@bforsberg hey! We don’t currently accept content:\\ URIs but I’ve been talking to the team about this. Would you mind sharing the full code you’re using that’s throwing the exception?


#3

This code crashes on a Nexus 5X running 7.1.1. Strict Mode is not turned on, but we still get the following exception.

Code

private void composeTweet() {
    try {

        // Get twitter_post.jpg from the root of the assets folder
        AssetFileDescriptor fileDescriptor = getContext().getAssets().openFd("twitter_post.jpg");
        FileInputStream input = fileDescriptor.createInputStream();

        // Creates an empty temp file in context.getExternalCacheDir()
        File imageFile = DiskUtil.createTempImageFile(getContext());
        FileOutputStream output = new FileOutputStream(imageFile);
        DiskUtil.copyFile(input, output);

        Uri imageUri = Uri.fromFile(imageFile);

        TweetComposer.Builder builder = new TweetComposer.Builder(getContext()).text("Test").image(imageUri);

        builder.show();

    } catch (IOException e) {
        Timber.e(e, e.getMessage());
    }
}

Exception

android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/{package_name}/cache/temp/tmp20170201_164031_1321807531.jpg exposed beyond app through ClipData.Item.getUri()
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
    at android.net.Uri.checkFileUriExposed(Uri.java:2346)
    at android.content.ClipData.prepareToLeaveProcess(ClipData.java:845)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8941)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8926)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
    at android.app.Activity.startActivityForResult(Activity.java:4225)
    at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48)
    at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:77)
    at android.app.Activity.startActivityForResult(Activity.java:4183)
    at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:859)
    at android.app.Activity.startActivity(Activity.java:4522)
    at android.app.Activity.startActivity(Activity.java:4490)
    at com.twitter.sdk.android.tweetcomposer.TweetComposer$Builder.show(TweetComposer.java:255)
    at {package_name}.composeTweet(ReferralsFragment.java:154)

#4

Thanks for the details @bforsberg! The team’s going to look into this more.


#5

@bforsberg Using a FileProvider should work. I will be sure to update our documentation to reflect the latest changes in Android N.