Tag Archives: Xamarin

XAMVVM-02 UnitTesting with Xamarin.Forms!

Thinking of how to adopt Testing practices into your Xamarin.Forms project, in this world of test driven software development? 😉 You’re about to find out!

Yes, you can easily incorporate UnitTest cases into your Xamarin.Forms project just like any other .NET solution, and there’s plenty of ways to do with several test frameworks.

As for the sake of clarity let me start off with a bit of basics…

Why UnitTesting?

So that we could write better software, with minimum failure rate. Specially for the continuous development of the software, making sure today’s code logic change doesn’t break any other elements of the application the next day, to simply put.

UnitTesting is a great approach for Test Driven Development based software building, where we test our code from the smallest units we could break into, making sure top to bottom all the bits are executing as expected! 😉

Follow a pattern…

It’s best to keep your UnitTest cases organised and categorised, as it could get messy when your Application grows as well as your test code base. You can organise your test cases according to a certain pattern, either based on your Application Pages or Flows.

Using Page based pattern for organising our test cases, allows us to write the test cases as they originates from each Page context itself. Further more on the base of behavior and functionalities available in each page in the application, as an example Home Page, Shopping Cart Page, Payment Page, and etc…

You could also use a Flow based pattern for your test cases, where you write test cases accordingly each individual feature flow of the application, as an example Login Flow, Order Flow, Payment Flow, and etc…

The choice is up to your requirement and the nature and complexity of your app. Although in my opinion page based approach could be easy to manage the test cases in long run.

Xamarin.Forms and UnitTesting!

Basically we could use any .NET Testing framework to test our Xamarin.Forms projects such as following.

  • MsTest
  • NUnit
  • xUnit, etc…

There are mainly two approaches we could take for UnitTesting our Xamarin.Forms project…

– ViewModel instances testing: This is about creating instances of the ViewModels of the app inside our UnitTest environment and testing each execution flow.

– Runtime Mocked testing: Here we’re creating a mocked app run time using a third party library inside our UnitTest environment and testing each execution flow.

ViewModel based testing, is a very limited form of testing hence there’s no way to perform testing on Navigation and UI Interactions flows. Although this is very easy to implement, it is not very effective, since with Xamarin.Forms applications we’re dealing with user interactions and all. Runtime Mocked testing is actually a much better way, hence we get to go through the actual application UI flow for each our test cases. So let’s do that! 😉

Xamarin.Forms Runtime Mocked UnitTesting!

Like I said above, this is the most effective since it not only saves a lot of development time, but also beneficial for TDD practices for accelerating development.

So we need to mock the Xamarin.Forms runtime without actually launch the app in an emulator or a device, which is going to be done using this awesome library, Xamarin.Forms.Mocks! Allowing us to create an actual instance of the app in memory, mocking the whole Xamarin.Forms run-time, allowing us to navigate through the app as if we’ve actually launched the app.

How to?

First thing we need to create a new UnitTest project in our Xamarin.Forms solution. Then add a reference of our Xamarin.Forms .Net Standard project to it, so that we can instantiate the app and add references from it into our test project. Next we have to add Xamarin.Forms.Mocks, nuget to the test project to emulate the Xamarin.Forms run-time. 😀

Finally, you can straight up create an instance of App class and access your Xamarin.Forms project’s objects in runtime!

But if you’re using a 3rd party MVVM framework like Prism, they usually have their own Container registration, which we need to manually handle ourselves in a mocked run-time environment. On the bright side, it also gives us more flexibility of control, since we could register our own mocked services for Test environment, such as a Location Service! whereas we could return a mocked fake location data when we override the LocationService with our own FakeLocationService. 😉

Here we override the default App class in our Test project with necessary container registrations and store it in a singleton static object, so that we can access it anywhere in our test environment. Oh and alongside we’re initiating our Xamarin.Forms Mocks run-time as well!

Now its all ready to go! Pretty straight forward eh! let’s get down to business.. 😉

Hands on time!

So just to showcase this hands-on awesomeness, I’ve prepared a simple Xamarin.Forms project application, where you can create simple notes, attach location data, attach created date time values and store them locally, allowing you to view them at any time in a list of items. Quite a simple text-pad-like app.

I’ve named this project solution as, XFTextpadApp and it uses Prism as the MVVM framework.

As you can see above is a view of the project structure with the complete MVVM set up. Let me also share a bit of showcasing of the app and its features to give a more in depth context.

Here’s a little peek into features of this demo Xamarin.Forms Textpad app running on iOS!

In the Home page you can view the List of Texts you have saved. By clicking on a Text item in the Home page list you can view that Text item in detail in the View Text page. Then once you click the “New Text” Button it will take you to the New Text page where you can create and save new Texts…

In the New Text page you can create new Texts with a Title and Description of your Text and click “Save” button to save it with the Location and Time data attached to it.

Then you will be navigated back to Home page. In the Home page Text list you can delete saved Text by using the context menu as well…

Thanks to Xamarin.Forms we can deploy it directly to iOS, Android, and UWP as well! 😉

Now the App project is ready, we need to add Test project to it.

Let’s begin by adding the Test project to our Xamarin.Forms project, create a new folder in the solution, named as “Tests” and then right click on it -> Add -> Add New Project

Now this is where the choice is absolutely up to you, as to which testing framework to choose from. Just for this demo, I’m gonna use NUnit Test framework, hence I will select NUnit Test Project (.NET Core) template and create our test project…

I will be naming the test project as, XFTextpadApp.NUnitTests making sure to stick to the standard naming practices! You might want to pay some attention to the Project Path there as well, where as to make sure we set the path to be inside the “Tests” folder that we created earlier.

First thing first, add a reference of the host XFTextpadApp .NET standard project into our XFTextpadApp.NUnitTests project. Then we’re going to add our Xamarin.Forms Mocking library, Xamarin.Forms.Mocks.

Just to make sure we write some beautiful test code, let’s add Shouldly nuget as well. This is more of a personal choice 😉 or if you prefer you could use the default assertions of NUnit (NUnit.Framework.Assert), or which ever the test framework you have chosen to set up.

If all went well then you should see the references as above. Now that’s out of the way, next on let’s get into coding!

Create app instance…

You could directly use the existing App class instance inherited from the Xamarin.Forms project within our Test project environment, but in the case of using 3rd party MVVM frameworks, or even when you want to mock some test compatible services, such as a GPS location service!?, then you need to construct your own App instance that’s catered for the Test environment. Which is what we’re going to do in this step.

Something to note here is that, the way you construct your Test App instance is completely dependent on how you have constructed your Xamarin.Forms application, so try to duplicate it as much as possible.

Let’s start by creating the instance of our app for the test environment. This basically means we need to create App class’s instance with all the container registrations set up, similar to what we already have in our App.xaml.cs file. Let create a new class called TestApp in our XFTextpadApp.NUnitTest project root.

public class TestApp : PrismApplication
{
	public TestApp() : this(null) { }

	public TestApp(IPlatformInitializer initializer) : base(initializer) { }

	protected override async void OnInitialized()
	{
		...
		
		await NavigationService.NavigateAsync("NavigationPage/HomePage");
	}

	protected override void RegisterTypes(IContainerRegistry containerRegistry)
	{
		containerRegistry.RegisterForNavigation<HomePage>();
		...

		containerRegistry.GetContainer().RegisterType<HomePageViewModel>(new Unity.Lifetime.ContainerControlledLifetimeManager());
		...
	}
}

Now make sure to register your Pages, ViewModels and Services accordingly. Also notice that how I have set up the default start up navigation in the OnInitialized() method according to Prism.

Next the Hooks…

This is more like the helper class that we’ll be using to set up the necessary hooks for our test run time environment, such as instantiating the App instance object, and initialising MockForms. Here we’re going to keep a public static object of our App instance, which we will be using all across out tests cases. Let’s create a class called TestHooks

public class TestHooks
{
	public static TestApp App { get; private set; }

	[SetUp]
	public static void Setup()
	{
		Xamarin.Forms.Mocks.MockForms.Init();

		App = new TestApp();
	}

	[Test]
	public static void IsAppRunning()
	{
		Assert.NotNull(App);
	}
}

We’re using the [Setup] attribute of the NUnit framework to do the initiation of the App instance before each execution of tests. And we’re also adding a simple test in the same class to make sure the instantiation has happened properly without an issue, as you can see by the method IsAppRunning() which is decorated with the [Test] attribute of NUnit. We’ve made those hooking methods static because we are going to be accessing them in our test cases!

And since we have just added our first Test case, we could try and run it, where as if everything is set up properly, you should see your app instantiating well and our first test case is passing! 😉

And it all passes the test with green! lol 😀

If you can’t get this step to pass successfully, then there’s definitely something wrong with the Test App instance set up, so you might wanna look into the DI Container initialization and all.

Alright, but we’re not done yet!

One base for all…

Then we are one step away from creating our Test cases! 😀 so before that we need to create the Base class for our Test classes that would be containing those Test cases. So let’s create out BaseTest class in the root of the project…

/// <summary>
/// Base class for Test classes
/// </summary>
public class BaseTest
{
    /// <summary>
    /// Instance of the app
    /// </summary>
    public static TestApp App { get; private set; }
 
	[SetUp]
	public void Setup()
	{
		TestHooks.Setup();

		App = TestHooks.App;
	}
     
    ...
}

It’s pretty simple, but its important to abstract a base layer for our test classes to dump all the repetitive test steps to reduce duplication of test code. Here we’re simply retaining the TestApp instance through the TestHooks class we just created before, and that instance will be useful for our Test cases later. 😉

On to the final step!

Creating the Tests…

Now that all is set up and ready to go, let’s create our actual Tests. But first create a “Test” folder in the root of our XFTextpadApp.NUnitTest project.

If everything is well set up until now, then it should look like the above structure.

Let’s add a new class to the Tests folder, but as for the name, you could use anything as you wish according to your preferred naming convention, but I would usually prefer something like “<PageName>Tests”, keeping the Page as the objective for the set of test cases. So let me create HomePageTests class, which will inherit from the BaseTest class.

Next we’re going to create the methods that actually indicates the Test cases, let’s take an example such as,

Scenario:
First time I launch the app
I am Navigated to the Home page
I see an empty list of data
I see a label indicating empty data

We could create the Test case for the above scenario as shown below…

[TestFixture]
public class HomePageTests : BaseTest
{
	/// <summary>
	/// Launching the app for the  first
	/// time and navigating in to Home page
	/// </summary>
	[Test]
	public void AppLaunchingFirstTimeTest()
	{
		// Test steps here
	}
}

As you can see I’ve named our test case method as, AppLaunchingFirstTimeTest, considering the gist of the test scenario that we’re targeting. In fact providing a proper name for your test cases are quite important, hence it makes it easier to read and understand, as well as for future maintenance.

Now Thanks to the Xamarin.Forms.Mock, we’re able to pull objects from Xamarin.Forms UI elements and the DI Container to construct a perfect test case for any given scenario. You can access any Xamarin.Forms elements through the App object as usual to check for any values you require.

So with that in mind, let’s write the Test steps for our test case..

[Test]
public void AppLaunchingFirstTimeTest()
{
	// Is the app running
	App.ShouldNotBeNull();
	
	// Retrieve Navigation Stack
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	
	// Am I in the Home page
	navigationStack.Last().BindingContext.GetType().Name.ShouldBe(nameof(HomePageViewModel));

	// ListView should be empty
	App.Container.Resolve<HomePageViewModel>().TextList.Count.ShouldBe(0);

	// Empty ListView Label Displayed
	App.Container.Resolve<HomePageViewModel>().IsEmptyTextList.ShouldBe(true);
}

Let me explain step by step…

First thing we need to do is to make sure the App is running, so in our Test case, let’s access the TestApp instance in our BastTest class, and use Shoudly’s extension to check for null or not state.

Then we access the Navigation stack through the App’s Navigation object, which we’re going to check for the current active Page, through the BindingContext type as you can see.

Finally we check if the ListView is empty by accessing the TextList collection object inside the Homepage ViewModel and we do the same for checking if the Empty list indicator label is visible as well. 😉

There you go, you’ve just created your first UnitTest case for your Xamarin.Forms app!

Mixing it up!

Since our Xamarin.Forms runtime is mocked, you can mix and mingle among the actual UI Elements of your App and DI Container objects.

You see in the previous demo code, how I’ve accessed NavigationStack of the app using App.MainPage instance, as well as you can see how I’m using the Current active Page instance to access its child element, which is a Label element and check its rendered value as follows…

// Get the value in ViewModel
var viewingTextItem = 
   App.Container.Resolve
      <ViewTextPageViewModel>().TextItem;

// Check TextTitle Label value
var textTitleLabel = 
((Label)((Grid)
	((ViewTextPage)GetCurrentPage())
		  .Content).Children.First());
textTitleLabel.Text.ShouldBe(viewingTextItem.TextTitle);

You can see how I have retrieved the Label element by traversing through the Page object, and comparing the results with the value I’ve retrieved from the ViewModel object. So you can mix and match these two approaches in harmony for implementing complicated test cases easily!

App Properties…

Thanks to the mocked Xamarin.Forms runtime we’re able to access most of its functionality as it is in our test cases, which goes to the Application Properties as well.

As an example here I am clearing out my Application Properties on TearDown event after any given test case is executed.

// Clear App properties in memory
Application.Current.Properties.Clear();
await Application.Current.SavePropertiesAsync();

Navigation…

The Navigation in my demo project is handled by Prism, which uses the default Xamarin.Forms navigation underneath it. The Xamrin.Forms.Mock seem to be handling it pretty well as well. So you wouldn’t be need to do any special handles in the test code.

[Test]
public void NavigatingToNewTextPageTest()
{
	...

	// Navigating to New Text page
	App.Container.Resolve<HomePageViewModel>()
		.GoToNewTextPageCommand.Execute();

	// Am I in the New Text page
	GetCurrentPage().BindingContext.GetType()
		.Name.ShouldBe(nameof(NewTextPageViewModel));
}

Hence I could simply call up the usual Navigation Commands that I use on the Button element, here in my unit test code as well. 😉 Navigation will behave as expected!

Mockin’ Services!

Like I mentioned before if you have a Service which relies on platform specific features, then you need to mock those services instances in your testing environment. In my demo I’m using a LocationService, which I have mocked in the my test code as follows…

/// <summary>
/// Mocked Location Service
/// </summary>
public class MockLocationService : ILocationService
{
	public Task<Location> GetLocation()
	{
		// Mock location data
		return Task.FromResult(new Location(0.11111, 0.22222));
	}
}

Also do not forget registration in the TestApp instance which I showed before…

// register mocked ILocationService
containerRegistry.RegisterSingleton
      <ILocationService, MockLocationService>();

Now with that, every time the actual App code try to resolve the LocationService it will get the MockedLocationService object and use its mock data during the test executions. You could also use an awesome library like moq for mocking services and data as well.

Fake em!

If you have actual API calls going in or out of your app, you shouldn’t use them in your unit tests, hence it could cause for slowing down the test executions, and would consume a lot of resources, keeping in mind tests are meant to be executed repeatedly.

So you need to create Mocked Services for those API bound calls, with fake data sets attached to them, so in test code, they would be using the fake data or fake responses instead. 😉 Another reason to use moq library! There are others as well, Faker.net and Bogus are also popular!

Reduce the repetition!

There could be repetitive steps in these Unit Test cases, therefore you can improve the code by extracting out those common repetitive test steps into separate methods or extensions.

public class ViewTextPageTests : BaseTest
{
	[Test]
	public void NavigatingToViewTextPageTest()
	{
		...
		// Create a new Text item
		var textItem = CreateSampleTextItem();
		...
	}

	[Test]
	public void ViewTextDetailsAndGoBackPageTest()
	{
		...
		// Create a new Text item
		var textItem = CreateSampleTextItem();
		...
	}

	public TextItem CreateSampleTextItem()
	{ ... }
}

As an example in both my test cases above, I need to create a new TextItem object, hence I’ve extracted it out to a common method which is used in both, reducing the repetition.

Here’s another example where I’ve created the following helpers in BaseTest class,

/// <summary>
/// Returns the active Page
/// </summary>
/// <returns></returns>
public static Page GetCurrentPage()
{
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	return (Page)navigationStack.Last();
}

/// <summary>
/// Returns the active ViewModel
/// </summary>
/// <returns></returns>
public static ViewModelBase GetCurrentViewModel()
{
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	return (ViewModelBase)navigationStack.Last().BindingContext;
}

Allowing me to retrieve the current active Page or the ViewModel directly.

Before and After Test Case…

Most Testing frameworks provides you with Before and After hooks for a given Test Case, where as in my demo, NUnit provides [Setup] and [TearDown] subsequently.

public class BaseTest
{
	[SetUp]
	public void Setup()
	{
		// Set up steps
	}
	
	[TearDown]
	public async Task TearDown()
	{
		// Teardown steps
	}
     
    ...
}

As I’ve shared before I’ve set up the [Setup] attribute in the BaseTest class, allowing me to reinstantiate TestApp instance before each Test Case executes.

[TestFixture]
public class HomePageTests : BaseTest
{
	[SetUp]
	public new void Setup()
	{
		// Page specific Setup
	}

	...
}

You can override the set up in your Page specific test class and set up the required customized setting up as well. This was you can also share data across the whole flow of the page test scope without resetting the TestApp instance. Quite a handy trick to keep in mind! 😉

Finalizing…

So all of this awesomeness is committed into my github repo:

Github repo:
github.com/UdaraAlwis/XFWithUnitTest

Since I took the Page based pattern for organising my unit test cases, here’s the set of test classes I ended up creating for each page.

Under the Test folder I’ve placed all my test class, but you can restructure this hierarchy as you please, even have sub folders containing different sets of test as well… 😉

