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://www.wintellect.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.

Share button clicked

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

Share photo

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.

Android Share Link

Android Sharing

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.

Android Permissions

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

Xamarin Consulting

Need Xamarin Help?

Xamarin Consulting  Xamarin Training