Blog

Implementing Sharing in Xamarin Forms

One thing you may want to do within your Xamarin application is to allow users to share items that your application may capture, such as photos. While this isn’t quite trivial in Xamarin Forms as it’s different for both iOS and Android, this isn’t too hard to implement with the power of renderers.

We’re going to look at a small demo app that downloads the Wintellect logo and allows it to be shared. Let’s take a look at how this all works.

Xamarin Forms

This demo project is pretty small so all we will have is just one XAML page and within the page will just have an Image. Below is our XAML and our View Model that we’re using as our BindingContext.

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="ShareExample.ShareImagePage">

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Share" Order="Secondary" Command="{Binding Share}" Name="Action" />
    </ContentPage.ToolbarItems>

    <Image x:Name="LogoImage" Source="https://training.atmosera.com/devcenter/wp-content/uploads/2013/10/Wintellect_logo.gif" Aspect="AspectFit" />
</ContentPage>
public class ShareImageViewModel
{
  public Command Share { get; set; }
  public ImageSource Source { get; set; }

  public ShareImageViewModel()
  {
      Share = new Command(ShareCommand);
  }

  void ShareCommand()
  {
      MessagingCenter.Send<ImageSource>(this.Source, "Share");
  }
}

Notice in our ToolbarItem we have a Command. Our View Model is where we’ll send our message that we will have subscribed to in each platform.

You may have noticed the MessagingCenter being used in our ShareCommand from above. This is from Xamarin Forms to use each platform’s code to allow the sharing. This is just another way for us to call each the iOS or Android specific code that will actually do the sharing.

iOS

For the iOS version, I referenced Keith Rome’s post on adding items to the bottom toolbar to show the share icon that we will be using. Once that’s in place, we can now use MessagingCenter in our AppDelegate class. In our

FinishedDidLaunching

method we just subscribe.

MessagingCenter.Subscribe<ImageSource> (this, "Share", Share, null);

And now for our Share method where we actually implement our iOS code.

async void Share (ImageSource imageSource)
{
    var handler = new ImageLoaderSourceHandler();
    var uiImage = await handler.LoadImageAsync(imageSource);

    var item = NSObject.FromObject (uiImage);
    var activityItems = new[] { item }; 
    var activityController = new UIActivityViewController (activityItems, null);

    var topController = UIApplication.SharedApplication.KeyWindow.RootViewController;

    while (topController.PresentedViewController != null) {
       topController = topController.PresentedViewController;
    }

    topController.PresentViewController (activityController, true, () => {});
}

There’s a decent bit going on here. If you remember from our Subscribe method from above, we told it that the type would be of ImageSource so that’s why our Share method has an ImageSource parameter. The first two lines in this method is from Xamarin Forms to use the ImageLoaderSourceHandler which is just a cross platform way to give us what we need. In this case for iOS, when we load in our imageSource into the LoadImageAsync method it returns back a UIImage. As you’ll see later, this returns something different in Android.

Depending on how you get your image data, you may need something different here. Here we just have a Xamarin Forms ImageSource, but if you’re calling a service to get your image you may be getting the data back as byte[]. With this, all you’d need to do different is to pass it in the Send method and your Share method will now look something like the below:

async void Share (byte[] imageData)
{
    var img = UIImage.LoadFromData (NSData.FromArray (imageData));

    var item = NSObject.FromObject (img);
    var activityItems = new[] { item }; 
    var activityController = new UIActivityViewController (activityItems, null);

    var topController = UIApplication.SharedApplication.KeyWindow.RootViewController;

    while (topController.PresentedViewController != null) {
       topController = topController.PresentedViewController;
    }

    topController.PresentViewController (activityController, true, () => {});
}

From here you can see that when we click on the share icon in the bottom toolbar we already have some initial choices to choose from.

If you click on the email option our image is placed inside the message itself.

Android

For Android, it’s a fairly similar concept in that we’ll be using the same Subscribe and Send method from above to call our platform specific code. The only difference is that in our MainActivity our Share method will be a bit different.

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 = Environment.GetExternalStoragePublicDirectory (Environment.DirectoryDownloads
       + Java.IO.File.Separator + "logo.png");

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

   intent.PutExtra (Intent.ExtraStream, Android.Net.Uri.FromFile (path));

   var intentChooser = Intent.CreateChooser (intent, "Share via");

   StartActivityForResult (intentChooser, ShareImageId);
}

All this is doing for Android is just creating an ActionSend intent and putting the photo as an Extra of the intent and start that Activity. However, it seems that Android requires the data to be downloaded onto the local storage before it can be used to share which is what we’re doing with the file manipulation APIs.

One thing to note for the simulator (I’ve been using the Xamarin Android Player myself) is that, though we’re creating an intent chooser for a user to choose where to share, the simulator just defaults to a message.

There is something else we need to do here, however. Though it may seem to work in the simulator if you try to run this on a real device you may find that the app crashes. This is because we still need to allow permissions for our application for WriteExternalStorage.

After that, you’ll be all set to share within your Android application.

Need Xamarin Help?

Xamarin Consulting  Xamarin Training

Jonathan Wood

View Comments

  • Thanks alot. Just what i needed. I made changes only in one line for Android since i created separate class file for this method:
    "Xamarin.Forms.Forms.Context.StartActivity(Intent.CreateChooser(intent, "Share Image"));"
    Hope this would be useful for someone.

  • Thanks alot. Just what i needed. I made changes only in one line for Android since i created separate class file for this method:
    "Xamarin.Forms.Forms.Context.StartActivity(Intent.CreateChooser(intent, "Share Image"));"
    Hope this would be useful for someone.

  • Thank you for the code. I have deployed it successfully to my Android smartphone. Do you have the code for Windows 10 (UWP)?

Recent Posts

8-Step AWS to Microsoft Azure Migration Strategy

Microsoft Azure and Amazon Web Services (AWS) are two of the most popular cloud platforms.…

3 days ago

How to Navigate Azure Governance

 Cloud management is difficult to do manually, especially if you work with multiple cloud…

1 week ago

Why Azure’s Scalability is Your Key to Business Growth & Efficiency

Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…

3 weeks ago

Unlocking the Power of AI in your Software Development Life Cycle (SDLC)

https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…

1 month ago

The Role of FinOps in Accelerating Business Innovation

FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…

1 month ago

Azure Kubernetes Security Best Practices

Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…

2 months ago