So in my demo below are the test classes that represents each page…

  • Home Page : HomePageTests
  • New Text Page: NewTextPageTests
  • View Text Page: ViewTextPageTests

Maintaining a good readability of your test cases can definitely benefit you in the long run! 😉

Once you open up your Test Runner, either built in Visual Studio Test Runner or even a 3rd Part Tool like Resharper Test Runner, all your tests should be discoverable as below…

All the UnitTest classes are shown with all the test cases in them, ready to be executed! 😉

Demo time!

So let’s fire up these UnitTests…

Woah! What a satisfying thing to watch eh! 😀

Github repo:
github.com/UdaraAlwis/XFWithUnitTest

Once again feel free to grab it on my github! 😉

Conclusion

You can easily implement UnitTesting in Xamarin.Forms just like any other .NET project, and there are plenty of ways to do it. Mocking Xamarin.Forms runtime and implementing our UnitTests on top of that, is a great way to ensure that our tests are executing as close as it gets to the real app runtime. You can easily integrate Xamarin.Forms.Mocks library with pure Xamarin.Forms or along side any other MVVM Library to set up your UnitTests!

We need to make sure to follow best practices and maintain clean, easy to read, test code across all our UnitTesting implementations. You can take different approaches to organising your test cases, while I personally believe Page-Context based pattern provides more clarity.

 Hope this documentation out of my own experience helps any of you fellow Xamarin.Forms devs out there! Share the love! 😀 Cheers yol!

Playing Audio with the MediaManager Plugin for Xamarin.Forms!

Let me show you how to play Audio in Xamarin.Forms across Android, iOS and Windows UWP using the super easy plug and play MediaManager Plugin.

So you wanna play Audio in your Xamarin.Forms app? Stream an audio file over the internet or stored locally in your device Gallery? Listening to songs or podcasts even when the app is in background mode or device is locked away? Then you’re in the right place! 😉

So playing audio in a music player style sounds like a complete nightmare for a cross-platform framework like Xamarin.Forms, but thanks to this incredible MediaManager plugin, just a breeze of work to deploy across Android, iOS and Windows UWP environments.

MediaManager Plugin!

Long time back I remember reading up the article in Xamarin Blog, Play Audio and Video with the MediaManager Plugin for Xamarin, https://devblogs.microsoft.com/xamarin/play-audio-and-video-with-the-mediamanager-plugin-for-xamarin/

Back then, I remember there were no direct support for Xamarin.Forms itself, but now we do, with simple plug and play capabilities in this MediaManager Plugin!

Github:
github.com/Baseflow/XamarinMediaManager
Nuget:
nuget.org/packages/Plugin.MediaManager/

Please feel free to take a look at their official github page, and the implementation code if you’re interested in digging down deep.

Backstory…

I was lucky enough to stumble upon the opportunity to explore the implementation of Audio playback in one of the Xamarin.Forms project I’m working on recently. The core feature of that app was to play audio sources that are stored online, with continuous app background playback enabled, similar to a music player or podcast player.

The first thing came to my mind was the MediaManager plugin. So I tried it out following the Github page and the Xamarin blog article.

But unfortunately I came across a lot of issues, trying to set up in a fresh Xamarin.Forms project itself, even though I followed the steps to the detail. So I had to scrape through old forums and sample projects off of Github, for a series of trial and error, figuring out the proper set up.

It turns out all the articles and documented setup guidelines are mostly outdated, and the Plugin has gone through so much new changes and improvements over the years. So I thought of sharing my experience on setting up the MediaManager Plugin for Xamarin.Forms, step by step from scratch! 😉

Sneak Peek!

Let me share a little sneak peek into the cute little demo I built…

That’s the beauty with a whole bunch of awesome features powered by MediaManager Plugin!

I’ve published this whole awesome demo up in my github repo,

Github repo:
github.com/UdaraAlwis/XFAudioPlayer

Feel free to take a look for a headstart before we begin! 😉

Setting it up!

Let’s begin with the set up of the Plugin with your Xamarin.Forms project. So I’m going to be using a fresh out of the box Xamarin.Forms project with the version 1.5.3.2, which is the latest updated version as of now.

Open up the Nuget Package Manager, on the Solution node, and search for Plugin.MediaManager.Forms package, and make sure to install it on your .NET Standard project node only, as shown below.

As of the writing of the blog post, I would recommend sticking to v6.94 version of the plugin as you can see above. The latest version had given me some run time issues.

It is important that you install the plugin only in the .NET Standard project, hence we’re using the Xamarin.Forms related package of the MediaManager plugin.

Also you may have noticed, there are multiple other packages related to MediaManager plugin, which caters for different purposes such as Plugin.MediaManager for Xamarin Native, Plugin.MediaManager.Reactive for Reactive Extensions, Plugin.MediaManager.ExoPlayer for ExoPlayer based implementations and so on.

Feel free to play around with them if you ever come across the need for such. Next we need to configure the initiation of the plugin.

No initiation setup required in platform projects, but in the App.xaml.cs of your Xamarin.Forms project node,

public partial class App : Application
{
	public App()
	{
		InitializeComponent();

		CrossMediaManager.Current.Init();

		MainPage = new NavigationPage(new MainPage());
	}
}

Oki doki, you’re good go!

Let the coding begin!

It’s actually easy to use Plugin.MediaManager in Xamarin.Forms! It provides a Singleton access to the complete player plugin instance, CrossMediaManager.Current, so you get full control of all the properties, behaviours and features in one place across the entire app context.

First, Play Audio!

Just hit the Play() for your audio as simple as below…

var audioUrl = "https://ia800605.us.archive.org/32/items/Mp3Playlist_555/Daughtry-Homeacoustic.mp3";
await CrossMediaManager.Current.Play(audioUrl);

Yes! it’s that simple. Check here the full list of Play() method overrides available: https://github.com/Baseflow/XamarinMediaManager#other-play-possibilities

Player Features!

Any Audio player should have the basic features such as Auto Play, Shuffle, Repeat mode and so on yeah? 😉

CrossMediaManager.Current.ShuffleMode = ShuffleMode.All;
CrossMediaManager.Current.PlayNextOnFailed = true;
CrossMediaManager.Current.RepeatMode = RepeatMode.All;
CrossMediaManager.Current.AutoPlay = true;

CrossMediaManager.Current instance provides you direct access to all those features you need.

Play, Pause, Stop, Resume?!?

Yeah well those key features of are easily accessible, and then some! 😉

var result = await CrossMediaManager.Current.Play();
var result = await CrossMediaManager.Current.Pause();
var result = await CrossMediaManager.Current.Stop();

All those returns a bool indicating the results of the action.

var result = await CrossMediaManager.Current.PlayPrevious();
var result = await CrossMediaManager.Current.PlayNext();

How about if it’s playing, then pause, it its pause, then resume play?

await CrossMediaManager.Current.PlayPause(); 

Yeah it’s got a feature for that too! 😀 which I’ve also used in my demo.

Step and Seek!

Yep, not hide and seek for sure…

// step forward or backwards
await CrossMediaManager.Current.StepForward();
await CrossMediaManager.Current.StepBackward();  

// seek to a specific position          
await CrossMediaManager.Current.SeekTo(timespan);

You can even adjust the default value for stepping actions using, CrossMediaManager.Current.StepSize and then directly seek to a specific location of the audio using SeekTo with a TimeSpan value! 😉

Access Media data…

You can load the metadata or media details of the audio source as follows,

IMediaItem currentMediaItem = await 
         CrossMediaManager.Current.Play(audioUrl);

Whenever you call Play() method it will return IMediaItem object which contains all the metadata regarding the audio source, such as Title, Artist, Album, Year, and etc…

Sometimes the retrieval of the metadata could take a while depending on the media source or the run time platform, so you can subscribe to the MetadataUpdated event to retrieve the data once they’re extracted.

var mediaItem = await CrossMediaManager.Current.Play(audioUrl);
mediaItem.MetadataUpdated += (sender, args) => {
	var title = args.MediaItem.Title;
};

This might be a bit troublesome, subscribing and unsubscribing, so you could access the metadata from the Queue instance directly, CrossMediaManager.Current.Queue.Current

IMediaItem currentAudioItem
       = CrossMediaManager.Current.Queue.Current;

Or directly as follows..

var title = CrossMediaManager.Current.Queue.Current.Title;
var artist = CrossMediaManager.Current.Queue.Current.Artist;
var album = CrossMediaManager.Current.Queue.Current.Album;
...

You can bind your UI properties to these values, once you execute Play() on your audio.

Now that I mentioned Queue, let’s get into that next…

Queue it up!

MediaManager simplifies a whole bunch features for you, and one of them is the Queue, which you can access directly through the instance, CrossMediaManager.Current.Queue which provides the IMediaQueue object. This one carries a whole bunch of awesomeness that you can use for your own player.

var currentMediaItem 
          = CrossMediaManager.Current.Queue.Current;
var nextMediaItem 
          = CrossMediaManager.Current.Queue.Next;
var previousMediaItem 
          = CrossMediaManager.Current.Queue.Previous;

In my demo I’m using the the override of passing a List of media urls to be played in a queue,

var songList = new List<string>() {
	"https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Yung_Kartz/July_2019/Yung_Kartz_-_02_-_Levels.mp3",
	"https://files.freemusicarchive.org/storage-freemusicarchive-org/music/Creative_Commons/Ketsa/Raising_Frequency/Ketsa_-_08_-_Multiverse.mp3",
	...
};

var currentMediaItem = 
	await CrossMediaManager.Current.Play(songList);

I could easily access it using the CrossMediaManager.Current.Queue.MediaItems

ObservableCollection<IMediaItem> mediaItemsInQueue 
	= CrossMediaManager.Current.Queue.MediaItems;

It returns an ObservableCollection of the MediaItems that I have queued up.

var mediaItem =
	CrossMediaManager.Current.Queue[index];

Just like that you could retrieve a specific item from the Queue as well.

Add to Queue…

To add an item directly to the Queue using the Queue.Add() method but, you need MediaItem object of that audio source. You can use the MediaExtractor object to create the MediaItem object you require and add that to the Queue as follows…

var generatedMediaItem =
	await CrossMediaManager.Current
	.Extractor.CreateMediaItem(mediaUrl);
	
CrossMediaManager.Current.Queue.Add(generatedMediaItem);

Now that new audio source will be added to the bottom of the Queue waiting to be played..

Play from Queue…

Use PlayQueueItem() to play an item from the Queue…

// from index
var isSuccess = 
     await CrossMediaManager.Current.PlayQueueItem(index);

// pass in the MediaItem
var isSuccess = 
      await CrossMediaManager.Current.PlayQueueItem(mediaItem);

Or better yet, pass in the MediaItem itself from the queue, it will return a bool whether it was found in the queue and started playing or not.

Player State matters!

You might say, Play this, Play that, but how do you know if it’s actually playing or not? even before that is it still loading the media source? or still buffering the data?

You can easily monitor this by subscribing to StateChanged event,

CrossMediaManager.Current.StateChanged += Current_OnStateChanged;
...

private void Current_OnStateChanged(object sender, StateChangedEventArgs e)
{
	if (e.State == MediaPlayerState.Playing)
	{
		// playing mode
	}
}

MediaPlayerState enum provides us 6 states of the media playback,

  • Loading
  • Buffering
  • Failed
  • Playing
  • Paused
  • Stopped

You could also check the state suing extension methods,

var result = CrossMediaManager.Current.IsPlaying();
var result = CrossMediaManager.Current.IsBuffering();
var result = CrossMediaManager.Current.IsStopped();

These nifty little extensions returns a boolean value with regards to the state.

Better yet you also got a singleton property you can bind to,

MediaPlayerState state = CrossMediaManager.Current.State;
if (state == MediaPlayerState.Playing)
{
	// playing mode
}

Yep multiple flexible ways! 😉 There’s another useful extension method, CrossMediaManager.Current.IsPrepared() which allows you check if the Player is already set up with Audio sources, and is running.

In my demo app I use this in the home page where I need to make sure the Player instance is already initialised or not with audio sources every time I activate the app from background.

protected override async void OnAppearing()
{
	base.OnAppearing();

	if (!CrossMediaManager.Current.IsPrepared())
	{
		await InitPlay();
	}
}

Pretty handy!

Useful Events…

There are plenty useful events you can subscribe to in order to monitor different properties and behaviors, https://github.com/Baseflow/XamarinMediaManager#hook-into-events

CrossMediaManager.Current.StateChanged
	+= Current_OnStateChanged;
CrossMediaManager.Current.PositionChanged
	+= Current_PositionChanged;
CrossMediaManager.Current.MediaItemChanged
	+= Current_MediaItemChanged;

I for one am subscribing to these events in my demo app, for monitoring Player State changes, current Media playback Position changes, current MediaItem Change. These events provides specific types of EventArgs parameters which you can use in the event methods.

Keep track of Time!

It’s important to keep track of the playback time data such as, Position and Duration of the audio that you’re playing. In my demo I use the PositionChanged event and Position, Duration properties to update the UI accordingly to show the user playback time data.

TimeSpan currentMediaPosition
	= CrossMediaManager.Current.Position;
TimeSpan currentMediaDuration
	= CrossMediaManager.Current.Duration;

Here’s how I update some of the UI elements based on the Position and Duration changes..

var formattingPattern = @"hh\:mm\:ss";
if (CrossMediaManager.Current.Duration.Hours <= 0)
	formattingPattern = @"mm\:ss";

var fullLengthString =
	CrossMediaManager.Current.Duration.ToString(formattingPattern);
LabelPositionStatus.Text =
	$"{CrossMediaManager.Current.Position.ToString(formattingPattern)}/{fullLengthString}";

SliderSongPlayDisplay.Value =
	CrossMediaManager.Current.Position.Ticks;

All kinds of cool UI bits you could implement with those data! 😀

Loading Local Audio files..

Now this is a cool little feature I decided to implement. My demo app will be able to load local Audio files from the local file system, into the app, and play! 😉

This should work seamlessly across Android, iOS and UWP. So I’m going to be using another nifty little library called, FilePicker-Plugin-for-Xamarin-and-Windows, which will simplify the whole file picking set up much easier.

I need to allow only MP3 audio file types to be picked in the app, so let’s define that first,

string[] fileTypes = null;
if (Device.RuntimePlatform == Device.Android)
{
	fileTypes = new string[] { "audio/mpeg" };
}

if (Device.RuntimePlatform == Device.iOS)
{
	fileTypes = new string[] { "public.audio" };
}

if (Device.RuntimePlatform == Device.UWP)
{
	fileTypes = new string[] { ".mp3" };
}

So based on the platform we need to set appropriate filter values before we execute picking. Next let’s pick the file using our FilePicker library and load into our media queue…

var pickedFile = await CrossFilePicker.Current.PickFile(fileTypes);
if (pickedFile != null)
{
	var cachedFilePathName = Path.Combine(FileSystem.CacheDirectory, pickedFile.FileName);

	if (!File.Exists(cachedFilePathName))
		File.WriteAllBytes(cachedFilePathName, pickedFile.DataArray);

	if (File.Exists(cachedFilePathName))
	{
		// Create media item from file
		var generatedMediaItem =
			await CrossMediaManager.Current
			.Extractor.CreateMediaItem(cachedFilePathName);
		// Add media item to queue
		CrossMediaManager.Current.Queue.Add(generatedMediaItem);
	}
}

Once the user picks the file, we get the FileData object. I’m writing that file object to the app cache directory with the help of Xamarin.Essentials.FileSystem helpers.

It is better to load the file into memory from the cache directory hence some platforms could flag directly accessing files outside the app directories as a suspicious activity and eventually break the flow of the app.

Once we store the file safely in App Cache directory, we load it into our app, using the Extractor to create the IMediaItem object and pass it on to the MediaManager’s queue. 😉

Well that’s all the tidbits I got to share regarding the little demo I built!

Demo time!

So I built a simple demo audio player which will be playing MP3 audio sources stored online, and as an extra functionality, it will allow us to play locally stored MP3 files as well.

Github repo:
github.com/UdaraAlwis/XFAudioPlayer

The first page, which is the Home page, will host the main Audio Play feature, such as Play/Pause, Next, Previous and so on. Then another page which will display the current audio Queue loaded into the Player. The same page will have the functionality to load local MP3 files and add to the Queue on the go…

Let’s fire it up and see the magic! 😉

Here we got iOS working like a charm! Well I’m not able to showcase the background or lock screen activity since I’m running it on the iOS Simulator and I don’t have an actual iPhone 😛

Next we got Android, working marvelously… 😉 Here I’m showcasing the full length of features including continuous playback on app background state as well!

Here’s the good old UWP Windows, working like a breeze! App will continue playing even if the app is minimized or device is locked as expected for background playback state! 😀

Remember I told yol about the extra little feature I added, being able to load local Audio files!? here we have it, working like a charm across iOS, Android and UWP Windows…

Let me flex a little bit more on the continuous background audio playback… 😉

As you can see on Android, we got direct access to media playback while the app is on background mode, and the audio is still playing even on lock screen…

Then on UWP Windows runtime we got the same exact features, it even complies with device native media buttons on the laptop keyboard!

Oh also on Windows 10 lock screen at the bottom right corner… 😉

Woot! Woot! 😀

Issues…

Even though I managed to build this cool little demo, with the help of MediaManager Plugin, I did notice some issues with it.

On UWP Windows runtime, it wasn’t loading Audio meta data for sources which are stored online. As in for any internet audio source, it would not be able to load the meta data of it. I saw some issues raised in the github page regarding this. So for now, just during UWP run time, we should rely on manually loading the audio source metadata, hopefully until the issue is fixed. Although my guess is, it could be a Windows File system security restriction!?

Another issue is that on Android, if the app is killed manually while its in background, the audio playback will stop it self. Usually this shouldn’t happen as far as I’ve seen with other Audio player apps. There’s a pending issue logged in github for this as well.

