Sharing an image using Xamarin Forms

Viewed 5583

I’ve created a Xamarin Forms (PCL) solution, and I’m focusing on the Android project at the moment. I’m trying to implement image sharing using a dependency service. The images are located in the drawable folder of the Android project. However, every time I run the code below, the app crashes with: an unhandled exception occurred. I've checked the output log but nothing stands out. Would anyone be able to run an eye over my code and tell me if there is an error in it?

Many thanks

Interface:

public interface IShare
{
    void Share(ImageSource imageSource);
}

Xaml:

<ContentPage.Content>
    <Image x:Name="LogoImage" Source="icon.png"/>
</ContentPage.Content>

Code-Behind:

private void Action_Clicked(object sender, EventArgs e)
{
    DependencyService.Get<IShare>().Share(LogoImage.Source);
}

ShareClass (in Android project):

[assembly: Dependency(typeof(ShareClass))]
namespace MyProject.Droid
{
    public class ShareClass : Activity, IShare
    {
        public async void Share(ImageSource imageSource)
        {
            var intent = new Intent(Intent.ActionSend);
            intent.SetType("image/png");

            var handler = new ImageLoaderSourceHandler();
            var bitmap = await handler.LoadImageAsync(imageSource, this);

            var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads
                + Java.IO.File.Separator + "logo.png");

            using (var os = new System.IO.FileStream(path.AbsolutePath, FileMode.Create))
            {
                bitmap.Compress(Bitmap.CompressFormat.Png, 100, os);
            }

            intent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(path));
            Forms.Context.StartActivity(Intent.CreateChooser(intent, "Share Image"));

        }
    }
}
3 Answers

Here is what I use for Android Implementation

 public Task Share(string url)
        {
            var path = Android.OS.Environment.GetExternalStoragePublicDirectory("Temp");

            if (!File.Exists(path.Path))
            {
                Directory.CreateDirectory(path.Path);
            }

            string absPath = path.Path + "tempfile.jpg";
            File.WriteAllBytes(absPath, GetBytes(url));

            var _context = Android.App.Application.Context;

            Intent sendIntent = new Intent(global::Android.Content.Intent.ActionSend);

            sendIntent.PutExtra(global::Android.Content.Intent.ExtraText, "Application Name");

            sendIntent.SetType("image/*");

            sendIntent.PutExtra(Intent.ExtraStream, Android.Net.Uri.Parse("file://" + absPath));
            _context.StartActivity(Intent.CreateChooser(sendIntent, "Sharing"));
            return Task.FromResult(0);
        }

        public static byte[] GetBytes(string url)
        {
            byte[] arry;
            using (var webClient = new WebClient())
            {
                arry = webClient.DownloadData(url);
            }
            return arry;
        }

As my targetSdkVersion >24, I add the following two lines to MainActivity.cs to allow other apps to access files.

    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.SetVmPolicy(builder.Build());

And here are the permissions required to be allowed in AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Here is the code that I used for the ShareClass to get the sharing intent working in the end, hope it helps someone:

[assembly: Xamarin.Forms.Dependency(typeof(ShareClass))]
namespace MyProject.Droid
{
public class ShareClass: MainActivity, IShare
{
    public async void Share(ImageSource imageSource)
    {
        var intent = new Intent(Intent.ActionSend);

        intent.SetType("image/jpeg");

        IImageSourceHandler handler;

        if (imageSource is FileImageSource)
        {
            handler = new FileImageSourceHandler();
        }
        else if (imageSource is StreamImageSource)
        {
            handler = new StreamImagesourceHandler(); // sic
        }
        else if (imageSource is UriImageSource)
        {
            handler = new ImageLoaderSourceHandler(); // sic
        }
        else
        {
            throw new NotImplementedException();
        }

        var bitmap = await handler.LoadImageAsync(imageSource, CrossCurrentActivity.Current.Activity);

        Java.IO.File path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads
            + Java.IO.File.Separator + "MyDiagram.jpg");

        using (System.IO.FileStream os = new System.IO.FileStream(path.AbsolutePath, System.IO.FileMode.Create))
        {
            bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, os);
        }

        intent.AddFlags(ActivityFlags.GrantReadUriPermission);
        intent.AddFlags(ActivityFlags.GrantWriteUriPermission);
        intent.PutExtra(Intent.ExtraStream, FileProvider.GetUriForFile(CrossCurrentActivity.Current.Activity, "com.mypackagename.fileprovider", path));

        CrossCurrentActivity.Current.Activity.StartActivity(Intent.CreateChooser(intent, "Share Image"));
    }
}
}
Related