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