Well that was pretty much it for the issues I noticed!

Conclusion

Well it was certainly fun little walk down the memory lane, apart from the trouble I had to go through following out of sync documentation. lol but it was worth it. It’s incredible how far MediaManager Plugin has come so far since the early days of Xamarin, and kudos to the developer @martijn00

MediaManager Plugin takes away all the pain of dealing with platform native handling of audio files and provide us direct access to great audio features. If you ever come across implementing an audio player app, this would be a great plugin to consider. Hope this little documentation of my experience with it was helpful for anyone out there! 🙂

Share the love! 😀 Cheers yol!

So I took up on TravelMonkey, the Xamarin + Cognitive Services Challenge!

Let me share my little adrenaline filled panic adventure into earning some awesome Xamarin Swag! from the Xamarin + Cognitive Challenge hosted by Microsoft, the TravelMonkey Challenge! 😀

Well it’s come to 2020, in the middle of a pandemic, a lock down, and it’s been a while since I took up on an actual challenge outside my work and personal coding experiments! Then I suddenly came across this little challenge posted by Microsoft, TravelMonkey – the Cognitive Services + Xamarin Combo Challenge! (https://devblogs.microsoft.com/xamarin/cognitive-services-xamarin-challenge/)

Backstory…

As usual, the first thing I checked, what’s in it for me, you know what I mean! 😉 YES! they had promised some awesome Microsoft swag! Xamarin t-shirts, monkeys, and stickers!?! Say no more, I was in! 😀 well at least I thought to myself… their Submission deadline was April 30, 2020 11:59 PM PDT!

The days went by, one by one, without even any second thoughts, yeah I’d do it tomorrow, or day after or some time… I’ll get it done!

Then suddenly, it was 29th April, the Friday night, oh shoot! tomorrow’s the deadline for submission of the awesome TravelMonkey challenge! Yeah well I could say it was my own procrastination that got me in that situation, I had waited till the last day!

Procrastination is bad!

Just like in that GTA San Andreas scene, in my head I was like, “Ah sh*t, here we go again!” it was literally a moment of panic, and I was the fence about giving it up. But then it was Friday night, the day I usually watch a good night movie and fall asleep to wake up very late on Saturday! 😦

But then again, it was middle of a pandemic lock down, and I haven’t really had this kind of a fun challenge in a while, so I thought of pulling an all nighter and getting it done! at least something worth while before the next 24 hours ended… 😮

At this point, I didn’t have a plan of what I’m going to be building or expand up on, so I thought of simply exploring the current implementation and figure out where are the points in which I could improve as for the challenge. Once again, it was a bad idea to start working on it, at a time when it was less than 24 hours before the submission! lol 😀

Sneak Peek!

But at the end, here the beauty I ended up building…

I know right.. gorgeous!

Yeah well behind all that eye-candy glamour there was a painful sleepless all-nighter experience, waiting to be unraveled…

Getting started…

So first, I forked the github repo from https://github.com/jfversluis/TravelMonkey into my own github repo: https://github.com/UdaraAlwis/TravelMonkey and set up the Azure Cognitive services in Free tier with the following,

  • Azure Computer Vision
  • Bing Translation
  • Bing Image Search

Then I got the API keys and hooked up into the Xamarin Mobile app project.

New Featurettes!

This is a travel related app! even though it is fictional. lol So I wanted to think of it as being used by smart Monkeys like us, who would love to see beautiful scenic photos of the top travel destinations in the world.

Why stop there? I should allow the users to search for a destination and view the top scenic photos of that destination, as a little cherry on top! 😉

Also how about letting the user translate any text into any language they choose? That would definitely come in handy for any traveller!

Bing Image Search FTW!

So I picked up the most visited destinations by international tourist arrivals data from Wikipedia, https://en.wikipedia.org/wiki/World_Tourism_rankings and hooked it up into the Bing Search Service to load images of those destinations. Each destination would be taken up with 10 images and we would randomize through them in the Home page carousel.

var client = new ImageSearchClient(
new Microsoft.Azure.CognitiveServices.Search.
ImageSearch.ApiKeyServiceClientCredentials(ApiKeys.BingImageSearch));

var imageResult = await client.Images.
SearchAsync(
	$"{destination} attractions", 
	minWidth: 500, 
	minHeight: 500, 
	imageType: "Photo", 
	license: "Public", 
	count: 10, 
	maxHeight: 1200, 
	maxWidth: 1200);

See how I modified the Bing Image search query there, {destination} attractions where as it would be executed as “France attractions”, “Thailand attractions”, and etc. So just like that I refined the search terms for scenic tourist photos from Bing Images.

Destination scenic Gallery!

I decided to add a travel destination Gallery page, consisting of scenic travel photos from Bing. User would be able to pick a destination from a presented list of countries in the Home page itself, and then navigate to its Gallery page to view the top 10 most scenic photos from Bing.

Here I did a little trick to load a list of countries in C# by tapping into CultureInfo object provided by .NET framework, pretty handy!

private static List<string> GetCountries()
{
	List<string> countryList = new List<string>();

	var getCultureInfo = CultureInfo.GetCultures(CultureTypes.SpecificCultures);

	foreach (var getCulture in getCultureInfo)
	{
		var regionInfo = new RegionInfo(getCulture.LCID);
		if (!countryList.Contains(regionInfo.EnglishName))
		{
			countryList.Add(regionInfo.EnglishName);
		}
	}

	return countryList;
}

This would return the list of countries in the world which I will be presenting to the user to choose from! I will use the Bing Image Search that I had already modified to load the scenic travel images set on the go.

Bing Translation FTW!

So I thought of adding some improvements to the Translation features, where currently they had a pre-set of languages they would translate to given the input text. I wanted to make it completely dynamic, by getting the list of languages available in Bing Translation service, and letting the user pick the languages they want to translate to.

Here’s how I got the list of supported languages Bing Translation,

public async Task<List<AvailableLanguage>> GetLanguageList() 
{
	string endpoint = ApiKeys.TranslationsEndpoint;
	string route = "/languages?api-version=3.0";

	using (var client = new HttpClient())
	using (var request = new HttpRequestMessage())
	{
		...
		request.RequestUri = new Uri(endpoint + route);
		// Send request, get response
		var response = client.SendAsync(request).Result;
		...
	}

	List<AvailableLanguage> availableLanguages = new List<AvailableLanguage>();
	foreach (var item in translationStatsResult.Translation)
	{ ... }
	return availableLanguages;
}

Once I got the available languages list, I would present them to the user to pick from for translating their input text. But during the app’s first time launch I would randomly pick 5 languages and show the translations.

So here’s how I extended the Translation service call with the dynamic request language list,

public async Task<List<AvailableTranslation>> 
TranslateText(string inputText, List<AvailableLanguage> listOfLanguages)
{
	// build the translate url chunk
	string requiredTranslationsString = "";
	foreach (var item in listOfLanguages)
	{
		requiredTranslationsString = requiredTranslationsString + $"&to={item.Key}";
	}
	
	...
	request.RequestUri = new Uri(ApiKeys.TranslationsEndpoint + "/translate?api-version=3.0" + requiredTranslationsString);
	... 
	
	translations.Add( new AvailableTranslation()
	{
		InputLanguage = bestResult.DetectedLanguage.Language,
		InputText = inputText,
		TranslatedLanguageKey = t.To,
		TranslatedLanguageText = t.Text,
		TranslatedLanguageName = MockDataStore.Languages.FirstOrDefault(x => x.Key == t.To).Name,
	});
	
	return translations;
}

I’m dumping them all into a list of AvailableTranslation objects which I will be unpacking in the UI for displaying the results of the input text translation.

Caching a bit of data!

Now this is something I had kept till the last minute, hence I couldn’t complete it as I expected, but I still managed to store some data in the app memory during run time to reduce repetitive duplicate queries to Bing services, which will also help me reduce the free tier quota usage.

I managed to store the list of destination scenic image result data and translation text in memory as a simple static singleton data object.

Emoji Support 😀

It would be nice to have some Emoji support for our text labels in the app, I thought. So I added it with the following nice little snippet I came across, https://github.com/egbakou/EmojisInXamarinForms

So with that nice little snippet I could insert emojis into a text and bind them to any Label element in Xamarin.Forms, nice and easy!

Title = 
$"Something went wrong 
{new Emoji(0x1F615).ToString()} 
Here is a cat instead!"

It will display the given emoji natively to the run time platform hence we’re using unicode representation of that emoji! 😉

No more icon files!

I really don’t like using physical image files for representing icons, so I got rid of them and introduced full Font Awesome based icons to the entire app. Setting it up in Xamarin.Forms is pretty easy now!

[assembly: ExportFont("fa-regular.otf", Alias = "FontAwesomeRegular")]
[assembly: ExportFont("fa-solid.otf", Alias = "FontAwesomeSolid")]

Like this label that shows a little globe icon using Font Awesome!

<Label
	Margin="0,0,12,0"
	FontFamily="FontAwesomeSolid"
	FontSize="20"
	Text=""
	TextColor="Gray"
	VerticalOptions="Center" />

Yeah Font Awesome is pretty handy!

https://montemagno.com/xamarin-forms-custom-fonts-everywhere/
https://dev.to/codingcoach/using-font-awesome-in-xamarinforms–3mh

Fix Android Status bar…

I know its annoying to deal with Android Status bar styling, and most of the time devs don’t even bother fixing it accordingly to their app theme. They end up leaving the ugly blue color bar at the top of the app.

But I wanted to make it right. May be I am too much of a perfectionist! 😛

<resources>
    <style name="MainTheme.Base"
			parent="Theme.AppCompat.Light.DarkActionBar">
        ...
        <item name="colorPrimary">#bfbfbf</item>
		...
        <item name="colorPrimaryDark">#d9d9d9</item>
        ...
        <item name="colorAccent">#808080</item>
		...
    </style>
</resources>

So I updated the Android Status bar styling values accordingly to my intended color scheme for the app.

PancakeView is yummy!

Yo this right here is a gem, such an awesome element to have in your app, provides loads of features and customization. https://github.com/sthewissen/Xamarin.Forms.PancakeView

It’s super simple to use, where I’ve used it as a container for many elements to provide a beautiful Shadow effect.

<yummy:PancakeView
	Margin="7"
	BackgroundColor="White"
	CornerRadius="20,0,0,40"
	HasShadow="True">
	<Grid Margin="0">
		<Image Aspect="AspectFill" Source="{Binding ImageUrl}" />
	</Grid>
</yummy:PancakeView>

I’ve used this beauty across the entire app in all pages to give a gorgeous gradient effect of Page background as shown below…

<yummy:PancakeView
	BackgroundGradientAngle="40"
	BackgroundGradientEndColor="White"
	BackgroundGradientStartColor="#d9d9d9">
	<Grid>
	...
	</Grid>
</yummy:PancakeView>

I’m so glad I came across this awesome nugget thanks to this challenge! 😀

Beautify XAML…

One thing I noticed in the original project was that the XAML wasn’t properly formatted and it was inconsistent with different tabs and spacing.

I would recommend using any XAML formatting tool in Visual Studio like XAMLStyler which automatically formats your XAML properly while you code. Something nice to have I assume. 😉

Let me make it prettier…

On top of my head, I did not like the UI, not at all. Not blaming the original devs, who’s done a great job putting it together, but I wanted to re-skin it my way, and sprinkle a bit of eye-candy awesomeness… 😉

One thing I love for sure, is building sleek, responsive, minimalistic and yummy looking Mobile App UIs. So that’s what I did. 😀 I decided to implement a minimalistic unified-white color based gradient-ized sleek UI, which called for a whole bunch of restructures in the UI.

So I changed all the color schemes they used and replace them with a white and dark-gray based gradient style in almost all the elements across the app.

Let’s look at those one by one…

Gradient-zing!

Who doesn’t love some good old gradient effects, at least when its well done!

Thanks to the PancakeView we can now easily add this effect to Xamarin.Forms elements, which I have used extensively in my UI design changes as well…

Here’s one example where I modified the AddPicture page with my new color scheme.

Splash it up!

One of the first things I wanted to get rid of was the original splash screen, I did not like it at all, and it was honestly scaring to see a cute little monkey exploding in a high speed animation on the screen. lol

So I change the whole splash screen animation into a smooth zoom-in and fade-out effect as shows in the code below…

private async Task AnimateTransition()
{
	...
	await Task.Delay(1000);

	// Scaling up smoothly upto 5x and Fading out as the next page comes up.
	var explodeImageTask = Task.WhenAll(
		Content.ScaleTo(5, 300, Easing.CubicOut),
		Content.FadeTo(0, 300, Easing.CubicInOut));
	...	
}

Once it completes we navigate to the MainPage. Now that animation was much pleasing to look at…

I felt like that cute little monkey got some justice! lol

Home page!

So like I mentioned before I laid out a full layout design restructure and one of the main pages was the Home page.

  • Getting rid of confusing layout
  • Focusing on the travel photo background
  • Getting rid of the empty space
  • Making sure content properly fills the page

This is a travel related app, so it should be focused on giving such experience for the user so I decided to maximize on the scenic travel photos in the home page, thus resizing the Image element to take up to 70% of the page space.

Also I’ve added navigation for the user to click on the destination name to and to be navigated to that travel destination’s scenic travel photo gallery page.

Look at that beauty eh! 😉

The user picture grid at the bottom, while giving it a fixed height, I managed to fix a whole bunch of alignment issues inside the template container as well.

I added a new element above the translation text element for the user, to select a destination where they would like to view, and navigate to that page from home page itself.

Woot! woot!

Next’s let’s see that beauty in action…

Travel Destination Page…

So from the home page once User selects a travel destination to view, then they get navigated to this gorgeous page filled with scenic travel photos of that destination, pulled from Bing Image Search results…

It gets even better, here’s what you see when you select Italy…

Truly gorgeous… Well I’ve used Pancake View here for the full page background for the gradient effect and shadow effect for the Image containers.

<DataTemplate>
	<yummy:PancakeView
		... >
		<Grid Margin="0">
			<Image Aspect="AspectFill" Source="{Binding ImageUrl}" />
		</Grid>
	</yummy:PancakeView>
</DataTemplate>

Bingo!

Translation revamped!

So as I mentioned before I’ve implemented a new feature extending Bing Translation, allowing the user to pick the languages they want to have their input text translated into.

Here’s the new Page I implemented for it, where I load the list of languages for the user to choose from. I love how Bing translation actually provides the native word for the languages in their own language. 🙂 pretty neat eh!

Once the user selects the languages, I will be saving that in the memory as user preferences. Then next time User enters any text for translation, I would be showing them the list of translations according to their preferred languages. 😀

Now ain’t that handy! 😉

Last minute Pull requested!

Yes, literally last minute! So after all that panic filled sleepless all-nighter effort, I manged to finish up some good looking app with cool features added, and trust me when I say, I literally submitted the Pull Request at the very last minute, exactly at 11:58 PM on April 30, 2020 PDT. Just one minute before the deadline! 😀

Here’s my Pull Request on github: https://github.com/jfversluis/TravelMonkey/pull/25

That was such an adventure, I think this was the first time I stayed up all night for coding, after many years since graduation! 😀

Here’s the repo in my github: https://github.com/UdaraAlwis/TravelMonkey

Well I could have done a much better job, in terms of features, code refactoring and standards, if I hadn’t procrastinated till last minute. I wouldn’t blame someone, if they looked at the code and complained, hence its not the cleanest considering my usual quality standards! but I would consider it was a satisfying completion, given the whole last minute stress and staying up a whole night! 😛

We got Swag!

So as they promised we got them swags yo! 😀

But but… later I got even a better news,

Well at the end all the participants got $25 gift codes to spend at .NET Foundation store! 😀 yaay! 😍

Oh well.. what an adventure! Thank you Microsoft! ❤️

Conclusion

This was such an awesome opportunity, and I’m glad I pulled through somehow even if it was last minute effort! It was actually fun! Learned another lesson not to procrastinate stuff like these till last minute, at least not till 24 hours prior to submission deadline. lol

Sharing a bit of Azure bits, it was surprisingly easy to integrate all these kinds of cool features with Azure Cognitive Services without having to deal with any complicated computing. If it was few years back I would have to deal with all these language translation and image processing stuff all by myself.

So glad I found the new PancakeView thanks to this challenge, it was quite handful, specially in crafting those beautiful gradient and shadow effects.

Finally I should send special thanks to Microsoft and @jfversluis @codemillmatt for this awesome opportunity!

Share the love! 😀 Cheers yol!

Overriding Back Button in Xamarin.Forms Shell…

Let me share all about overriding the Back Button navigation in Xamarin.Forms Shell applications, oh and yes! it includes handling the Android on-screen back button as well! 😉

This topic has been quite a confusing and wobbly area in Xamarin.Forms for the longest time, even I remember having to write numerous customer renderers, and hacks to just to get this simple handle done, overriding the back button…

Yes, we got hope!

But with shiny new Xamarin.Forms Shell seems to have provided quite a promising solution for this, out of the box framework itself, without us having to do much work.

I’ve been working on trying to override the back button behavior on Xamairn.Forms Shell recently, both with Navigation bar button and Android hardware back button. So I decided to share my experience with yol and provide a proper solid solution for your worries.

Ways of the Backwards…

Fundamentally there are two ways how a backward navigation could occur, although there could be other ways depending on the flow of our app…

  • Navigation bar Back button (iOS and Android)
  • Android on-screen Back Button

So when we need to consider both those scenarios when taking control of backward navigation.

Investigation…

Since overriding the Backwards Navigation in Xamarin.Forms has always been quite confusing and difficult to handle, when I started off of Xamarin.Forms Shell, I thought of giving it a clean slate and a fresh try from scratch.

Based on that here are the findings I came up with…

Case 1: OnBackButtonPressed()

OnBackButtonPressed() This method has been there for quite a long time in Xamarin.Forms framework right out of the box, I remember using this long time back, but they kept on breaking its behavior during many releases, which was quite troublesome.

This is suppose to let you override the Android on-screen (hardware) back button action, where a developer can override this method and it would intercept that action giving the developer the option whether to allow it or cancel it.

protected override bool OnBackButtonPressed()
{ ... }

You can override this in a ContentPage but surprisingly, it DOES NOT WORK! Now I would argue it makes total sense for it to be used in such context, and if it worked, it would have made things so much easier, but no, unfortunately not. 😦

But in Xamarin.Forms Shell, if you override this in the AppShell class, it does seem to work. It will intercept every time you click the Android Back button in any page.

public partial class AppShell : Xamarin.Forms.Shell
{
	public AppShell() { ... }

	protected override bool OnBackButtonPressed()
	{
		// true or false to disable or enable the action
		return base.OnBackButtonPressed();
	}
}

But the only problem is you need to have it implemented in AppShell class, which calls for some complicated implementation in the code,

  • We have to handle each individual Page behavior in a global context
  • No async context available to perform some awaitable async operation

So that’s double the trouble I wouldn’t want to go down that mess! trust me, I’ve tried lol.

They have several bug tickets open for this issue from “time to time”, here’s one of them: https://github.com/xamarin/Xamarin.Forms/issues/7072

Just an extra, if you need to handle an awaitable operation in a non-async context, here’s a sytarting point: https://forums.xamarin.com/discussion/27752/how-to-await-a-displayalert-from-a-page-without-async-button-event

Case 2: Shell.BackButtonBehavior

Shell.BackButton Now this is something new that was shipped with Xamarin.Forms Shell, which lets you override the Navigation Bar Back button, even allowing you to customize the button appearance with an icon or text.

It allows you to cancel the user invoked backward navigation from the Navigation Bar Back button. You could also subscribe a command that will fire up and let you proceed as you wish.

<Shell.BackButtonBehavior>
    <BackButtonBehavior
        Command="{Binding GoBackCommand}"
        IsEnabled="True"
        TextOverride="Back" />
</Shell.BackButtonBehavior>

Microsoft Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#navigation-events

Do not get this confused with the Android on-screen back button, this does not work for that.

But there’s a small bug in it right now, where as in iOS run time it wouldn’t fire the Command as expected unless you set the TextOverride or IconOverride property. But it works perfectly fine on Android. There’s an active bug on it: https://github.com/xamarin/Xamarin.Forms/issues/8546

Nonetheless this is a good option to keep in mind.

Case 3: Shell.OnNavigating()

Shell.OnNavigating event is also a nifty little feature shipped out with Xamarin.Forms Shell, which allows you to intercept any kind of navigation and override it.

Yes it works on both Android and iOS! allowing you to override any navigation, either forwards or backwards direction. This goes by saying that it supports handling Android on-screen back button navigation as well.

It passes in a parameter, ShellNavigatingEventArgs provides with the following,

  • ShellNavigatingEventArgs.Cancel() allows you to cancel the navigation.
  • ShellNavigatingEventArgs.Source property provides enum ShellNavigationSource, determines the type of navigation.
  • ShellNavigatingEventArgs.Current and ShellNavigatingEventArgs.Target provides the navigation path details, kind of like, from and to path.

Microsoft Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#navigation-events

There are two ways to implement this, you can override OnNavigating() in the AppShell class

public partial class AppShell : Xamarin.Forms.Shell
{
    public AppShell() { ... }
 
    protected override void OnNavigating
                           (ShellNavigatingEventArgs args)
    {
        // implement your logic
        base.OnNavigating(args);
    }
}

or you can subscribe to the Shell.Current.Navigating event of it as follows…

protected override void OnAppearing()
{
	Shell.Current.Navigating += Current_Navigating;
}

private async void Current_Navigating(object sender, 
                           ShellNavigatingEventArgs e)
{
	// implement your logic
}

Also here you need to make sure to unsubscribe from those even handlers once you’re done with the override action, otherwise they will retain in memory and cause all kinds of weird issues in your app.

Given both solutions, I would say the most productive option is to use the event subscription, instead of overriding in a global context. But then again it should depend mostly on your requirement. You need to keep in mind, “With great power comes great responsibility” when implementing this method, you have to make sure you’re properly handling the resources here.

Case 4: Shell.GoToAsync() for backwards!

Shell.GoToAsync() is the method that is provided by Xamarin.Forms Shell for programmatically navigating forward in pages. Until very recently Shell didn’t provide any way to Navigate backwards, but with one of the latest update they now allow it as follows,

await Shell.Current.GoToAsync("..");

Microsoft Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#backwards-navigation

This is quite important hence this fills an important part of the puzzle, where we need to override the backward navigation event, but also forward that action programmatically once we confirm it from our logic.

Alternatively you could also use the synchronous method call, which seem to be an Xamarin.Forms internal method,

Shell.Current.SendBackButtonPressed();
...
// or on Page level
page.SendBackButtonPressed();

https://docs.microsoft.com/en-us/dotnet/api/Xamarin.Forms.Page.OnBackButtonPressed?view=xamarin-forms

But I would not recommend this to be used since its synchrony and its meant for Xamarin.Forms internal framework calls.

Investigation Conclusion:

We need both Navigation Bar back button and Android on-screen Back Button to be handled for a complete solution in this case. Now given all 3 cases, we could derive a solution by using Case 2, Case 3, and Case 4 for a full fledge overriding of the Back Button behavior in Xamarin.Forms Shell. So that’s what we’re going to explore next..

Sneak Peek!

Before I get into the actual solution that I built up, let more share a little magic here!

So that’s the awesomeness I’m going to share with you guys! Let me explain…

The Solution…

Just like I explained in my little investigation conclusion, we’re going to make use of both Shell.BackButtonBehavior and Shell.OnNavigating counterparts to implement our overriding of the Back button in Xamarin.Forms Shell. This will take care of both App Navigation Bar back button and Android on-screen back button events.

Navigation bar Back Button: We shall implement the Shell.BackButtonBehavior in the Page with a Command handler attached to it, which will override the Navigation bar back button event, and hold that flow asynchronously until we get a confirmation from an Alert dialog. Once we got the confirmation, we will forward that backward navigation event using GoToAsync(“..”) execution.

Android on-screen Back Button: We could implement the Shell.OnNavigating event subscription to handle the Android back button navigation. This implementation will need a bit of work, hence we’re going to subscribe to the Shell.OnNavigating event upon the Page OnAppearing event and unsubscribe from it upon OnDisappearing event for cleaning up the event handlers. Once we get a hold of the back button event, we will asynchronously await for the Alert dialog confirmation and forward the navigation using GoToAsync(“..”), same as the previous execution.

Keep in mind that I will be showcasing how to handle both these scenarios at once, in perfect synchronous harmony with a beautiful non-conflict implementation. 😉

Additionally I will include them separately as well in my demo project for you to explore them separately as well just in case if you had such requirement. I have published this up in my Github repo, if you’re interested in taking a peak,

hosted on github:
github.com/UdaraAlwis/XFShellBackButtonOverride

Alright then, on ahead…

Before I begin, make sure to update the installed Xamarin.Forms version in your project, whereas for this demo I’m using version 4.6.0.847, so I would recommend using the same or newer version.

Let the coding begin!

Given that you have prepared your Xamarin.Forms Shell project solution, and ready to go, let me recap some basics I’ve set up this project with. I’m using pure out of the box Xamarin.Forms Shell project, with no additional libraries or dependencies. I have set it up accordingly to MVVM architecture with appropriate BindingContext set up for each XAML Page.

Let’s begin with our Navigation bar Back button override implementation, by adding Shell.BackButtonBehavior set up in our XAML Page.

<ContentPage
    ... >
 
    <Shell.BackButtonBehavior>
        <BackButtonBehavior Command="{Binding GoBackCommand}">
            <BackButtonBehavior.TextOverride>
                <OnPlatform x:TypeArguments="x:String">
                    <OnPlatform.Platforms>
                        <On Platform="iOS" Value="Go Back" />
                    </OnPlatform.Platforms>
                </OnPlatform>
            </BackButtonBehavior.TextOverride>
        </BackButtonBehavior>
    </Shell.BackButtonBehavior>
 
    <ContentPage.Content>
        ...
    </ContentPage.Content>
</ContentPage>

Remember the Xamarin.Forms Shell bug I mentioned earlier regarding the iOS run time? So here I’ve come up with a workaround for it by setting TextOverride property for iOS platform. You could even use the IconOverride property as well if it fits your requirement.

Now let’s wire up that Command, GoBackCommand in our ViewModel…

public class TestPageViewModel : BaseViewModel
{
	public Command GoBackCommand { get; set; }

	public TestPageViewModel()
	{
		...
		GoBackCommand = new Command(async () => await GoBack());
	}

	private async Task GoBack()
	{
		var result = await Shell.Current.DisplayAlert(
			"Going Back?",
			"Are you sure you want to go back?",
			"Yes, Please!", "Nope!");

		if (result)
		{
			await Shell.Current.GoToAsync("..", true);
		}
	}
}

As you can see I’ve wired up the Command to the GoBack() async method, where I’ve fired up an Alert dialog for the user awaiting confirmation asynchronously. Then once we get the go ahead confirmation we perform the backward navigation programmatically using GoToAsync(“..”) method.

Now that bit is completed, it should let you handle the Navigation Bar back button event as you wish! 😉

Next let’s take care of the Android on-screen Back button override implementation, by making sure we have hooked into the OnAppearing and OnDisappearing events in our Page, which could differ based on the MVVM library you use. But if you’re using pure Xamarin.Forms here like me, then you can hook up to them as follows…

public partial class TestPage : ContentPage
{
	public TestPage(){ ... } 

	protected override void OnAppearing()
	{
		base.OnAppearing();

		// execute OnAppearingCommand
		// informing ViewModel
		((TestPageViewModel)this.BindingContext)
				.OnAppearingCommand.Execute(null);
	}

	protected override void OnDisappearing()
	{
		base.OnDisappearing();

		// execute OnDisappearingCommand		
		// informing ViewModel
	}
}

The idea here is to inform our ViewModel that the Page is Appearing or Disappearing and based on that we subscribe or unsubscribe from Shell.OnNavigating event as follows…

public class TestPageViewModel : BaseViewModel
{
    ...
    public Command OnAppearingCommand { get; set; }
    ...
  
    public TestPageViewModel()
    {
        ... 
        OnAppearingCommand 
                = new Command(() => OnAppearing());
        ...
    }
 
    private void OnAppearing()
    {
        Shell.Current.Navigating += Current_Navigating;
    }
 
    private void OnDisappearing()
    {
        Shell.Current.Navigating -= Current_Navigating;
    }
 
    private async void Current_Navigating(object sender, 
                                ShellNavigatingEventArgs e)
    {
        if (e.CanCancel)
        {
            e.Cancel();
            await GoBack();
        }
    }
 
    private async Task GoBack()
    {
        // display Alert for confirmation
        ...
 
        if (result)
        {
            Shell.Current.Navigating -= Current_Navigating;
            await Shell.Current.GoToAsync("..", true);
        }
    }
}

As you can see we’re subscribing to Shell.Current.Navigating event based on Appearing and Disappearing events of the page, making sure that we’re cleaning up the event handlers as I explained before.

Here we’re intercepting the Navigation in the Current_Navigating() method, and we immediately cancel it and call up on awaitable GoBack() method, where we do the Alert confirmation for the user. Then from there, based on the confirmation, we perform go back or cancellation, and additionally we’re unsubscribing from the Shell.Current.Navigating event there itself, for preventing circular event.

Here I am unsubscribing from Shell.Current.Navigating in both GoBack() and OnDisappearing() is for safety, but you could handle this according to your own requirement as well.

Afterthought…

You can only keep the 2nd implementation and still have the Navigation Bar back button overridden, this is due to Shell.OnNavigating firing up for any kind of navigation happening in Shell. So you don’t really need to have the Shell.BackButtonBehavior implementation, but you could keep both in case if you need to implement any extra features, or for safe keeping of the navigation state. 😉 Your choice!

Also since the Android on-screen Back Button handling is only required on Android, you could restrict that code logic to be registered only for Android run time using Device.RuntimePlatform == Device.Android flag of Xamarin.Forms framework.

No! I don’t want both!?

Now having both the above implementation will let you override Navigation Bar and Android on-screen back button actions. But what if I only want to override one of them? Good question!

In that case you could only have one of the above implementation up on your choice, but if you want to keep both and dynamically switch between the options, you could easily do that by introducing a simple flag property in your ViewModel such as follows,

public class TestPageViewModel : BaseViewModel
{
    public bool IsBackwardNavAllowed { get; set; } = false;
 
    public TestPageViewModel()
    {
        ...
        NavBarBackButtonCommand = new Command(async () => 
        {
            IsBackwardNavAllowed = true;
            await Shell.Current.GoToAsync("..", true);
        });
        ...
    }
 
    ...
 
    private async void Current_Navigating(object sender, ShellNavigatingEventArgs e)
    {
        if (e.CanCancel && !IsBackwardNavAllowed)
        {
            e.Cancel();
            await GoBack();
        }
    }

    ...
}

Here I have the IsBackwardNavAllowed flag, where I use to allow backward navigation originated from NavBarBackButtonCommand which is bound to Shell.BackButtonBehavior, but I still override the Android on-screen back button navigation event. 😉

Little demo awesomeness!

So in my little demo app, I have implemented 3 separate scenarios of overriding the Back Button Navigation in Xamarin.Forms Shell!

You can take a look at each XAML Page and their ViewModel counter parts to see how I have implemented this awesomeness. Alright then without further a due, let’s see it in action!

Fire it up!

Here in our 1st Page we have Android and iOS side by side both with Navigation Bar Back Button overridden successfully… 😀

You can see here on Android we have the default Back button in the Navigation bar, but on iOS we have the Text overridden back button due workaround I used for fixing the iOS bug I mentioned earlier.

Then in our 2nd Page we have Android on-screen Back button overridden successfully, in which case there wouldn’t be any response to show on iOS obviously…

As you can see I’ve deliberately disabled the overriding of the Navigation Bar Back button action using the implementation that I discussed earlier, hence we’re nicely overriding only the Android on-screen Back Button action.

Finally in our 3rd Page we have Android and iOS side by side with both Navigation Bar Back Button and Android on-screen Back Button overridden successfully…

There you go, Navigation bar back button events are overridden in both Android and iOS, while also overriding the Android on-screen back button event as well! 😉 This this implementation you don’t have to deal with the iOS bug of Shell.BackButtonBehavior…

Oh look at that beauty eh! 😉

hosted on github:
github.com/UdaraAlwis/XFShellBackButtonOverride

Once again feel free to check out the code on github! 😀

Conclusion…

The whole idea of overriding backward navigation in classic Xamarin.Forms was quite tedious, having to implement custom renderers and all kinds of platform specific hacks. But with Xamarin.Forms Shell it seems to be made easier, but still need a bit of work, and few pending bugs needs fixing from Microsofts.

So using the awesomeness of Xamarin.Forms Shell we explored how to override the Navigation Bar Back Button and Android on-screen Back Button events, with multiple customization possibilities for catering to your specific requirements.

Hope this was helpful for any of my fellow devs out there!

Share the love! 😀 Cheers yol!

Restructuring the Xamarin.Forms Shell Default App Template…

Let’s restructure the default project Template for Xamarin.Forms Shell Apps provided by Visual Studio 2019, clean it up, optimize it for the best use of Shell features. 😉

To be more detailed when you create a fresh Xamarin.Forms Shell app, in Visual Studio 2019, you get a certain default template app project provided by VS2019, let me show you how to restructure it in a clean and optimized manner for best use of features, performance and code structure.

Xamarin.Forms Shell is Awesome…

but I had quite a bit confusion understand the reason behind it and the bells and whistles of it, let me explain! So I’ve been working extensively with Xamarin framework for over 4 years now, and I’m confident to say that I have expertized myself on the best use of it. 😀

The way Xamarin.Forms Shell was marketed for was to provide a better alternative for dealing with Master Detailed or Tab Page based Xamarin.Forms Apps. This really made sense to me, since I knew how troublesome or the complexity we have to deal with in those scenarios.

Template Project mess?!

I went through the documentation, followed up on some demo code the community had shared, and once I was confident, it was time to get my hands dirty. So I created a fresh new Xamarin.Forms Shell project in Visual Studio 2019, and started going through the code.

It was a messy chaos! Since the first line of code, it was confusing, with many different Xamairn.Forms implementation practices all over the place in both UI and C# code behind, Xamarin.Forms Classic and Shell navigation mixed up in all over the project and so on. Took me quite a while to get a hold of it. 😦

This is quite a bad set up for a Template project, could be very disorienting for anyone who’s fresh starting off with Xamarin.Forms Shell, let alone Xamarin.Forms itself.

But why?

My best bet is that they wanted to give the perception to the developer that you can interchange and mix up as you like, Xamarin.Forms Classic bits and Shell bits. This is probably in a good intention, but for anyone who’s just starting to grasp it, could be very confusing, mixing up everything together in a template project.

Sure Xamarin.Forms Classic and Shell are completely interchangeable elements, but for a template, you need to give a clear, straight forward way to get started for anyone.

Ze Solution!

So my solution, is to adopt only Xamarin.Forms Shell related implementation, features, and practices into the default Template, so it gives a clear, easy to understand, straight forward view of using Xamairn.Forms Shell to build apps. Thinking in terms of simplest terms, decoupled components with clean and readable code, we need to reflect the best practices of Xamarin.Forms in the Template. 😉

So here I am sharing my journey of restructuring the default project Template for Xamarin.Forms Shell Apps step by step… Also I would like to share this as a guide to fixing up an existing messy project, with all the good coding practices in mind when it comes to Xamarin.Forms! 😀

Default Template Project…

Let’s take a proper look at the what you get fresh out of the box when you create a new Xamarin.Forms Shell project in VS2019 as of now,

So as you can see it promotes MVVM structure in the project, with Models, Views, and ViewModels separated, while also having a separate DataStore service. The basic functionality of this app is to Write text note items with a Title and Description and save them in the memory.

The app consists of ItemsPage where it shows all the text notes added, then ItemDetailsPage where you can view each of the notes, then the NewItemPage which is a modal page allowing you to add new text items, finally a simple AboutPage with a little intro to the Xamarin.Forms Shell.

Issues need Fixes…

Now let me walk you through some of the main problematic bits I found in this template project, one by one…

BindingContext init() inconsistent…

The BindingContext initialization with the ViewModel instance it all over the place, while some pages having it in code behind in the constructor.

And others having it in the XAML itself as shown below..

This should be unified either to code behind Constructor or the other only.

NewItemsPage, no ViewModel!?

For the NewItemsPage, there’s no ViewModel available, and it sets the BindingContext to itself as shown below…

This needs to be modified with its own ViewModel class, and move these data functions into it.

Missing Shell  Query Parameters…

The recommended way to pass data between pages in Xamarin.Forms Shell is to use Query Parameter strings, but this is not reflected in the Template project at all. As you can see below, it uses a tightly coupled Constructor parameter object passing instead.

This needs to be changed to use Xamarin.Forms Shell query parameters, as recommended.

Need to unify Color Resources…

Apart from the global Colors and Styles resources defined in the App.xaml, there are page level resources added as well in some pages.

This should be removed and switched to use global context Colors for better re-usability and reduce repetition of code.

Classic Xamarin.Forms Navigation!? Why!?

Now this was a serious WHY? moment I had when I first saw this, no where in the template project is using actual Xamarin.Forms Shell Route based navigation.

All over the project you will see the Classic Xamarin.Forms Navigation being used.

This needs to be changed to use the actual Shell Route based navigation.

To make it worse, for Modal pages, it implements a very bad practice of forcefully pushing the Navigation Bar on top of it. 😮

Now you can see why I have complained it’s a messy mix of everything, which needs cleaning up with a proper project structure.

Let the Restructuring begin!

Let me walk yol through the whole restructuring process I did step by step, so that you get a clear idea how to make changes in your own projects. Also have pushed this up in my Github repo, if you’re interested in taking a peek.

hosted on github:
github.com/UdaraAlwis/XFShellTemplateDemoApp

Alright then let’s on ahead…

Step 1: Cleaning up Colors and Styles…

Let’s get rid of the page level Color values and move them to the App.xaml, allowing them to be shared on an app global context, increasing re-usability and removing redundancy.

<!--
	Application Styles and Resources
-->
<Application.Resources>
	<ResourceDictionary>
		<Color x:Key="Primary">#2196F3</Color>
		<Color x:Key="Accent">#96d1ff</Color>
		<Color x:Key="LightTextColor">#999999</Color>
	</ResourceDictionary>
</Application.Resources>

Make sure to keep one key for each color value, and share that in all the required elements. Now we have a much cleaner XAML! 😉

Step 2: BaseViewModel to Infrastructure!

The BaseViewModel.cs class is not actively being instantiated but provides a base for the ViewModels of the project, so it would make sense to move out the BaseViewModel.cs class into a separate folder called, Infrastructure.

Also let’s do a bit of code refactoring inside the BaseViewModel, with the field naming, such as private fields, by adding _fieldName format as a good C# code standard.

Step 3: BindingContext in the Constructor()

Let’s have the ViewModel instantiation and its assigning to the Page.BindingContext, inside the Constructor() of each page. Yep, and don’t forget to remove the XAML set up added in the default template. 😉

public partial class ItemsPage : ContentPage
{
    private readonly ItemsViewModel _viewModel;

    public ItemsPage()
    {
        InitializeComponent();

        BindingContext = _viewModel = new ItemsViewModel();
    }
    
    ...
}

This would give better control over the ViewModel’s object instance. The private field will be named accordingly with the “_” prefix, and kept as a private readonly field, since its only going to be instantiated once in the Constructor itself. Make sure to propagate the same for all the Pages in the project.

Step 4: Clean up ItemDetailViewModel!

We need to clean up the ItemDetailViewModel, to be stand-alone and loosely coupled. This will also help us in implementing a proper Shell Route based navigation later.

Let’s convert the Item property into a full fledged property with a private backing field, GETter and SETter. 😉 In the constructor, get rid of the parameter passed in, and let’s assign a dummy value to it as default value.

public class ItemDetailViewModel : BaseViewModel
{
	private Item _item;

	public Item Item
	{
		get => _item;
		private set
		{
			SetProperty(ref _item, value);
			Title = _item?.Text;
		}
	}

	public Command LoadItemCommand { get; set; }

	public ItemDetailViewModel()
	{
		var item = new Item
		{       
                        Id = Guid.NewGuid().ToString(),
			Text = "Sample Item",
			Description = "This is an item description."
		};

		Item = item;

		LoadItemCommand = new Command<string>(async (itemId) => await LoadItem(itemId));
	}

	private async Task LoadItem(string itemId)
	{
		Item = await DataStore.GetItemAsync(itemId);
	}
}

Apart from the Item property, I have added a new Command, which will load the Item details object from the DataStore service.

Now that a well structured, clean ViewModel eh! Next let’s handle the parameter that we’re suppose to pass from ItemsPage to ItemDetailPage…

Step 5: Setting up Query Parameters…

As a part of the previous step, we need to handle the selected Item object that’s being passed into the ItemDetailPage. We’re going to handle this properly with Xamarin.Forms Shell Query parameters. So let’s pass the Id value of the selected Item object, as a query parameter into the page as follows, with the QueryProperty attribute.

[QueryProperty(nameof(ItemId), "itemid")]
public partial class ItemDetailPage : ContentPage
{
	private readonly ItemDetailViewModel _viewModel;
	private string _itemId;

	public string ItemId
	{
		get => _itemId;
		set => _itemId = Uri.UnescapeDataString(value);
	}
	
	...
}

Here we’re maintaining ItemId string property in the Page, where Shell we set the query value into during the navigation.

Do not forget to fire up the LoadItemCommand in the ViewModel of the page, with the ItemId that we acquired during navigation.

...
public partial class ItemDetailPage : ContentPage
{	
	...	
	protected override void OnAppearing()
	{
		base.OnAppearing();

		_viewModel.LoadItemCommand.Execute(ItemId);
	}
}

Alright, then let’s fix the navigation bits next…

Step 6: Use proper Shell Navigation!

Instead of using Xamarin.Forms Classic navigation, let’s migrate all the Navigation bits to proper Xamarin.Forms Shell Route based Navigation yeah!

Let’s start by registering the Page routes, that we use for navigation. Preferably using lower case letters for all the routes.

public partial class AppShell : Xamarin.Forms.Shell
{
	public AppShell()
	{
		InitializeComponent();

		Routing.RegisterRoute("itemdetailpage", typeof(ItemDetailPage));
		Routing.RegisterRoute("newitempage", typeof(NewItemPage));
	}
}

Then update all the navigation bits to use Shell route based navigation…

...
public partial class ItemsPage : ContentPage
{    
    ...
    private async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
    {
        ...

        await Shell.Current.
                    GoToAsync($"/itemdetailpage?itemid={item.Id.ToString()}");
        ...
    }
}

Now, that’s a proper Shell Navigation in action!

Step 7: Set up NewItemViewModel!

NewItemPage does not have a ViewModel created against it, in order to maintain a proper MVVM structure we need to move all the code behind bits in NewItemPage.xaml.cs into the NewItemViewModel as follows…

public class NewItemViewModel : BaseViewModel
{
    private Item _item;

    public Item Item
    {
        get => _item;
        set
        {
            SetProperty(ref _item, value);
        }
    }

    public NewItemViewModel()
    {
        var item = new Item
        {
           ...
        };

        Item = item;
    }
}

The in the page constructor we assign the instance of this ViewModel to the BindingContext, and you’re done..

Step 8: Use proper Modal Navigation!

The NewItemPage is treated as a Modal page, we should use Shell.PresentationMode instead of classic Navigation.PushModalAsync() for navigating to Modal pages.

First of all make sure we’re navigating to the NewItemPage properly using Shell Route navigation as follows,

...
public partial class ItemsPage : ContentPage
{    
    ...
    private async void AddItem_Clicked(object sender, EventArgs e)
    {
        await Shell.Current.GoToAsync($"/newitempage");
    }
}

Next we set up Shell.PresentationMode property in the NewItemPage to render the page navigation as the Modal page we expect it to be, using ModalAnimated value.

<ContentPage
    x:Class="XFShellTemplateDemoApp.Views.NewItemPage"
    xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
    ios:Page.UseSafeArea="true"
    Shell.PresentationMode="ModalAnimated">

	<!--  Content of the Page  -->
	
	... 

</ContentPage>

Also we should set up the UseSafeArea property for iOS to ignore the iPhone notch, since Modal page overlays the whole app window.

Finally, let’s get rid of the NavigationBar based buttons and use Page Content based Buttons, and modify the UI layout accordingly.

<ContentPage
    x:Class="XFShellTemplateDemoApp.Views.NewItemPage"
    Shell.PresentationMode="ModalAnimated">

    <ContentPage.Content>
        <Grid Margin="0" Padding="0">

            ...

            <StackLayout Padding="15" Orientation="Horizontal">
                <Button
                    BackgroundColor="{StaticResource Primary}"
                    Clicked="Cancel_Clicked"
                    HorizontalOptions="FillAndExpand"
                    Text="Cancel"
                    TextColor="White" />
                <Button
                    BackgroundColor="{StaticResource Primary}"
                    Clicked="Save_Clicked"
                    HorizontalOptions="FillAndExpand"
                    Text="Save"
                    TextColor="White" />
            </StackLayout>

            ...

        </Grid>
    </ContentPage.Content>
</ContentPage>

I have created separate Cancel and Save Buttons which is inside a StackLayout, which in return is inside in the parent Grid Layout where rest of the content resides.

...
public partial class NewItemPage : ContentPage
{    
    ...
    private async void Cancel_Clicked(object sender, EventArgs e)
    {
        await Shell.Current.Navigation.PopModalAsync();
    }
}

For dismissing the page we can stick to PopModalAsync() call in the Navigation stack, since Shell doesn’t have it’s own for that.

Step 9: Overall code quality clean up…

Apart from all these structural changes, another aspect I heavily focused on was, the readability of the code and maintaining proper coding standards, down to the variable naming.

It’s important to properly write the code with all these little details in mind so that its easy to read and understandable by anyone who try to understand the code.

Alright then, with that I conclude the restructuring!

Restructured Template Project…

Aaand let’s take a proper look at what we got at the end after the extensive restructuring of the Xamarin.Forms Shell Template project in VS2019,

Here’s it in action in iOS!

in Android!

Once again you may find the whole project code is hosted on my Github repo,

hosted on github:
github.com/UdaraAlwis/XFShellTemplateDemoApp

Feel free to fork it out and use it as anyway you wish, may be even for a starter pack for your Xamarin.Forms Shell App development journey! 😉

Conclusion!

Well that concludes my journey of restructuring the Xamarin.Forms Shell default project template in VS2019, for the best use of Shell features, performance and optimized clean code.

Xamarin.Forms Shell is actually an awesome new paradigm to build Xamarin.Forms app, but honestly the VS2019 Template project could really use some proper restructuring for making it easier and straight forward for the beginners to start off. 😉

Share the love! 😀 Cheers yol!

So I played around with Android Emulators in Visual Studio 2019!

Let me share some of my experience with playing around with the latest updated Android Emulators in Visual Studio 2019!

Microsoft had finally rolled out a full fledged Android Emulator set up (Xamarin Android Device Manager) that’s very stable and much easier to use with Xamarin mobile development, expiring the previously buggy always-out-dated VS Emulator set up that was shipped for Xamarin dev. Yeah seriously I hated that and had a lot of issues using those emulators.

Backstory…

So recently I got a little deep into the new Xamarin Android Emulator set up in Visual Studio 2019, where I had to build a whole bunch of custom Emulators for some experiments. I had to do a lot of fine tuning and customization for those Android Virtual Devices. Also I had to focus on Performance management as well, which was quite interesting to deal with given the HAXM and Windows Hyper-V separation.

It was a great learning experience, where I noticed a lot of new features and differences between the previous VS Emulator set up compared to this one.

So here I am sharing my experience…

Getting Started…

Here are some important articles that might be important for anyone to get started…

Managing Virtual Devices with the Android Device Manager
https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/device-manager?tabs=windows&pivots=windows
Great step by step guide on how to update Device Manager, create new Virtual Devices, Customizing and Managing the performance further…

Editing Android Virtual Device Properties
https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/device-properties?pivots=windows
Step by step guide for Editing Virtual Device Properties…

Troubleshooting
https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/troubleshooting?pivots=windows
Basically this includes fixing HAXM issues, Hyper-V issues not configured up in BIOS, or not Enabled in Windows, etc.. It’s quite easy to miss those configurations so you might want to focus twice on those if you ever run into any issues.

The official documentation from Microsoft does a great job of explaining how to get started and all, so I won’t be repeating the same on my blog post, rather I would focus on the important bits that I experienced and issues I ran into which I eventually solved during my playing around! 😉

The adb binary is obsolete!?!

So this is the first weird issue I ran into when I tried out the Android Emulator on Visual Studio 2019, there is a reason why I call it weird though… lol

“The ADB binary found at C:\Program Files (x86)\Android\android-sdk\platform-tools\adb.exe is obsolete and has seriousperformance problems with the Android Emulator. Please update to a newer version to get significantly faster app/file transfer.”

Yeah notice the “seriousperformance” lol, no idea why they haven’t spell-checked the error message. Anyhow I kept on getting this warning message every time I launched my Android Emulators, I couldn’t really understand why, since I had VS 2019 updated to the latest version at the time. But later only I figured out that you need to manually update some other bits from your Android SDK Manager as shown in below steps…

Update Android Emulator!

You need to make sure to update your Android Emulator version, from the Android SDK Manager as shown below…

Go to the Tools tab, and expand the Android Emulator section, make sure you have installed the latest version as shown there. Most likely this won’t be updated by the usual VS Updater process, which was the issue in my case.

Also one more thing you need to do, since the “obsolete ADB binary issue” could be occurred from either one of these.

Update Android SDK Build Tools!

Go to Tool tab and expand Android SDK Build Tools section…

You need to make sure to have the latest version installed, and remove any older versions already installed of the Android SDK Build Tools as shown above. Because this could be causing the “obsolete ADB binary issue” that I mentioned earlier.

Intel HAXM vs Windows Hyper-V!

Now some devs seem to be getting confused about this, first think of it as this, you have an Android Emulator and you have these two different support systems that you can use to accelerate the performance of it. You can use only one of them, its either Intel HAXM or Windows Hyper-V, you cannot use both at the same time. Got it? 😉

Check out the docs: Hardware acceleration for emulator performance (Hyper-V & HAXM)
Well the documentation from Microsoft does a great job at explaining both these setups in great detail step by step.

I personally tried both of them separately in my Lenovo Windows Laptop, that’s running on Intel Core i7 Processor. Keep in mind, if you want to try Intel HAXM then you need to disable Windows Hyper-V and vise-versa, otherwise you’ll run into all kinds of issues.

Aha! Intel HAXM!

Intel’s Hardware Accelerated Execution Manager (HAXM). HAXM is a virtualization engine for computers running Intel CPUs. – Source

Check if your Intel Processor supports Virtualization Technology: https://www.intel.com/content/www/us/en/support/articles/000005486/processors.html

You development machine needs to be running on an Intel processor in order for HAXM to work, even in that case that processor needs to support Intel VT, you can check it from the link I shared above. This works on both Microsoft Windows and Apple Mac OS systems, as long as the hardware requirements are met.

Intel HAXM has always been there since long time back for accelerating the performances of Android Emulators, so it supports Emulators that are running older versions of x86-based virtual devices.

If you’ve successfully set up Intel HAXM, you can check status of HAXM set up as follows:

sc query intelhaxm

Microsoft recommends this option to be your default choice for setting up your Android Emulators. But if your dev set up doesn’t support Intel HAXM acceleration, next let’s see the second option…

Ooo! Windows Hyper-V!

Microsoft’s Hyper-V and the Windows Hypervisor Platform (WHPX)Hyper-V is a virtualization feature of Windows that makes it possible to run virtualized computer systems on a physical host computer. Source

As obvious as it is, this only works on Windows OS! This was introduced for Android Emulators quite recently, so you need to have the following set up for your local Android SDK and Tools:

  • Android Emulator package 27.2.7 or later
  • Android SDK Tools version is 26.1.1 or later

Also you need to have Microsoft Windows 10 Pro, Enterprise, or Education version installed. You can check if your system could support Windows Hyper-V as follows:

systeminfo

If all those values are shown as Yes, then you can go ahead and enable Windows Hyper-V on your machine 🙂

So, Intel HAXM or Windows Hyper-V!?!

Yeah, so which is better? given that you can ONLY think of if you’re development PC is compatible for both of them!

I’ve tried both of them, and to be honest I’ve seen much better performance with Intel HAXM Acceleration in my Windows 10 Lenovo Laptop, with Intel Core i7 processor. Since Microsoft docs also recommend this option, yes I would definitely recommend this be your primary choice as well for better performance.

FastBoot, Intel HAXM only!

Now this is something strange that I noticed during my try outs, FastBoot feature does not seem to be supported on Windows Hyper-V, during every launch it was executing a fresh cold boot. But with Intel-HAXM it works like a charm! So that’s probably something you need to keep in mind! 😉

If you’re not familiar with FastBoot, let me walk you through a little intro…

FastBoot vs ColdBoot!

You can see this configuration in the Properties from the Android Device Manager as following…

FastBoot allows you to directly boot your Android Emulator from a pre-saved snapshot state image, so you get a super fast boot and be able to deploy the apps faster when you launch directly from Visual Studio. Every time you close the Emulator it will save a snapshot of it’s current state, which will be used in the next boot.

So what is ColdBoot?

The opposite of FastBoot is ColdBoot, where during every launch the Android Emulator executes a fresh boot instance. ColdBoot is by default disabled as you can see in my previous screenshot, you need to tick on the fastboot.forceColdBoot in order to enable this. You should only use this if you need a fresh boot in each time your Emulator launches.

Now as obvious as it is, keep in mind you can’t use both of them at the same time, so make sure to tick on either forceColdBoot or forceFastBook as you prefer. 🙂

Maximum performance!

For maximizing the performance of your Android Virtual Device, I found utilizing on these three properties quite useful,

  • hw.gpu.mode – the GPU allocation set up of your Emulator
  • hw.cpu.ncore – number of Processor Cores allocated to your Emulator
  • hw.ramsize – amount of RAM size allocated to your Emulator

Now the higher values you set for those properties will definitely provide better performance in your Android Emulator, but it will require consumption of more resources from your development machine, so make sure to cross check against it when you tweak those up!

hw.gpu.mode -> host!

By default this property will be set to “auto” mode which will set the Emulator to decide whether to use device GPU processor to render the Emulator’s GPU processing or use Software GPU Emulation.

If you’ve got a dedicated powerful GPU in your development machine, I would say this should set the “host” option for the GPU emulation in the Emulator, which forces the Emulator to use the system GPU device, which in return provides great performance.

New Camera magic!

Since the latest update Android Emulators are now updated with an awesome Camera emulation feature which allows you to emulate a virtual 3D scene. You can enable this by setting the hw.camera.back property to virtualscene value.

This is such an awesome feature it allows you to navigate through an emulated virtual scene in a 3D space, with full 360 degree camera angle movements.

Now that’s some awesomeness eh! 😉

LCD Density!

You can set the density of the screen in your Android Emulator, to a list of custom values possible to set up the density-independent pixels for rendering.

Keeping in mind, setting hw.lcd.density to 160 value will cause the emulator to render each pixel in the device screen equivalent to your host machine’s physical screen pixels. You should be able to find the most suited screen density for the screen resolution you have set up for your emulator.

Here’s an example of screen resolution 1080×2160 with each lcd screen density option available from 160, 240, 213, 320, 420, 480, to 560 as follows…

Well well you can see how it clearly changes the UI rendered DPI based on the density settings you have set up… 😀

Custom Resolutions play!

So one tricky thing I got to play around was creating Android Emulators with custom screen resolutions, now this really requires a careful set up of the screen Density settings as well.

So for the fun of let me show you a custom Android Emulator that I build with the screen resolution equivalent to iPhone 11 which has height to width 1792×828 resolution…

So something to keep in mind is that, right on the first try you wouldn’t get screen density property compatible for the custom screen resolution, so you will need a few try outs to sort out the density property. Yes it took a few try outs for me as well! 😉

hw.lcd.height – screen height, hw.lcd.width – screen width, hw.lcd.density – screen density

Setting up skin.path value…

When you set up a custom resolution to your Emulator, you need to make sure to update the skin.path property value as well.

Set this value followed by the format resolution, widthxheight as shown here.

Not sure how this related to the custom resolutions, but if you miss this step your emulator screen will end up with the default resolution value set up here upon create. So make sure to set this value according to your custom screen resolution as well 🙂

Enabling on-screen Keys…

[ back | home | recent ] yes those on screen keys might not be available when you first create your custom emulator, to enable this you need to disable the hw.mainKeys property.

You should un-tick this property value to enable on-screen navigation keys.

And the resulting should be as straight as below… 😉

Well there you have it, working like a charm! and that’s pretty much it for all the tricks and lessons that I learned during my playing around with Android Emulators in Visual Studio 2019!

Conclusion

The latest updates to Android Device Manager allows you to create Android Virtual devices or emulators with incredible flexibility and easy to manage interface, with improved performances and enhancements unlike before. 🙂

The Microsoft documentations provide an incredible support for getting started step by step, and even customizing your Android emulators for Xamarin Development with ease.

I happened to be stumbled upon a great opportunity to learn a few tricks and lessons for complex use of the latest Android Virtual Devices for Xamarin Development, which I had shared in this article. 😉

Hope it helps any of you fellow devs out there!

Share the love! Cheers! 😀

Pushing the limits of Hybrid WebView in Xamarin.Forms!

Let’s push the possible limits of Hybrid WebView and build something awesome in Xamarin.Forms! 😀

Remember my last blog post, Building a bi-directional interop bridge with WebView in Xamarin.Forms! which is where I shared about building a bi-directional invoke bridge between Javascript and C# dotnet run time using Hybrid WebView.

So based on that I went on a little journey to push the limits of this Hybrid WebView and built some cool demos with it. So here I am sharing it all with yol! 😉

Pushing the limits!

BTW: This is going to be a continuation of my previous blog post, so better take a look at it first if you haven’t: Building a bi-directional interop bridge with WebView in Xamarin.Forms!

To put it into fancy words,

We built a bi-directional communication bridge, between completely different run times, with possibility of two way execution invoke on demand! Hybrid WebView…

So now, the question is, what can we do to push the limits of our Hybrid WebView? Sounds like something for the imagination to limit!

Behold the awesomeness!

Imagine, being able to load a Web page into you Xamarin.Forms WebView, and being able to access Device features such as Camera, GPS Location, Accelerometer, etc..

Basically we’re going access Device Native features through the WebView and retrieve data directly from C# .NET run time in our Xamarin.Forms app! You will be able to load any HTML content, either from a Web Hosted source or locally generated HTML source, it would work like a charm thanks to the Hybrid WebView!

In order to demonstrate this awesomeness, let’s try out the following feature for the demo implementation…

  • Capture Photos using Device Camera
  • Pick Photos from Device Gallery
  • Get Device Native information
  • Get Device GPS Location data

All those device features and data will be accessed from the Javascript running inside the Hybrid WebView! 😉

Like I mentioned before, we will have two HTML sources for this demo, a web hosted HTML source and a locally generated HTML source to make sure it works for either cases! 😀

Now here’s a bit about what will help us build this awesome demo..

– Bi directional bridge!
Being able to invoke executions directly between the Javascript environment and C# .NET Xamarin.Forms run time, is what is going to help us build this awesomeness!

Javascript <~> Xamarin.Forms (C# .NET)

So you can pass data from the Javascript that’s running inside the Hybrid WebView out into the C# .NET run time, as well as you can pass data directly into the Javascript that’s running inside the Hybrid WebView.

– Multiple parameters…
In my previous blog post I mentioned this at the end where you can extend the same implementation we did for our Hybrid WebView, into supporting multiple parameters, so here I will use this to demonstrate what we’re going to build!

Sneak Peak!

Now here’s some action on the go with this awesomeness… 😉

As usual I’ve hosted this whole demo project up on my github repo:

Code on github: https://github.com/UdaraAlwis/XFHybridWebViewAdvDemo

This is how we do it!

So let’s get right into it, but first let’s make sure some prerequisites.

– Basic Hybrid WebView implementation
Refer to my previous post and check out the implementation of the Hybrid WebView. Building a bi-directional interop bridge with WebView in Xamarin.Forms!

– Xamarin.Essentials set up to access the device native feature
You need to implement Xamarin.Essentials and set up all the device native features and their configuration for the features you wish to use. https://docs.microsoft.com/en-us/xamarin/essentials/

Multiple Parameters support!

Let’s begin with adding support for multiple parameters in our Hybrid WebView as follows…

public class HybridWebView : WebView
{
	private Action<string, string> _action;

	public void RegisterAction(Action<string, string> callback)
	{
		_action = callback;
	}

	public void Cleanup()
	{
		_action = null;
	}

	public void InvokeAction(string param1, string param2)
	{
		if (_action == null || (param1 == null && param2 == null))
		{
			return;
		}

		if (MainThread.IsMainThread)
			_action.Invoke(param1, param2);
		else
			MainThread.BeginInvokeOnMainThread(() => _action.Invoke(param1, param2));
	}
}

Code on github: /XFHybridWebViewAdvDemo/Controls/HybridWebView.cs

As you can see, I have defined Action property with two parameters, along side the setter method of it, RegisterAction() accepts Action instances with two parameters.

InvokeAction() which gets called from each native renderer level now accepts two parameters accordingly. As an addition I have added an enforced UI Thread execution using Xamarin.Essentials.MainThread feature, since we’re going to access IO heavy device features.

Following the same pattern you can add as many number of parameters as you wish! 😉

We need to add support for this in our Javascript implementation as well, so we create a pre defined separator (a pipe separator preferably “|”) that separates parameters in the data object we’re sending from javascript to Hybrid WebView’s Renderer’s script handler.

..
invokexamarinforms('PHOTO|CAMERA')
..

When our Hybrid WebView renderers receive the invoke from Javascript, we need to handle the incoming data object as follows by splitting it up using the separator we defined…

var dataBody = data;
if (dataBody.Contains("|"))
{
	var paramArray = dataBody.Split("|");
	var param1 = paramArray[0];
	var param2 = paramArray[1];
	((HybridWebView)hybridRenderer.Element).InvokeAction(param1, param2);
}
else
{
	((HybridWebView)hybridRenderer.Element).InvokeAction(dataBody, null);
}

Then we pass it on to the InvokeAction() event, for Xamarin.Forms level to handle whichever the Action has subscribed to it. This way you can handle as many parameters as you wish!

Launch invoke from HTML Javascript to C# .NET!

So here’s how we set up the simple implementation to call up the invokeXamarinFormsAction() method that we have defined in our Hybrid WebView platform Renderers. Well there’s not much different from what we implemented in my previous demo, but here we are passing multiple parameters into the javascript method upon the button click.

...

<script>
...
function invokexamarinforms(param){
    try{
        invokeXamarinFormsAction(param);
    }
    catch(err){
        alert(err);
    }
}
</script>

...

<button type="button" 
	onclick="invokexamarinforms('PHOTO|CAMERA')">
	Get from Xamarin.Forms</button>

...

This is something I’ve explained step by step in my previous blog post so I wouldn’t go into details in here. You can define as many onclick actions as you wish with the set of predefined parameters like “PHOTO|CAMERA” and “PHOTO|GALLERY”, even single parameters, “GPS” and “DEVICEINFO”, etc…

Next you need to handle those parameters in C# code to execute the specific action we’re targeting, as simple as a if-else block as follows, or even a switch statement would suffice.

...

private async void ExecuteActionFromJavascript(string param1, string param2)
{
	...	
	if (param1 != null && param1.Equals("PHOTO") && param2.Equals("CAMERA"))
	{
		var result = await _deviceFeaturesHelper.TakePhoto(this);
		if (result != null)
		{
			...
		}
	}
        ...
	else if (param1 != null && param1.Equals("DEVICEINFO"))
	{
		var result = await _deviceFeaturesHelper.GetDeviceData();
		if (result != null)
		{
			...
		}
	}	
	...
}

Based on the requested action we execute it in C#, in this case accessing Camera and Capturing a photo _deviceFeaturesHelper.TakePhoto() or even getting Device Native information _deviceFeaturesHelper.GetDeviceData() as shown above.

Let’s move to the next step of this chain…

Ping back from C# .NET to HTML Javascript!?

Now that we established pathway to call the C# .NET run time from Javascript, we’re able to invoke any action, but how do we get back the result data into the Javascript?

So in my previous blog article Talking to your WebView in Xamarin.Forms! which explains how easy it is to pass data into the Javascript rendered inside the WebView at run time, since our Hybrid WebView is an extension of the default WebView, we can use the same method here…

...
        var result = await _deviceFeaturesHelper.GetDeviceData();
        if (result != null)
        {
             await webViewElement
                   .EvaluateJavaScriptAsync($"setresult('{result}')");
        }
...

So we’re calling up on EvaluateJavaScriptAsync() with the Javascript function name that’s accepting to the results for this specific action. This function needs to be created inside the Javascript before hand, that is rendered inside the Hybrid WebView as follows…

...
<script>
...
	function setresult(value) {
		// - display the value in HTML
		// - send the data to server
	}
</script>
...

Once the data is passed into your Javascript function, You can do whaever you want with the data, be it display in the HTML, or send it up to a web server, your choice! 😉

Calling the Device Native!

Well this is quite simple if you know how to use Xamarin.Essentials to access device native features and other 3rd party plugins to access various features from Xamarin.Forms! But I’ll quickly walk through the code that I’m using in this demo.

I’ve basically created like a little Facade layer which handles all the device native features required as follows, and each method handles a given specific feature such as Camera and GPS features using their respective services of plugin calls…

public class DeviceFeaturesHelper
{
	public async Task<string> TakePhoto(ContentPage pageContext)
	{
		// launch Media Plugin to capture photos from camera
	
		...

		return imageAsBase64String;
	}
	
	public async Task<string> GetDeviceData() 
	{
		// launch Xamarin.Essentials to load device info

		return $"{nameof(DeviceInfo.Model)}: {device}<br />" +
			$"{nameof(DeviceInfo.Manufacturer)}: {manufacturer}<br />" + 
			$"{nameof(DeviceInfo.Name)}: {deviceName}<br />";
	}
}

Code on github: /XFHybridWebViewAdvDemo/DeviceFeaturesHelper.cs

So what you need to keep in mind is that we need to return a value that’s compatible to be displayed inside our WebView, based on HTML, that’s why you see I have modified some of those returned values accordingly, such as Image objects are returned as base64 strings and device information formatted as a text block with <br /> inline.

These methods are called from the Hybrid WebView’s Invoke action that we created before and results are returned to be pushed back into Javascript.

Handling Media Image objects…

Using Media Plugin for Xamarin.Forms, provides you with a MediaFile object which contains the Image object that you acquired either from Camera or Gallery, but how do we convert that into something that’s compatible to be pushed into Javascript-HTML environment?

The solution is,

MediaFile -> byte[] array -> Base64 string

We’re going to convert our MediaFile object into a byte[] array, then convert again into a base64 string, which makes it so much easier to transfer the data into the javascript run time and use that object for any purposes inside javascript itself. Here’s my code snippet for this…

public async Task<string> TakePhoto(ContentPage pageContext)
{
        ...
	var file = await CrossMedia.Current.TakePhotoAsync(...);

	// Convert bytes to base64 content
	var imageAsBase64String = Convert.ToBase64String(ConvertFileToByteArray(file));

	return imageAsBase64String;
}

private byte[] ConvertFileToByteArray(MediaFile imageFile)
{
	// Convert Image to bytes
	byte[] imageAsBytes;
	using (var memoryStream = new MemoryStream())
	{
		imageFile.GetStream().CopyTo(memoryStream);
		imageFile.Dispose();
		imageAsBytes = memoryStream.ToArray();
	}

	return imageAsBytes;
}

This is what you saw in the previous section which I have used in my /DeviceFeaturesHelper.cs
You can use this in the javascript functions as easy as below,

function setresult_takephoto(value) 
{
	document.getElementById("photoCamera_ResultElement").src 
                                             = "data:image/png;base64," + value;
}

Well that’s the entire set up of this awesome demo, so then let’s see it in action…

Fire it up!

Here’s the web page we’re loading: https://testwebpage.htmlsave.com/

Look at em on fire, Android, UWP and iOS side by side…

Code on github: https://github.com/UdaraAlwis/XFHybridWebViewAdvDemo

Conclusion…

This was just me pushing the limits of the Hybrid WebView to build awesome stuff with Xamarin.Forms! This will definitely come in handy whenever you get a scenario you need to implement an existing Web App into a Xamarin.Forms app, and you need to let the user use it as a Mobile App, with being able to access device native features.

Well that concludes it. Hope you find it useful!

Share the love! 😀 Cheers!

The step by step set up of Media Plugin for Xamarin.Forms!

Let’s properly set up Media Plugin (Xam.Plugin.Media) for Xamarin.Forms, harnessing the full capabilities with an optimized implementation! 😀

This is a continuation from my previous blog post, Behold the check-list of Media Plugin set up for Xamarin.Forms! where I shared the list of important bits you need to focus on when setting up the Media Plugin.

So here I’m building up on that and compiling a step by step guide implementation of the Xam.Plugin.Media for Xamarin.Forms, with the latest updates!

Backstory…

During my recent implementation with the Media Plugin for Xamarin.Forms, I realize that there are some new updates to this Plugin and its dependent Permission plugin that are not documented properly out there!

So I thought of writing up a new article with those updated bits and a better implementation with this library in a proper manner to harness the best of its performance and features without running into accidental bugs! 😉

Media Plugin – Xam.Plugin.Media!

Xam.Plugin.Media is the free Plugin Library by James Montemagno, that allows us to easily interact with Capturing Photos and Video and accessing them from the device Galley using Xamarin.Forms! So this library provides two main functionalities,

  • Capture Photos/Videos from Camera
  • Pick Photos/Videos from Gallery

Apart from that it allows you to Crop, Compress Photos, Set Custom Sizing and Quality, Save to Albums, and etc. It fully supports Android, iOS, UWP (Windows), and even Tizen device platforms. Quite an awesome library for sure!

Github: https://github.com/jamesmontemagno/MediaPlugin
Nuget: http://www.nuget.org/packages/Xam.Plugin.Media

This library internally depends itself on Permissions Plugin (Plugin.Permissions) for taking care of the Permissions that are required to handle in each Native platform to access Camera features and device Gallery features.

Step by Step!

Alright then let’s take a step by step walk through of setting up Media Plugin in your Xamarin.Forms project from scratch!

1. Let the set up begin!

Assuming you have already created your Xamarin.Forms project, let’s begin by adding the Xam.Plugin.Media into your Project from Nuget Package Manager.

Lets search for “Xam.Plugin.Media” in Nuget and install the library for all the project nodes in your solution, Xamarin.Forms Host project, Android, iOS, and UWP (Windows) platform nodes.

2. Initialize()!

Then you need to set up the Initialization of the Media Plugin in the Xamarin.Forms layer, by calling up the Initialize() method preferably at the start up of the App.

If you’re using a Service instance to be used with Media Plugin, then you should set this is up in the Constructor of it.

Now let’s set up the configuration for all the platform projects one by one…

Let’s set up Android!

Let’s begin with the Android bits, which is the longest set of configuration.

1. Permissions in AndroidManifest!

by adding the Permission bits that are required for the Media Plugin. Simply go to Android Project -> Properties -> Click on “Android Manifest” tab -> scroll down to “Required Permissions” section…

Simply select those two Permissions, for Reading and Writing data to the device storage, in terms of Capturing Photos and Videos and saving them during run time.

You could even add them manually in the AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <uses-sdk ... />
    <application ... >
    ...
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
  </application>
    ...
</manifest>

Then again, unless you’re going to saving your captured Photos or Videos then no need to add the “WRITE” permission. So make sure to decide on your requirement.

2. Permission Plugin – OnRequestPermissionsResult()

Next we need to set up the call back for the Permission Plugin on the OnRequestPermissionsResult() method in your MainActivity.cs class.

on github: /XFMediaPluginDemo.Android/MainActivity.cs

Visual Studio 2019 adds the override of this method automatically to your MainActivity class, but if its not there you need to set up as shown above.

3. FileProviderfile_paths.xml

We need to set up the FileProvider path values in the file_paths.xml, so go ahead create a new folder called “xml” in your “Resources” folder, and add a new XML file called “file_paths.xml” with the following content.

on github: /XFMediaPluginDemo.Android/Resources/xml/file_paths.xml

Oh, and make sure the Build Action of that file is set to “AndroidResource” in Properties.

4. FileProvider in AndroidManifest!

Then let’s add the FileProvider definition in the AndroidManifest.xml

on github: /XFMediaPluginDemo.Android/Properties/AndroidManifest.xml

This should be added inside the <application> node.

5. Plugin.CurrentActity set up…

We need to set up the Plugin.CurrentActivity plugin for Media Plugin to attach itself to the active Activity during the run time. Nuget Package Manager -> install Plugin.CurrentActivity, only into your Android project node.

Now that’s installed we need to set it up in the code as well.

6. Plugin.CurrentActity Initialization!

First we need to create the MainApplication.cs class set up that inherits from Android.App.Application base for initializing the CrossCurrentActivity Instance up on the Activity change at run time.

on github: /XFMediaPluginDemo.Android/MainApplication.cs

Next we need to set up the init() call on MainActivity.cs class as well.

on github: /XFMediaPluginDemo.Android/MainActivity.cs

Here also we’re calling the Init() method of CurrentActivity plugin but this time we’re forwarding the Bundle parameter that’s passed into the OnCreate() method.

7. Hardware Requirement filter!?!

Now this is an optional step, once your app is published, and you want to Google Play store to make your app available only for devices that has the following features, “Camera”, “Camera with Auto Focus”, etc, then you need to add the following “UsesFeatures” attributes to your AssemblyInfo.cs file.

That concludes the Android project set up.

Let’s set up iOS!

The iOS set up is much easier actually where we only have to set up the permissions.

1. Permissions in Info.plist!

On your iOS project, right click on the Info.plist file -> Open With -> select XML (Text) Editor option, which will open up in the XML editor window as follows.

on github: /XFMediaPluginDemo.iOS/Info.plist

You need to add Permissions as shown here, with an appropriate description, which will be used to show to the User when the Permissions are being requested at run time. You need to explain what those Permissions are used for in your app.

<plist version="1.0">
<dict>
    ...
    ...
    <key>NSCameraUsageDescription</key>
    <string>This app needs access to the camera to take photos.</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>This app needs access to photos.</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>This app needs access to microphone.</string>
    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>This app needs access to the photo gallery.</string>
</dict>
</plist>

But here also I’m reminding, set up only the Permissions that are absolutely required by your app’s functionality.

That concludes the iOS project set up.

Let’s set up UWP!

Well in UWP (Windows) project is even more easier to set up

1. Permissions in Package.appxmanifest!

Simply open up the Package.appxmanifest file in your UWP project -> Go to “Capabilities” tab -> Tick on “Webcam” option from the Capabilities list.

on github: /XFMediaPluginDemo.UWP/Package.appxmanifest

That concludes the UWP project set up.

Let the Xamarin.Forms, coding begin!

Now this is where we’re going to set up our implementation to use the Media Plugin in our Xamarin.Forms project host.

Doesn’t matter whether you’re going to implement in Page code behind or MVVM heavy ViewModel, we should maintain a clean decoupled structure as much as possible.

Pre-requisites!

So each feature we access we need to perform the following,

  • Check for the availability of the feature (ex: Camera, Gallery)

    Media Plugin provides these bool properties which allows you to check for the availability of the features you want to access, such as Camera, and Gallery. If they return true then it is safe to proceed with the call.
...
if (!CrossMedia.Current.IsCameraAvailable ||
		!CrossMedia.Current.IsTakePhotoSupported)
{
	await DisplayAlert("No Camera", 
              "Sorry! No camera available.", "OK");
	return null;
}
...
  • Check for the status of the Permission required (ex: Camera, Storage)

    This is another safety layer that is also recommended, checking the Status of the Permission before you access those features from Media Plugin. Based on it you can perform requesting Permission from the User during run time using the Permission Plugin that’s already set up in your project.
...
var cameraStatus = await CrossPermissions.Current.
			CheckPermissionStatusAsync(Permission.Camera);
var storageStatus = await CrossPermissions.Current.
			CheckPermissionStatusAsync(Permission.Storage);
var photosStatus = await CrossPermissions.Current.
			CheckPermissionStatusAsync(Permission.Photos);
...

Those two check ups are recommended as safety layers for smooth experience for the user and to avoid running into unexpected issues. Once those two calls are satisfied, then we can access the feature we need. 😉

It is best to have separate methods for each specific action, such as Capture new Photo or Select a new Photo from Gallery and those methods should return the resulting ImageSource object or default failure value.

Camera Feature – TakePhoto()

Here’s the method implementation that you can use to Capture Photo using the device Camera and return an ImageSource upon success.

public async Task<ImageSource> TakePhoto()
{
	if (!CrossMedia.Current.IsCameraAvailable ||
			!CrossMedia.Current.IsTakePhotoSupported)
	{
		await DisplayAlert("No Camera", 
                    "Sorry! No camera available.", "OK");
		return null;
	}

	var isPermissionGranted = await RequestCameraAndGalleryPermissions();
	if (!isPermissionGranted)
		return null;

	var file = await CrossMedia.Current.TakePhotoAsync(new 
        Plugin.Media.Abstractions.StoreCameraMediaOptions
	{
		Directory = "TestPhotoFolder",
		SaveToAlbum = true,
                PhotoSize = PhotoSize.Medium,
	});

	if (file == null)
		return null;

	var imageSource = ImageSource.FromStream(() =>
	{
		var stream = file.GetStream();
		return stream;
	});

	return imageSource;
}

You can easily use this for a Page behind code implementation or a Service layer implementation for Capturing Photos.

StoreCameraMediaOptions provides you with a whole bunch of features you can easily use to customize and resize the captured Photo within the library itself. 😀

Gallery Feature – SelectPhoto()

Here’s the method implementation that you can use to Select Photo using the device Gallery and return an ImageSource upon success.

public async Task<ImageSource> SelectPhoto()
{
	if (!CrossMedia.Current.IsPickPhotoSupported)
	{
		await DisplayAlert("Photos Not Supported", 
                   "Sorry! Permission not granted to photos.", "OK");
		return null;
	}

	var isPermissionGranted = await RequestCameraAndGalleryPermissions();
	if (!isPermissionGranted)
		return null;

	var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new 
        Plugin.Media.Abstractions.PickMediaOptions
	{
		PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
	});

	if (file == null)
		return null;

	var imageSource = ImageSource.FromStream(() =>
	{
		var stream = file.GetStream();
		return stream;
	});

	return imageSource;
}

In both above methods we are first checking the availability of the feature, and then the status of the permission, before we make the call to Media Plugin.

You can see that upon successful execution completion we’re returning the retrieved ImageSource, otherwise in any case of failure we return null. Also you can remove DisplayAlert() set up, if you’re using a Service layer, instead just throw an Exception which you can handle at the point of execution. 😉

Permission Checkup!

As you can see we have a method call to RequestCameraAndGalleryPermissions() which checks for the Permission status for the features we need to access, which implements as follows.

private async Task<bool> RequestCameraAndGalleryPermissions() 
{
	var cameraStatus = await CrossPermissions.Current.
	CheckPermissionStatusAsync(Permission.Camera);
	var storageStatus = await CrossPermissions.Current.
	CheckPermissionStatusAsync(Permission.Storage);
	var photosStatus = await CrossPermissions.Current.
	CheckPermissionStatusAsync(Permission.Photos);

	if (
	cameraStatus != PermissionStatus.Granted || 
	storageStatus != PermissionStatus.Granted || 
	photosStatus != PermissionStatus.Granted)
	{
		var permissionRequestResult = await CrossPermissions.Current.
		RequestPermissionsAsync(
			new Permission[] 
			{ 
				Permission.Camera, 
				Permission.Storage, 
				Permission.Photos 
			});

		var cameraResult = permissionRequestResult[Permission.Camera];
		var storageResult = permissionRequestResult[Permission.Storage];
		var photosResults = permissionRequestResult[Permission.Photos];

		return (
			cameraResult != PermissionStatus.Denied &&
			storageResult != PermissionStatus.Denied &&
			photosResults != PermissionStatus.Denied);
	}

	return true;
}

We’re check for Camera, Storage, Photos access permission status, which are required for Camera and Gallery access from the User in all the platforms. As you can see based on the existing status we request the Permission from user, and return the results. This will prompt the user with the popups asking for Permission to access. 😀

A better, Permission Checkup!

Just to make it more cleaner and decoupled, here’s an improved Permission check up method where you can pass in the exact Permission you need to check and it will take care of it. Oh and this is very much reusable for any kind! 😉

private async Task<bool> RequestPermissions(List<Permission> permissionList)
{
	List<PermissionStatus> permissionStatuses = new List<PermissionStatus>();
	foreach (var permission in permissionList)
	{
		var status = await CrossPermissions.Current.
		CheckPermissionStatusAsync(permission);
		permissionStatuses.Add(status);
	}

	var requiresRequesst = permissionStatuses
                                 .Any(x => x != PermissionStatus.Granted);

	if (requiresRequesst)
	{
		var permissionRequestResult = await CrossPermissions.Current.
		RequestPermissionsAsync(permissionList.ToArray());
		
		return permissionRequestResult
			.All(x => x.Value != PermissionStatus.Denied);
	}

	return true;
}

You simply have to pass in the Permission you want to check for as follows,

public async Task<ImageSource> TakePhoto()
{
	...
	var isPermissionGranted = await RequestPermissions
	(new List<Permission>(){ Permission.Camera, Permission.Storage }); 
	if (!isPermissionGranted)
		return null;
	...
}

public async Task<ImageSource> SelectPhoto()
{
	...
	var isPermissionGranted = await RequestPermissions
	(new List<Permission>(){ Permission.Photos }); 
	if (!isPermissionGranted)
		return null;
	...
}

You can pass in any kind of Permission type for check and request for Granted status.

Exception Handle!

You can see I’m not handling exceptions in here, that I would leave to the execution point of these methods calls.

try
{
	var result = await SelectPhoto();
	if (result != null)
		viewPhotoImage.Source = result;
}
catch (Exception ex)
{
	// handle your exception
}

This I believe the best way to handle any exceptions that could occur, could be in your ContentPage code behind or ViewModel. 😀

Main Thread!

Unless you’re calling these features of Media Plugin from a code behind Event handler, then you need to make sure this is executed on the app’s Main Thread.

https://theconfuzedsourcecode.wordpress.com/2020/01/27/behold-the-check-list-of-media-plugin-set-up-for-xamarin-forms/#Run-on-UI-Thread

If you ever run into any issues, make sure you have gone through my previous blog post: Behold the check-list of Media Plugin set up for Xamarin.Forms! which will definitely help you tackle any issues easily!

Well that sums it up the whole set up and a bit of under the hood check up!

Fire up the Demo!

So just for this article I created a simple demo that reflects all of this recipe of better implementation of Media Plugin for Xamarin.Forms!

Check it on my github: github.com/XFMediaPluginDemo

Side by side on Android, iOS, and UWP!

Conclusion

Following this guide you can easily implement the Media Plugin for Xamarin.Forms with a proper maintainable architecture! Although setting up might seem a bit tedious, its actually quite straight forward. Like I’ve shown in the code you need to handle Async Await calls properly and up to the UI Thread and exception handling.

Some of those bits that I have shared here aren’t mentioned in the plugin docs yet, since they’re out of date. So I really hope this helps you fellow devs!

Share the love! 😀 Cheers!

Behold the check-list of Media Plugin set up for Xamarin.Forms!

Let me share a check list for easily implementing the Media Plugin (Xam.Plugin.Media) for Xamarin.Forms with a peace of mind! 😉

Here I’m sharing some important bits that you need to focus on to avoid running into any obnoxious issues during run time of your Xamarin.Forms app!

Backstory…

Recently I was implementing Media Plugin library (Xam.Plugin.Media) in one of my Xamarin.Forms projects, even though I had implemented this before, I ran into some missing bits that caused some problems, so I had to Google them out.

So after resolving my implementation I thought of writing up this article to sum up a check list that you need to go through to make sure you’ve set up your project properly for the Media Plugin to work, hassle free, giving you a peace of mind! 😉

Media Plugin – Xam.Plugin.Media!

Xam.Plugin.Media is the free Plugin Library by James Montemagno, that allows us to easily interact with Capturing Photos and Video and accessing them from the device Galley using Xamarin.Forms!

Github: https://github.com/jamesmontemagno/MediaPlugin
Nuget: http://www.nuget.org/packages/Xam.Plugin.Media

There’s a little intro to the Media Plugin, then let’s jump right in!

Behold the check list!

It is quite straight forward how to set up Media Plugin with the guidelines of the official docs in github repo, but there are a few bits that you need to focus on as follows…

1. On Android: CurrentActivity Plugin!

You need to install Android CurrentActivity Plugin using the Nuget package manager, and properly set up the MainApplication Class set up. This used to be automatically set up during the installation from nuget but it doesn’t seem to be doing that so far, so you need to manually set it up yourself.

#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Application
{
    public MainApplication
      (IntPtr handle, JniHandleOwnership transer)
      : base(handle, transer)
    {
    }

    public override void OnCreate()
    {
        base.OnCreate();
        CrossCurrentActivity.Current.Init(this);
    }
}

Also you need to initialize CrossCurrentActivity.Current instance in MainActivity.OnCreate() method.

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        ...
        
        base.OnCreate(savedInstanceState);

        CrossCurrentActivity.Current.Init(this, savedInstanceState);

        Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        LoadApplication(new App());
    }
    
    ..
}

