1

I am trying to share an image through implicit intent. The image is shared successfully through Messenger and Twitter but fails on Facebook News Feed, Viber and Email. I read somewhere that I need to save the image to the external or internal SD card first before sharing. I am a little lost on 1) how to save the image to the SD card and 2) how to point to the new image location on the SD card in order to share it. Currently my code for sharing the image looks like this:

Button share =  findViewById(R.id.sharetoapps);
        share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Uri uri = Uri.parse("android.resource://com.testing.mypic/drawable/bad_day");
                intent = new Intent();
                intent.setAction(Intent.ACTION_SEND);
                intent.putExtra(Intent.EXTRA_STREAM,uri);
                intent.setType("image/png");

                startActivity(Intent.createChooser(intent, "share to:"));
            }
        });

And my xml is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <Button
        android:id="@+id/sharetoapps"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="share" />



</LinearLayout>

If you have any pointers or know of any relevant tutorials I would appreciate it.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Maz
  • 118
  • 10
  • 1
    `EXTRA_STREAM` is not supposed to have a `Uri` with an `android.resource` scheme. [It is supposed to have a `content` scheme](https://developer.android.com/reference/kotlin/android/content/Intent#extra_stream). Copy your resource to a file (e.g., in `getCacheDir()`), then use `FileProvider` and its `getUriForFile()` method to get the `content` `Uri` to share. Be sure to add `FLAG_GRANT_READ_URI_PERMISSION` to the `Intent` as well. See [the documentation](https://developer.android.com/training/secure-file-sharing) for more about sharing content in Android. – CommonsWare Jun 08 '20 at 17:11
  • OK so what I understood is that I should not use images from the drawable folder to share to social media but instead a direct file. I'm afraid I'm not familiar with the rest of the terms you mentioned, I'll have to read up on it all. Thank you! – Maz Jun 08 '20 at 17:17
  • @CommonsWare I have read through 15 different solutions somewhat relevant to my issue but nothing I have tried has worked. I am struggling with the step of saving the file in order to share it. I should have pointed out that I have an SQLite db with filenames. A filename is randomly generated and is used to grab the relevant drawable image which is then displayed on the screen. I have not understood how to save the file to the external SD card but I may be getting confused because I can't hardcode the drawable resource to save it locally. Do you have an example I could work with? – Maz Jun 09 '20 at 20:44
  • 1
    Personally, I tend to use `assets/`, rather than `res/drawable/`, for this sort of situation. [This Java app](https://gitlab.com/commonsguy/cw-jetpack-java/-/tree/v0.9/PdfProvider) (and [its Kotlin equivalent](https://gitlab.com/commonsguy/cw-jetpack-kotlin/-/tree/v0.9/PdfProvider)) demonstrate copying a PDF from `assets/` to a file, then using `FileProvider` and `ACTION_VIEW` to display it. Those examples are covered in [this book](https://commonsware.com/Jetpack). – CommonsWare Jun 09 '20 at 20:49
  • Interesting again. I will read through it all and hope to understand it. Thank you! I wonder if it's best to read [this](https://commonsware.com/Android/) one first? – Maz Jun 09 '20 at 20:58
  • 1
    Probably not. That book (*The Busy Coder's Guide to Android Development*) was my original book. When the Jetpack and Kotlin came out, I could not reasonably rewrite that book (all 4000+ pages of it!). The book I linked to ([*Elements of Android Jetpack*](https://commonsware.com/Jetpack)) replaces the introductory chapters of *The Busy Coder's Guide to Android Development*. My *Elements* books are all up to date (as is *Exploring Android*, if you like hands-on tutorials better). – CommonsWare Jun 09 '20 at 21:03

1 Answers1

0

OK I finally got it to work but it requires a number of things.

First the following needs to be added to the AndroidManifest.xml file:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <!-- ressource file to create -->
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths">
    </meta-data>
</provider>

Then I had to create a folder named xml under res. Then I created a file called file_paths.xml inside that folder. The file contains the following:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>

Finally my share method ended up looking like this:

Button share =  findViewById(R.id.sharetoapps);
        share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ActivityCompat.requestPermissions(QuotesActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);


                boolean success=false;
                Bitmap image = BitmapFactory.decodeResource(getResources(), getResources().getIdentifier(msg,"drawable",getPackageName()));
                final String TAG = QuotesActivity.class.getSimpleName();
                File path = Environment.getExternalStorageDirectory();
                File dir = new File(path + "/newAppFolder/");
                dir.mkdir();

                File file = new File(dir,"frs.png");

                OutputStream out = null;
                try{
                    out = new FileOutputStream(file);
                    image.compress(Bitmap.CompressFormat.PNG, 100, out);
                    success=true;
                    out.flush();
                    out.close();

                } catch (FileNotFoundException e){
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if (success) {
                    Toast.makeText(getApplicationContext(), "Image saved with success",
                            Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(getApplicationContext(),
                            "Error during image saving", Toast.LENGTH_LONG).show();
                }


                File f = new File(Environment.getExternalStorageDirectory() + File.separator+ "newAppFolder" + File.separator + "frs.png");
                Uri imageUri = FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),BuildConfig.APPLICATION_ID + ".provider", f);
                Intent shareit=new Intent(Intent.ACTION_SEND);
                shareit.setType("image/png");
                shareit.putExtra(Intent.EXTRA_STREAM, imageUri);
                startActivity(Intent.createChooser(shareit, "Share Image Via"));

                startActivity(Intent.createChooser(intent, "share to:"));
            }
        });

Note:

When I try to share the image in more than one place I get a warning saying my application keeps stopping and asking me whether I want to report the app (which I don't at present) though it still allows me to continue sharing the image. I am not sure what is causing this. If anyone has an idea please let me know.

Maz
  • 118
  • 10