How to let users upload their photos into your app
Giving your users the ability to upload their own photos into your app is pretty common and yet, can still be tough within Xamarin Forms. Anytime you need to access a camera or work with images (besides just showing one) you’ll need to implement it at the platform level. So what we’ll cover is how to use Dependency Injection to get our images from either the camera or an image gallery (if you need a refresher on this topic you can start here https://developer.xamarin.com/guides/xamarin-forms/dependency-service/).
I’ve added a sample project that contains everything, even the recent updated changes, you can find it here. Some of the code in this post might not match 1 to 1 with the sample project but most of the core concepts are the same.
Let’s start by creating a new interface that will define two methods that we will implement later on for both iOS and Android. This interface should be placed in the shared code solution of your project.
In your iOS Solution create a new class that will implement the CameraInterface we just created.
Now we need to start implementing the two methods we declared in the interface, we’ll start with the camera. The first thing we need to do is check if we have permission to access the camera, if this is the first time asking, then the user will get the default iOS prompt where they can give your app camera permission. If they have already declined permission before you’ll want to add a message to the user telling them so and how to turn this back on in their settings.
With camera permission out of the way, we can now launch the camera and wait for the callback once the picture has been taken.
To recap the code snippet above, once the user takes a picture, I keep the original size but compress it by 50% to make the file size smaller. I then turn the image into a byte array so I can send it to a server to be saved. Even if you have no interest in doing that this approach still works really well since even though iOS uses UIImage and Android uses Bitmaps, both of these types can be converted into a byte array so the end result will work for both platforms. Stay tuned for how we will use the Messaging Center and where that is going 🙂
One final note for iOS, you also need to provide two values in the info.plist that basically let’s Apple know your app intends to use the camera and access photos.
You can use any messaging you prefer on the right, just remember that your users will actually see this message when they get the iOS prompt asking permission.
NOTE: Some of the Android code is outdated now with recent changes to Android’s file system etc. If you noticed weird behavior when trying this code that’s why. Updated solution for Android can be found here.
In the Droid solution we need to create a class that implements the CameraInterface just like we did on iOS.
This should look very similar to what we just did, the only difference is the rest of our code will reside in the MainActicity.cs class.
In order to catch the call back from the camera and the image gallery we need to implement the method OnActivityResult inside the MainActivity.cs class.
One of things I encountered when doing all of this Bitmap work, mainly fixing the orientation of the image, took a really long time on Android. So to make the user experience as seamless as possible, I highly recommend doing this on a background thread so your app isn’t staring at a black screen for a few seconds while the phone is processing the bitmaps.
In order to do this I created a “child” class within the MainActivity that implements AsyncTask. If you’ve ever done native Android in Java your probably familiar with this, the only real difference here is of course the syntax. If your not familiar with this, AsyncTask is just a way to run some code on a non UI thread and it gives you a call back once your code is finished to then update your UI. You can find more information here, https://developer.android.com/training/displaying-bitmaps/process-bitmap.html#concurrency.
Again, this code is almost identical to what we did on iOS, except now we are going to do all the processing in the background then send the byte array back up to our UI.
Final thoughts on Android, make sure you update the AndroidManifest.xml file to include Camera and ReadExternalStorage permissions.
Back to the MessagingCenter
Now we can go over how to take these byte arrays and actually get the image to show up in the UI. Since this tutorial is meant for Xamarin Forms, your main UI will be up in the shared code solution, then we call down to the specific platform we’re on to handle the camera and photos, then we send the result back up to the shared code solution using the MessagingCenter.
You can find more about this here https://developer.xamarin.com/guides/xamarin-forms/messaging-center/.
In the UI I have a button that ask to upload a photo, here is the button event.
The code above is how we use the Dependency Injection to then call the camera or launch the photo gallery on each platform.
In order to catch the byte array we keep sending, we’ll need to subscribe and listen for that event (I named it ImageSelected). So inside your ContentPage constructor (or which ever layout you are using for the UI that will be displaying the image), add the last bit for MessagingCenter.