2. On Android: Permission Plugin set up!

When you install the Xam.Plugin.Media it will come with the Plugin.Permissions library references inside it. For this to work properly on Android you need to make sure to set up its native handlers on Android in the MainActivity.OnRequestPermissionsResult() method override.

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
    Xamarin.Essentials.Platform.
       OnRequestPermissionsResult
       (requestCode, permissions, grantResults);

    Plugin.Permissions.PermissionsImplementation.
       Current.OnRequestPermissionsResult
       (requestCode, permissions, grantResults);

    base.OnRequestPermissionsResult
       (requestCode, permissions, grantResults);
}

If you’re using Xamarin.Essentials already in your app or you’ve created your Xamarin.Forms Project recently with an update Visual Studio 2019, then OnRequestPermissionsResult() override should already exist in your MainActivity class. In that case just add the PermissionsImplementation.Current.OnRequestPermissionsResult(..) snippet to the method. Well I actually missed out on on this and I ran into some weird issues on Android.

3. On Android: FileProvider set up!

Make sure to set up the FileProvider in AndroidManifest along side the xml/file_paths.xml file in the Resources directory. One crucial point to keep in mind is that there are two ways you can set up the android:authorities value in the FileProvider.

  • android:authorities=”${applicationId}.fileprovider”
  • android:authorities=”com.example.android.fileprovider”

Sometimes it can be confusing when you are setting up this value, as shown above, either keep it as the first option as it is or the second option, with your app package name “<your app package name>.fileprovider” minted. For the clarity of it though I would suggest sticking to the first option as shown in the docs as well.

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <uses-sdk ... />
    <application ... >
    ...
    <provider android:name="android.support.v4.content.FileProvider"
                android:authorities="${applicationId}.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"></meta-data>
    </provider>
    ...
  </application>
    ...
</manifest>

4. CrossMedia.Current.Initialize();

You need to make sure to initialize the Media Plugin before calling up any of its method functions. You can do this on Xamarin.Forms layer, or even in Platform Nodes, but preferably on the Page that you’re intending to use the plugin.

You should set it up on App.xaml.cs start up methods if you’re intending to use Media Plugin on multiple pages in your App.

public partial class App : Application
{
    public App()
    {
        InitializeComponent();

        Plugin.Media.CrossMedia.Current.Initialize();

        MainPage = new NavigationPage(new MainPage());
    }
}

If you’re abstracting it out to a Service instance, then you can call this up in the Constructor during instantiation as well.

5. Run on UI Thread!

Unless you’re calling up the Media Plugin’s functions in an Event Handler directly invoked by a UI Element, you need to make sure you’re running on UI Thread during the run time. Otherwise you could run into various kinds of issues since, since accessing Camera or Gallery relies heavily on Native IO operations.

Therefore make sure to run it on UI Thread, by either using default Xamarin.Forms UI Thread force invoke method, Device.BeginInvokeOnMainThread() as below,

Device.BeginInvokeOnMainThread(async () =>
{
	await Plugin.Media.CrossMedia.Current.TakePhotoAsync(...);
});

...

Or if you’ve got Xamarin.Essentials installed in your project, then you can use MainThread Helper it provides a neat way to check for the execution thread, and based on that force the execution on UI Thread,

if (!MainThread.IsMainThread)
{
    await Plugin.Media.CrossMedia.Current.TakePhotoAsync(...);
}
else 
{
    MainThread.BeginInvokeOnMainThread(() =>
    {
        await Plugin.Media.CrossMedia.Current.TakePhotoAsync(...);
    }); 
}

...

6. Perform Permission check up!

It is best perform a Permission availability check up for the features that you’re accessing from Media Plugin using the Permission Plugin, that’s referenced along with it. This is something that’s recommended in the Media Plugin’s docs as well, which you will find at the end though. But in my experience this is a crucial set up to have an extra assurance of the features you’re trying to access from Media Plugin.

Basically before each call to Capture or Pick any Photo/Video from the Media Plugin, you need to check for the availability of the Permission for Camera, Storage, and Photos. Initially as shown below…

private async Task<ImageSource> TakePhoto()
{
    ...
    
    var isAccessGranted = await RequestCameraAndGalleryPermissions();
    
    ...
}

private async Task<bool> RequestCameraAndGalleryPermissions() 
{
    var cameraStatus = await CrossPermissions.Current.
                CheckPermissionStatusAsync(Permission.Camera);
    var storageStatus = await CrossPermissions.Current.
                CheckPermissionStatusAsync(Permission.Storage);
    var photosStatus = await CrossPermissions.Current.
                CheckPermissionStatusAsync(Permission.Photos);
    ...

    // request access permissions

    ...
}

If they’re not Granted yet or denied you need to launch a request for them from the User during the run time. I must note that the github docs of the Permission plugin are outdated and doesn’t reflect the latest changes of the library. I will be sharing the full implementation of this code snippet later in this article.

7. Set up Required Permissions!

Some of those permission requirements you need to define in the device native configuration in Android -> AndroidManifest.xml, iOS -> Info.plist, and UWP -> Package.appxmanifest. This is well documented in the Media Plugin’s docs.

https://github.com/jamesmontemagno/MediaPlugin#important-permission-information

8. Set up Required Permissions! only!

Yes it’s better not to set up Permissions unless you absolutely need them, according to your requirement. Let’s say you’re only using the Media Plugin to access Gallery, then you don’t need to set up required Permissions for Camera, and data Write Access. This will also give an extra peace of mind for your Users as well. 😉

9. Re-usable code!

If your apps is going to be using Camera and Gallery usage all over the in multiple pages, then it’s better to implement a separate Service layer for it using the Media Plugin.

This will definitely come in handy when you’re dealing with a good MVVM architecture in your project solution. You can abstract out the required features into a Service instance, that’s best registered as a Singleton object in your IoC Container.

public MediaService : IMediaService
{
	public MediaService()
	{
		...
	}
	
	public async Task<ImageSource> CapturePhoto()
	{
		...
	}
	
	public async Task<ImageSource> SelectPhoto()
	{
		...
	}
	
	...
}

As an added extra you could have a Permission check up method, where you pass in the type of permissions you want to request from User unless already granted.

...
private async Task<bool> RequestPermissions(List<Permission> permissionList)
{
    ...
}
...

Well.. that’s basically the check list you need to go through when setting up Media Plugin in your Xamarin.Forms! 😉

Conclusion…

Even though its straight forward to set up the Media Plugin (Xam.Plugin.Media) for Xamarin.Forms, there’s a high chance you might miss something during the process and run into all kinds of weird issues during the run time, specially since there’s some platform specific bits to set up as well!

I’ve also shared some tips at the end for setting up the usage of it to cater for a better implementation. I might write up another post sharing a step by step guide for setting up all these bits in my next article! Until then, hope this helps!

Share the love! 😀 Cheers!

Building a bi-directional interop bridge with WebView in Xamarin.Forms!

Let’s build an advanced communication bridge into your Xamarin.Forms WebView, talk to it, and let it talk back to us at will!? 😉 lol Yes let me show you how to pass data from Javascript environment to C# .NET run time in the Web page rendered inside your Xamarin.Forms WebView!

I’m talking about building a bi-directional communication tunnel with HTML/Javascript inside your WebView in Xamarin.Forms yo! 😀 buckle up your seatbelts!

So in my previous article, Talking to your WebView in Xamarin.Forms! I talked about, how to build a uni-directional C# .NET to Javascript environment in Xamarin.Forms WebView.

WebView in Xamarin.Forms..

In this article I’m going to take another step forward and allow the same functionality to occur the other way around as well… We’re talking about a two-way invoking between .NET run time and javascript run time in a Xamarin.Forms WebView!

Unfortunately this cannot be done by default in WebView.

Behold, Hybrid WebView!

This right here is a bit more advanced extension of the WebView with a bit of Xamarin Native magic! 😉 In order to establish an invoke bridge directly from HTML Javascript sandbox that its running inside the WebView, out to the .NET runtime, we need something more natively handled in Xamarin!

Basically we’re going to implement a device native script handler for the WebView which is going to handle the bridging between the Javascript and the .NET runtime handshake, in return giving us the opportunity to invoke calls from javascript into the .NET run time the Xamarin.Forms is execution on! 😉

Well that’s a very simplistic explanation, but there’s a whole article about it on Microsoft Xamarin Docs, Customizing a WebView if you’re interested! Since its already there, I wouldn’t be going into complete details of it, rather I would be explaining the improved implementation I have done on top of it for the Hybrid WebView.

Over there it focuses on loading Embedded HTML content, but I will extend my implementation to support for dynamic HTML content, allowing you to handle javascript loaded from a Web Source and support even run time generated javascript.

Invoking C# from Javascript in the WebView!

In order to do this, in par with Xamarin.Forms WebView, we need to implement a Custom Renderer for WebView, which we will refer to as HybridWebView.

HybridWebViewRenderer will be created across all the native platforms we intend to use our HybridWebView, in Android, iOS and Windows native environments each equipped with its own javascript handler to build a bridge on to our .NET run-time. 😉

We access the native WebViewRenderer properties and basically implement a special handler to listen to a certain pre-defined Javascript method execution. In this method which we add into the javascript that is rendered inside the WebView, we will define the parameters we need to use, in that way we can pass any number of parameters and data types as we want.

We’re going to intercept the execution of this javascript method inside our Hybrid WebViewRender, and then redirect it on to the .NET method we’ve subscribed to. So in the Hybrid WebView definition we will have an Action method that we bind to in our Xamarin.Forms level which we will subscribe to wherever we’re using this magical bits! 😉

Let the coding begin!

Let’s begin with HybridWebView Control in Xamarin.Forms! Here we;re adding an Action that we will subscribe to in order to receive data from Javascript invokes inside the WebView rendered content.

HybridWebView

namespace XFWebViewInteropDemo.Controls
{
    public class HybridWebView : WebView
    {
        private Action<string> _action;

        public void RegisterAction(Action<string> callback)
        {
            _action = callback;
        }

        public void Cleanup()
        {
            _action = null;
        }

        public void InvokeAction(string data)
        {
            if (_action == null || data == null)
            {
                return;
            }
            _action.Invoke(data);
        }
    }
}

 

InvokeAction is the method that will be used by the Native Renderer object to direct the invokes from javascript executions. Using the RegisterAction we can dynamically register the Action we need to subscribe to.  You can add any number of parameters as you wish in here, but you need to make sure to handle them in the native renderer as well.

Native Renderers…

We’re going to build native renderers for each platform we’re targeting, Android, iOS, and UWP (Windows). Basically all the renderers follow the same basic concept as we discussed before, but each of their implementation is going to be different based on the platform.

We need to make sure to handle the subscribe and unsubscribe of the Element Native properties and events properly in the renderer’s OnElementChanged() event.

We’re going to inject the javascript method that we’re going to listen to in the renderers as following.

private const string JavaScriptFunction = "function invokeCSharpAction(data){....}";

 

We will be defining this in each renderer, according to the native platform. Every time a invokeCSharpAction() javascript method executes inside the WebView, it will get fetched by the Renderer and the following method call will occur.

((HybridWebView)Element).InvokeAction(value);

 

Up to the HybridWebView’s Action subscription on Xamarin.Froms run time, allowing our Action to fire up and retrieve the data coming in from javascript.

Alright now let’s get into details of each native renderer.

Android Renderer!

We’re going to use the Android’s WebViewRenderer to subclass our HyrbidWebViewRenderer.

github: /XFWebViewInteropDemo.Android/Renderers/HybridWebViewRenderer.cs

Like we discussed before for Android, we have the following script injection defined,

private const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";

 

For Android we need some extra bits of implementation, by creating a JavascriptWebViewClient that will set up listening to the execution of javascripts inside the WebView.

Then we have to create a JsBridge, which handles the interfacing with Javascripts, and fires up InvokeAction() method to redirect the execution flow up to the Xamarin.Forms level handlers.

Both those custom objects need to be set up in the HybridWebView in the renderer Element upon instantiation.

Control.SetWebViewClient
(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
Control.AddJavascriptInterface
(new JsBridge(this), "jsBridge");

 

Once all that set up, and you build the Android project straight away, you might be getting a build error as following. (unless you’ve set this fix up before in your project)

Its caused by the JsBridge class we implemented with an Export attribute for the invokeAction method for our renderer, to export this into a native java method. So we need to add the Mono Android Export library.

You can fix this by going to Android Project -> References -> Add References -> Select Assemblies tab on the left panel -> tick on Mono.Android.Export Reference from the list of References.

Click Ok and rebuild, you’re all set! 😉

That’s pretty much it for the Android Renderer. Next on to iOS…

iOS Renderer!

For iOS we are going to use WkWebViewRenderer as the base renderer for our HybridWebView and in addition we have to implement IWKScriptMessageHandlder interface to handle the custom javascript execution monitoring that we target to handle.

github: /XFWebViewInteropDemo.iOS/Renderers/HybridWebViewRenderer.cs

We set up a WKWebViewConfiguration object in the constructor and we get access to the property WKWebViewConfiguration.UserContentController which allows us to set up our native bridge to Javascript execution firing up inside the WebView.

public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
    _userController = config.UserContentController;
    var script = new WKUserScript(new NSString(JavaScriptFunction),
                   WKUserScriptInjectionTime.AtDocumentEnd, false);
    _userController.AddUserScript(script);
    _userController.AddScriptMessageHandler(this, "invokeAction");
}

 

Then for iOS, we have the following script injection defined using webkit API, accessing the invokeAction script that we attached and finally calling on the postMessage() method with the data parameter.

private const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";

 

IWKScriptMessageHandler provides us with DidReceiveScriptMessage() method which we use to transfer the data up to the Xamarin.Forms level handler using, HybridWebView.InvokeAction(data).

Quite simple ans straight forward eh! next to Windows, or UWP as you might prefer.. 😉

UWP Renderer!

We use the Xamarin native WebViewRenderer for UWP or Windows platform.

github: /XFWebViewInteropDemo.UWP/Renderers/HybridWebViewRenderer.cs

The native default renderer grants us access to these two events NavigationCompleted and ScriptNotify. We need to make sure to subscribe to those events in our HybridWebViewRenderer in Windows as follows.

Control.NavigationCompleted += OnWebViewNavigationCompleted;
Control.ScriptNotify += OnWebViewScriptNotify;

 

NavigationCompleted, allows is to easily inject our javascript handler function, which is defined as follows for UWP or Windows,

private const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";

 

And then ScriptNotify, provides us the chance to redirect back the execution to Xamarin.Forms level handler using HybridWebView.InvokeAction(data).

Bingo, that completes the UWP or Windows Renderer!

Now that we’ve finished the setting up of our HybridWebView and its Native Renderer for Android, iOS and Windows, its time to consume it and taste it out! 😉

Let’s try it out!

Here’s we shall begin by consuming it in a XAML page in Xamarin.Forms!

<controls:HybridWebView
	x:Name="webViewElement"
	HorizontalOptions="FillAndExpand"
	VerticalOptions="FillAndExpand" />

github: /XFWebViewInteropDemo/HybridWebViewDemoPage.xaml

And then don’t forget to Subscribe to retrieve the data coming in from javascript inside our WebView using RegisterAction() method we created!

...
    // Subscribe for the data coming in from Javascript
    webViewElement.RegisterAction(DisplayDataFromJavascript);
}

private void DisplayDataFromJavascript(string data)
{
    Device.InvokeOnMainThreadAsync(() =>
    {
        ...
        // Do whatever you want with the data
        ...
    });
}
...

github: /XFWebViewInteropDemo/HybridWebViewDemoPage.xaml.cs

I’m just going to use the Main UI Thread’s help to execute any UI related stuff. And here’s a little demo HTML that I’m setting up in our Hyrbid WebView.

webViewElement.Source = new HtmlWebViewSource()
{
    Html =
        $@"<html>" +
        "<head>" +
            ...
            "<script type=\"text/javascript\">" +
                "function invokexamarinforms(){" +
                "    try{" +
                "        var inputvalue = 
document.getElementById(\"textInputElement\").value;" +
                "        invokeCSharpAction(inputvalue + '. This is from Javascript in the WebView!');" +
                "    }" +
                "    catch(err){" +
                "        alert(err);" +
                "    }" +
                "}" +
            "</script>" +
            ...
        "</head>" +

        "<body>" +
            "<div>" +
                "<input type=\"text\" id=\"textInputElement\" placeholder=\"type something here...\">" +
                "<button type=\"button\" onclick=\"invokexamarinforms()\">Send to Xamarin.Forms</button>" +
            "</div>" +
        "</body>" +

        "</html>"
};

github: /XFWebViewInteropDemo/HybridWebViewDemoPage.xaml.cs

As you can see I have a javascript function, invokexamarinforms() that will get invoked from a button call in the body. Once this method executes, it calls on the invokeCSharpAction() method that we defined in our Hybrid WebViews Native renderers.

In my javascript snippet I’m surrounding this call with a try catch in order to make sure the Native Renderer is properly implemented or not. Making sure this method is properly executes is a crucial step during debug if you run into any issues.

So let’s try out that sample code bits in action!

Time for some action! 😉

Hit that F5 yo! (well.. if you’re in Visual Studio! lol)

Side by side iOS, Android and UWP working like charm! 😉

As you can see in my simple Xamarin.Forms demo, I am demonstrating a simple C# .NET to Javascript call with data and Javascript to C# .NET call with data, a true bi-directional communication bridge!

Here we are typing some text in the Xamarin.Forms Entry element and sending it into the HTML inside the WebView. And then typing some text in the HTML Text Input element inside the WebView and click on HTML Button, and sending it to the Xamarin.Forms Label to be displayed, works like a charm!

I have shared the demo app code in my github as usual: github.com/XFWebViewInteropDemo

A little chat conversation between Javascript to C# and vise-versa! 😉

Yeah just a fun little demo I have added to the same repo in github! 😀

Extra tips!

Yep it’s that time, for some extra tips based on my experience with Xamarin.Forms Hybrid WebView! Although the extra tips that I already discussed in my previous article Talking to your WebView in Xamarin.Forms! still applies for this as well since we’re still extending from default Xamarin.Forms WebView, but apart from that…

Web Source, Embedded, Code HTML!? all same!

Doesn’t matter whatever the source of the HTML you’re setting in the Hybrid WebView, be it a web source directly from a URL, or loading an embedded HTML File, or even a code generated dynamic HTML content, it doesn’t make a difference.

The only thing that matters is the invokeCSharpAction() in your rendered HTML, so that the native renderers can pick it up and forward the execution to Xamarin.Forms .NET handlers!

Yes! extra parameters!

Even though I’m showcasing only a single parameter during this demo article, from javascript to C# .NET run time, you can easily extend this same implementation to pass any number of parameters as you wish! As I explained in the article make sure to define it in the following bits,

HybridWebView.InvokeAction(string data1, string data2)

Something to keep in mind is that you can only pass a single parameter into the invokeCSharpAction(data).  So in your javascript make sure to merge all the parameters into a single value and have a pipe delimiter (ex: |) like separator for them (ex: data1|data2) that you’re before to the invokeCSharpAction(data) method, which you will break it up on arrival in the native renderer and pass them up to the InvokeAction(data1, data2).

var dataBody = data;
var dataArray = dataBody.Split("|");
var data1 = dataArray[0];
var data2 = dataArray[1];

((HybridWebView)Element).InvokeAction(data1, data2);

Finally wire it all up, you’re good to go! 😉 I might share another article with some cool implementation with this in near future! 😀

Conclusion

You can easily build a communication bridge from C# .NET to javascript environment in Xamarin.Forms WebView! but the other way is not really possible out of the box!

That’s why we’re implementing this Hybrid WebView Control which allows us build a communication bridge from javascript to C# .NET environment directly during run time! 😉

So this concludes my bi-directional communication tunnel with HTML/Javascript inside your WebView in Xamarin.Forms yo!

Well that’s pretty much it!

Share the love! Cheers! 😀