Using Fonts for Icons in Xamarin.Android

I’m currently working on a new privacy application for Android and in a previous post I guided you from the Xamarin.Android Drawer Navigation project template to something that actually worked (as in you could actually use the pretty navigation provided by the template).

Now I wanted to change the menu items to something more relevant with some appropriate icons – I mean, how hard can that be right?

Well, as with everything in development these days – things are not always as easy as they seem to be.

The source code from the previous post can be found on Github and if you take a look you will find the menu defined within an XML file at ..\Resources\menu\activity_main_drawer.xml. A number of items are defined here with the same basic attributes:

<item 
    android:id="@+id/nav_camera" 
    android:icon="@drawable/ic_menu_camera" 
    android:title="Import" />

So, all I need to do is to change the android:icon attribute to point to the drawable I want ….. and that’s where the “fun” started.

If you’ve worked with drawables in Android you will know that you need multiple versions of the same graphic at different resolutions. This will allow different devices, with different screen resolutions to display the appropriate graphic. You can find more information here: https://developer.android.com/training/multiscreen/screendensities.

If you look at the above article you will see that five different resolutions (screen densities) listed – that means you need five versions of each of your graphics for your app (although there are instances where you can get away without all of them).

There are online tools to perform the generation for you but the resulting assets still need to be extracted and copied into the project.

Then comes the small matter of what icons to use – and where to get them from.

Android comes with built-in icons, like the ic_menu_camera asset in the above menu item. But finding a list of these isn’t, as I’ve found, that easy and Google recommend copying the icons you need (at all require screen densities) into your project and not to rely on them being present on any particular users device.

So, is there a better way?

Well, as the title of this post eludes, we can use fonts instead – yes, you read correctly … Fonts!

After a little bit of searching I found a blog post by James Montemagno in which he describes using the FontAwesome font in Xamarin.Forms projects.

Well, I’m not using Xamarin.Forms, I’m using Xamarin.Android but if one can do it then surely the other can too.

After a little bit of Googling (actually Duck Duck Go) I stumbled on a post by Joan Zapata where he presents updates to his Iconify library for Android.

Checking out the Readme on Github it certainly looked like this was the answer to my problems, there was just one wrinkle – it was written in Java.

No problem you say – just man up, roll up your sleeves and create a Library Binding project. Yes, I could do that – or I could see if someone else had already ported it over to Xamarin – which of course they had.

If you head over to https://github.com/PragmaticIT/xiconify you will find the source and can dig through it at your leisure – but the Readme points to a nuget package which can be easily installed into your project, so that’s what I did and as you can see from the image below, I selected to ‘Material Design’ package.

Once the package is installed it needs to be initialised in the applications Main Activity:

protected override void OnCreate(Bundle savedInstanceState)
{
	base.OnCreate(savedInstanceState);
	Xamarin.Essentials.Platform.Init(this, savedInstanceState);
	SetContentView(Resource.Layout.activity_main);
	Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
	SetSupportActionBar(toolbar);

	Iconify.with(new MaterialModule());
	
	.
	.
	.
	.
	.
}

To replace the menu icons all we need to do is fetch a reference to each of them and call SetIcon passing in the required IconDrawable provided by the new package:

var myMenuItem = navigationView.Menu.FindItem(Resource.Id.nav_camera);
myMenuItem.SetIcon(
	new IconDrawable(this, 
					 MaterialIcons.md_message.ToString()
					 )
					.color(Color.Gray));

The result will look like this:

The great thing about this is that the font will scale as required without getting blocky – I don’t need to do anything more.

The Readme for the Xamarin ported version of Iconify also provided details for adding Font Icons to your XAML and even how to create your own Icon Packs.

So there you have it – a simple way to replace your icons with scalable fonts, doing away with the need to provide versions for each screen density.

Getting Started with Visual Studio 2019 Android Navigation Drawer template

So, I’ve had an idea for another privacy-focused application, this time aimed at mobile devices – Android in particular (I know that Apple are a little touchy about encryption apps – maybe I’ll venture into iOS at a later date).

Notwithstanding my desire to keep my skills up to date I knew that the project I have in mind would require a lot of platform specific logic. While Xamarin Forms can handle this I prefer to take the hit, roll my sleeves up and I opted for a native Android project instead – and that’s where the trouble/fun started.

If you go through the ‘New Project’ process below you will end up with an application which will look something like the one above;

Yep -just what I needed, an application with a slide out menu. Now all I need to do is to replace the default options with my own and then open the appropriate views when they are clicked – what could be eaiser?

Well, when you venture into the code you will find the following event handler within the MainActivity class:

Hmm – so no actual code in place for when an option is selected then!? Running the app and selection various options confirms this is the case. So how hard can it be … really?

In the past I’ve used the Xamarin Forms Drawer Navigation model to create this sort of interface so was a little out of touch with the way native Android was doing things. I knew that I was probably looking at using Fragments, rather than Activities, to act as the content views but had never really used them.

Fragment is Obsolete – eh, what?

I know enough about Fragments to know that I needed a Fragment class and an associated Layout file (the view if you like).

I created a Fragments folder and, using the Add > New Item option, added a Fragment class.

The class was duly created and Visual Studio displayed a green squiggly under the Fragment base class reference. No, big deal – we’ve all seen this before, probably nothing too worrying;

Oh! It would appear that Fragment is deprecated – what the what?

This was rabbit hole number 1 – if Fragment is deprecated what do I use instead?

After a couple of hours trawling the Internet and generally getting frustrated I began to piece together fragments of information (pun intended) which led me to a solution, actually a couple of them.

  1. Drop the ‘Compile Target’ from 9.0 (Pie) to 8.1 (Oreo) where the Fragment class is not marked as obsolete.
  2. Reference the Support Library implementation of the Fragment class instead

Right, option 1 isn’t really an option unless you are happy to tether your application to Oreo. This may be fine for say a proof of concept but not really for a production application. An app compiled against Oreo should run fine on Pie and above – but your mileage may vary so make you you check that out!

Option 2 should not have come as a surprise to you or anyone else familiar with Android development – very few apps these days can be written without using the Support Libraries.

The complication came because when you search the Internet for information on the Android Support Libraries you will run into posts about AndroidX and Jetpack – which are essentially the new Support Library implementations. Trying to ties these back to Xamarin proved to be excessively time consuming and in the end I found that their implementations, e.g. nuget packages, are still in pre-release and documentation is sparce so I was reluctant to use them unless I really had no option. At this point I was considering using the Xamarin Forms option instead – but where’s the “fun” in that..?

The fix for my Fragment was to simply update the Android.App using statement to target the Support library instead:

No more green squiggly line and the application builds just fine – all I need now is to create the Layout and write the code to swap out the Fragments based on the selected option from the menu in the slide out drawer – simple…..!

Wiring Up the Fragments

If you look at the structure of the solution that the template generated you will see that the content of the displayed in the main area of the UI is contained in a Layout view called content_main (Resources > layout > content_main.xml).

Opening this up we can see that this layout consists of a RelativeView with a TextView inside it.

Fairly straightforward stuff here – but how do we swap our fragments in and out?

Well, as it stands – we can’t..! What we need to do is to change the RelativeLayout to a FrameLayout, give it an Id and remove the TextView (as it won’t be needed).

Now we have a container for our fragments we need to respond to the menu selections, inflate the appropriate fragment and ‘inject’ it into our FrameLayout.

I have created three fragment classes with associated layouts – these are pretty basic with the layouts containing a single TextBox each and the corresponding classes just inflating them. You can download the finished solution from the link in the resource section at the bottom of this post.

The first thing we need to do is to set the initial layout state and for this we will display the ‘Welcome’ fragment as out ‘Home/Landing Page’

To do this we will need a FragmentManager, in particular – a Support Fragment Manager. Fortunately our generated MainActivity inherits from AppCompatActivity so it already has a property containing an instance of this class.

To set our initial layout we will need to create and commit a transaction via the Fragment Manager – don’t panic, it’s three lines of code which needs to be added to the OnCreate method of the MainActivity.

        protected override void OnCreate(Bundle savedInstanceState)
        {
            .
            .
            .
            .
            var welcomeTransaction = SupportFragmentManager.BeginTransaction();
            welcomeTransaction.Add(Resource.Id.fragment_container, new Welcome(), "Welcome");
            welcomeTransaction.Commit();
        }

This will add in instance of a WelcomeFragment to the FrameLayout – essentially pushing the view onto it’s internal stack.

Now, I’ve seen a couple of trains of thought as to how to handle displaying the appropriate transaction based on the menu selection and they each have pros and cons;

  1. Add all of the required fragments to the FrameLayout, showing and hiding them as required (the FrameLayout will store the fragments in a Stack)
  2. Swap out fragments on demand so that the FrameLayout only ever contains a single child view.

With option 1 all of the fragments are loaded into the FrameLayout we are using as a Fragment Container with all but the initial view, in our case the Welcome fragment, hidden as part of the transaction. The upside of this approach is that it will maintain the state of each fragment even when it is hidden. The downside is that you will need to keep track of the currently displayed fragment so that it can be hidden when another menu option is selected and of course there is the memory consumption to think about – but this may not be a concern depending on your requirements.

Because my app is aimed at a persons privacy I don’t want all of the state to be kept in memory – when a menu option is selected I want the current fragment to be destroyed. With this in mind I’ll be implementing Option 2 and replacing the fragments as required so that the FrameLayout stack only ever contains a single fragment.

Scrolling down to the OnNavigationItemSelected handler we can now add our code to swap out the fragments (I’ve just updated the Gallery and Slideshow options here)

            else if (id == Resource.Id.nav_gallery)
            {
                var menuTransaction = SupportFragmentManager.BeginTransaction();
                menuTransaction.Replace(Resource.Id.fragment_container, new Fragment1(), "Fragment1");
                menuTransaction.Commit();
            }
            else if (id == Resource.Id.nav_slideshow)
            {
                var menuTransaction = SupportFragmentManager.BeginTransaction();
                menuTransaction.Replace(Resource.Id.fragment_container, new Fragment2(), "Fragment2");
                menuTransaction.Commit();
            }

So, almost the same three line as when we added the Welcome fragment (so a refactoring target) but this time we are replacing the contents of the FrameLayout (not replacing the layout itself, just it’s child views).

The result will be when the menu it opened (using the hamburger button or swiping from the left edge of the screen) and the Gallery or Slideshow option is clicked that the appropriate fragment will be loaded into the FrameLayout, replacing the one that was already these.

In Summary

Most apps need some form of menu and the fact that the NavigationDrawer template provides all the nice UI it does leave the developer having to trawl the internet to work out what to do next.

Even though I knew that fragments would be required there was very little in the way of documentation to be found, specifically about extending this template. Add this to the rabbit hole that is AndroidX/JetPack and it can become frustrating for developers new to Xamarin development.

While this post walks you through one implementation there are doubtless others out there. If you feel I’ve missed something then either leave a comment below or head over to the Github repository to post an issue of submit a pull request (whichever works best for you).

Resources

Full Source Code

Unit Testing with the Xamarin.Forms MessagingCenter

While we all know that Test Driven Development (TDD) is a good idea, in practice it’s not always viable. It could be a time constraint, a resource issue or the project just doesn’t warrant it.

While TDD may sometimes be an option, unit tests themselves should really be considered to be a must. They will save you a lot of time in the long run and while they may not prevent you from going grey, ask me how I know, they will reduce your stress levels when bugs raise their ugly heads.

So, whether you write your tests before you write the code or vice-versa, if you are developing production code you really should write tests to cover it.

Now, one of the requirements for unit testing is the ability to mock out a components dependencies so that you are only testing the component itself.

Normally you would use the Dependancy Injection pattern to help develop loosely coupled systems but Xamarin.Forms has a few components which can be a fly in the ointment – one of these is the MessagingCenter.

MessagingCenter allows you to send messages from one component to another using the publish-subscribe pattern to do so in a loosely coupled manner.

It’s build into Xamarin.Forms and is very easy to use;

On one side of the process you will send (publish) your message;

MessagingCenter.Send(this, "ForceLogout", message);

One the other side you will subscribe to the message;

 MessagingCenter.Subscribe<WelcomePage, string>
  (this, "ForceLogout", async (sender, arg) => {
    await ForceLogout(arg); 
});

The problem is that MessagingCenter cannot be mocked and injected into your class – so how do you unit test it?

Well, the answer is embarrassingly straightforward – you may already be using a similar approach to test for events being raised (I know I am).

Basically, all we need to do is to subscribe to the message in our test, setting a flag when the message is received;

var messageSent = false;

// Arrange 
MessagingCenter.Subscribe<WelcomePage, string>
  (this, "ForceLogout", (sender, arg) =>
        {
            messageSent = true;
        });

// Act
.
.
// Assert
Assert.IsTrue(messageSent);

It really is as simple as that. While we can’t mock out the MessagingCenter, we can simply subscribe to the message we are interested in – just as we would in the application code itself.

AppSettings in Xamarin.Forms

If you have used ASP.NET in recent years you will probably be familiar with the appSettings.jsonfile and it’s associated, build-specific transformations, e.g. appSettings.development.json and appSettings.release.json.

Essentially these allow developers to define multiple configuration settings which will be swapped out based on the build configuration in play. Common settings are stored in the main appSettings.json file while, for instance, API Endpoint Urls for development and production deployments are stored in the development and release files.

At compile-time any values specified in the deployment version of the file overwrite those in the common version.

Simple – works well and we use it all the time without thinking about it. But what about Xamarin.Forms – it doesn’t have such a mehanism out of the box so how do we achieve this and prevent accidently publishing an app to the App/Play Stores which are pointing to your development/staging servers?

The Problem

Previously I have tried a number of approaches and while they mainly worked there were always shortcomings which meant that I couldn’t really rely on them.

One used a pre-deployment step in Visual Studio to copy the appropriate file, based on the build configuration, from one location to another where it would be picked up by the applications startup code. This worked fine when running on Windows but not when building on the Mac (using Visual Studio for Mac) because it uses the cp command and not copy.

Yes, I could have created an alias from copy to cp but what about when I want to configure a Continuous Integration build on Azure DevOps?

Another approach had me creating Operating System specific script files, .bat on Windows and .sh on the Mac, and again using a pre-build task to run the appropriate script (executing the extension-less command would run the appropriate version on each platform). But passing arguments for the build configuration was clunky and again Azure DevOps pipelines didn’t really seem to want to play ball – maybe Microsoft is a bit cautious about letting anyone execute scripts on their Azure servers πŸ˜‰

Well, after deploying and testing the wrong version of an app onto my phone and scratching my head for twenty minutes I decided enough was enough and using the first approach above as a base I have come up with a simple mechanism which does the job.

The (my) Solution

The solution I’m running with requires a configuration file to be created for each build configuration, e.g. Debug and Release (by default), which are configured as ‘Embedded Resources’.

A static property is added to the App class which implements the Singleton pattern to load and return an instance of a class that represents the contents of the configuration file – I’m using Newtonsoft.Json to deserialise the file and hydrate an instance of the class.

Add some Conditional Compilation Symbols to the mix and we are just about there.

If you would rather look at the code in Visual Studio then you can download it here.

Enough talk – let’s get to it πŸ˜‰

To the Code

I’ve created a basic Xamarin.Forms project using Visual Studio 2019 Community Edition, stripped out all the default stuff and added in a single Content Page, ViewModel, Class and two Configuration Files:

The Solution (in all it’s glory)

The appsettings.debug.json file has the following content:

The appsettings.debug.json file

You probably don’t need any clues to the content of the other version πŸ˜‰

The only thing to remember here is to ensure that you set the ‘Build Action’ for these files as ‘Embedded Resource’:

Setting Build Action on .json files

The AppSettings.cs class is a simple POCO with a single property which corresponds to the json files:

The AppSettings.cs POCO class file (yes – I could remove the redundant ‘using’ statements!)

Now, when a Xamarin.Forms app starts up the App class is, for all intents and purposes, the entry point and is generally available to the Content Pages throughout the app. So this is a good place to expose our AppSettings:

App.xaml.cs

Notice how the property getter will instantiate the AppSettings instance if it is not already in place.

Also notice the use of the conditional compilation statements (#if .. #else .. #endif) in the LoadAppSettings method. This is where the ‘magic’ happens. I know that some people may shy away from this approach but this is the way I’ve gone for now.

Basically the LoadAppSettings method will read in the specified file depending on which build configuration is in play at the time. The file is deserialised into an instance of AppSettings and the local variable updated.

As the .json files are Embedded Resources we can address them using their fully qualified names, noting that the namespace is made up of the overall Namespace (AppSettingsPoc), the folder name containing the files (Configuration) and the actual filenames. Yours will be different for sure – just remember how it’s comprised.

For the conditional compilation to work we need to specify the appropriate symbols (the ‘RELEASE’ text in the above code).

To do this, Right-Click on the shared project (the one with the App.xaml file) and select ‘Properties’:

Project properties for AppSettingsPoc (shared project)

Select the ‘Build’ tab from the left hand side and set the configuration to ‘Release’ if it’s not already.

In the ‘Conditional Compilation Symbols’ field enter ‘RELEASE’ (or whatever you want to call it – just match it up with what you use in the App.xaml.cs file). If there are other values already present then tag this new one to the end, delimiting it with a semi-colon.

So, we have the configuration files, we are loading them and making the available to the Application. Now we just need to consume the data and for this I’m using a ViewModel, HomeViewModel.cs, which will be the Binding Context to our Page.

The ViewModel class is another simple POCO with a single property which reads the WelcomeText from the AppSettings instance via the App class:

The HomeViewModel.cs POCO class – with redundant ‘using’ statements removed πŸ˜‰

Finally, we just need to bind this property to a UI element on our Page:

HomePage.xaml

Notice that on line 10 in the above markup I’m specifying the BindingContext to an instance of the HomeViewModel. As with many things in Xamarin.Forms, there are numerous ways of acheiving this.

The label has a Text property which I’ve bound to the WelcomeText property (which will be on the ViewModel remember) and that’s about it.

If I run the app in Debug mode I will see the message as read from the appsettings.debug.json file. Run it in Release mode and it will be the message from the appsettings.release.json file:

In Summary

The solution presented above requires a small amount of setup and then it pretty much fire-and-forget. If you need a new setting then update your AppSettings.cs class, add the values to your .json files and you are good to go.

Need a new build configuration, say Staging? No problem. Just create the new .json file (remembering to set it’s build action as ‘Embedded Resource’), add a new ‘STAGING’ symbol to the project properties, update the LoadAppSettings method to check for it and you are done. Simple as that really.

Now, some may say that Conditional Compilation is bad and that using Reflection is the work of the Devil. But frankly – I’m quite pragmatic about these things and if it works and doesn’t have a dreadful code smell then I’m not going to lose too much sleep over that.

Updating an end of life application

A while ago I posted that the FillLPG for Android application was, in a word, Dead! But in few days time users will notice a new version, 2.0.28.5, hitting the Play Store as well as in-app notifications to update – so what gives?

Have I changed my mind about withdrawing support for this app – no, I haven’t. Essentially my hand has been forced by Google’s recent decision to deprecate some of the functionality I was using to fetch nearby places as part of the ‘Add New Station’ wizard as well as requiring 64 bit support – the latter being little more than a checkbox and nothing that most users will ever notice.

Removal of the Places Picker

Prior to the update, when adding a new station a user could specify the location in one of two ways;

  • Select from a list of locations provided by the Google Places API and flagged as ‘Gas Stations’
  • Open a ‘Place Picker’ in the form of a map and drop a pin on the desired location

It is the second option which is now going away – and there is nothing I can do about it. Google are pulling it and that’s that.

The Place Picker was added as I noticed that a nearby ‘Flogas’ centre, where you could buy cylinders of LPG and also refill your vehicles tank, was not on the list returned by Google Places. Using the Picker it was possible to zoom and pan in order to locate the desired location. It was also useful if you weren’t actually present at the station you wanted to add, i.e. it wasn’t nearby!

So where does that leave users (apart from heading to the Play Store to complain and leave a 1 star review!) – well, if the desired location is not displayed in the list then they will need to head over to the website and add the station there. Not as convenient as using the app maybe but not rocket science either.

But why bother if the app is ‘Dead’?

Well, after viewing some in app analytics I found that on average around 25 new stations were added, via the app, each month so there is a chance that users would bump up against this problem when trying to open the Place Picker – chances are that the app could simply crash out.

If the ‘Add New Station’ feature wasn’t being used I’d probably just have removed the menu option and have done with it.

But enough users were using it so I set aside a couple of hours to investigate and remove the Place Picker and it’s associated code while leaving the ‘Nearby List’ in place – even if it will only contain locations flagged by Google Places as being ‘Gas Stations’.

In Summary

In this instance the required update was not too onerous – just a couple of hours of work really, however, this may not always be the case.

Android is always evolving and Google could well make changes to other areas of functionality that could adversely affect the application and require a lot more development effort, e.g. forcing a migration to the new version of the Maps API.

In that instance it would probably the end of the road for the app and it would either have to hobble along or be pulled from the Play Store altogether.

For now though, it’s business as usual πŸ™‚

Your app does not support Andorid Pie!

I receive a lot of SPAM regarding the FillLPG mobile app, mainly offering to increase my install numbers and ratings, but today new approach appeared in my Inbox.

Screenshot showing email in mobile client

Hi there,

I was reviewing your app FillLPG – LPG Station Finder, and it looks great. But it appears the app does not support new Android Pie.  Without it, more than half of the users cannot use the app properly. I am an app developer and I can update your app in a couple of days if you want.

Thanks

Jon

It may not be obvious but this is just SPAM, sent by a bot and I doubt that anyone called ‘Jon’  is actually involved in the process, let alone reviewing my app.

The reason I can be so sure of that is threefold:

  1. The app does support Android Pie – or rather Android Pie supports it! As it stands the app doesn’t use any features that require this level of the SDK so doesn’t need any special coding. I have a Google Pixel 2 XL, running Android Pie, and it’s been running the app fine for months.
  2. The claim that ‘more then half of the users cannot use the app properly‘ is obviously targeted at people who are not in the mobile development space. Looking an the Android distribution dashboard it is clear the Android Pie is still in it’s infancy – with a distribution of less than 0.1% it doesn’t even make it onto the chart! Not surprising when only a small handful of phones, including the Pixel 2/XL, are actually running it.
  3. Finally, the email says that the app ‘looks great’ – which, I’m afraid to say, it doesn’t! It looks dated and is in need of an overhaul (which is on the cards in the New Year). Maybe the email is just trying to appeal to my ego – but then again I doubt it.

So yet another scam email trying to fleece the unwary of ‘a couple of days’ of development time for some questionable updated along with, undoubtedly, the loss of control of their source code and God only knows what hidden costs.

I obviously didn’t respond but there are plenty of apps out there that have been written for companies with no internal development resource and these are the real targets of this type of scam. I’ve written apps for a number of clients in this situation.

Using the ‘scatter-gun’ approach they are bound to find a few unwary app owners out there who may just be taken in by this. And herein lies the problem – to make this kind of thing worthwhile when the response will be quite low, the returns need to be high from each victim!

Caveat Emptor!

Another Xamarin Forms app about to hit the App/Play Stores

Smite is a wooden garden game based on a Northern European game and played around the world.

If you think of a combination of skittles and boules you’ll be pretty much there – but not quite, there are a few twists.

Each player will take turns to throw a wooden ‘smitter’ at 10 numbered wooden pins, arranged in a similar manner to those in 10 pin bowling.

  • Knock over a single pin and you score the number on that pin.
  • Knock over two or more pins and you score the number of pins that fall; knock over four pins and you score four points.
  • Before the next players turn the pins are stood back up but remain where they fell, they are not returned to their original location.
  • Miss all the pins three turns in a row and you are ‘smitten’ and out of the game.
  • If any players score exceeds 50 points they are returned to 25..!
  • When a player scores exactly 50 points the game will end when the round completes – all remaining players will complete the round. There can be more than one winner!

It sounds simple but when the pins start to spread out the game becomes much harder – I can personally attest to this, as can many members of my family..!

Keeping score is not difficult but games can go on longer than expected and you soon find yourself scrabbling around for scraps of paper to continue the scoring.

Having run out of paper on many occasions I decided to create a simple app to keep score and apply the simple rules above. The ability to take player photos to use as avatars and ensuring that game state is saved when the app is backgrounded (lunch and dinner frequently interrupt a ‘a few quick games of Smite’) add some nice functionality and coding challenges.

Written using Xamarin.Forms there are Android and iOS versions of the app with around 95% of the code being shared – only a couple of small platform specific classes were required.

I currently have a few testers looking at the release candidate version – with a few more being recruited at the upcoming Smite World Championships.

It’s a pretty straightforward app and nowhere near as complicated as the likes of my other apps,Β FillLPG or Motorhome Stopover, but I fully expect to have a few bugs to fix and features to add.

Xamarin Gotcha – Care needed when taking a photo with the Xam.Plugin.Media plugin

I’m currently writing a Xamarin.Forms scoreboard application which, as part of the functionality, allowed each player to take a photo which would be displayed within their ‘player tile’. I made use of the Xam.Plugin.Media plugin developed by James Montemagno to implement this feature and everything was working like a charm. I then parked the project for a couple of months while I attended to some paying development and training.

When I returned to the project I looked at the outstanding items on my backlog and decided to implement the saving of game state when the app is backgrounded. This was pretty straightforward and I had it nailed in a few hours by adding code to the OnStart, OnSleep and OnResume handlers in the shared class library (in this case, a PCL). After testing the functionality I then ran through a manual ‘smoke test’ to make sure everything was working as expected – and that’s when the trouble started πŸ™

I was initially working on the Android version and I quickly discovered that the photo taking functionality appeared to be broken. When I took a photo and then accepted it using the Android camera app I was taken back to a blank player list!

This didn’t used to happen – this was working code and I was certain I hadn’t change anything to do with the player photo code.

Nuget?

I then decided to create a quick and dirty app to pull in just the packages I needed to take a photo and display it within a view – and that worked just fine using the same versions that I had in my project, so the “problem” was in my code.

Returning to my code, the first thing I tried was to update all the Nuget packages. Some time had passed since I’d last opened the project and there were a number of updates pending. I was testing on my Pixel 2 XL running Android P (I’m in the beta program) and maybe, just maybe there was a mismatch here. As it was, this made no difference but it was a good job done – I’d have needed to do this anyway so no time like the present.

PCL v .NET Standard?

One major difference was that my app was using a Portable Class Library (PCL) while the sample app used .NET Standard (as you can’t create a PCL version now). Maybe that was my problem – maybe I needed to upgrade to please the plugin and/or Xamarin.Forms 3.0. Deciding it was another useful exercise anyway I decided to do just that – I created a new shared class library using .NET Standard and pulled my code over (a very simple process considering).

No joy – the problem persisted!

Then, in a moment of clarity, I wondered whether this was a problem was present in the iOS version of the app and to my surprise I found that it wasn’t. Running the smoke test on an iPhone 6s demonstrated the expected behaviour.

Going back to Android and diving into logcat I didn’t find anything obvious in terms of errors but then I saw a debug output message that I had added to the OnResume handler while developing the Save Game functionality. Why was that being called?

Eureka!

Then the penny dropped and it’s a fundamental part of the way that Android works.

When I called into the plugin to take the photo it opened up the Android Camera app – temporarily backgrounding my app in the process. When the user takes and accepts the photo, the Camera app will return control to my app, passing it the image data, and thus bring it into the foreground.

Of course, when the app is backgrounded the OnSleep handler is called and when it is brought into the foreground OnResume is called. In my case the OnSleep handler wasn’t a problem, but the OnResume hander was a different matter.

When resuming the app will now attempt to locate any saved state and if found it will deserialise the data and initialise the state to continue the saved game. But, if no saved state was found it will assume that the app is being opened with no saved state so it would just create a new game – and this is what it was doing, creating a new game with an empty player list!

A quick update to handle this unexpected backgrounding/foregrounding behaviour and I was back to a fully working app on iOS and Android.

The fact that the camera app was temporarily backgrounding my app didn’t dawn on me at the time but when I thought about it it was obvious.

A frustrating few hours to be sure but at the end of the day the app is now working the way it was intended to work and it’s now running with .NET Standard with all Nuget packages updated.

First Xamarin.Forms app goes live in both App Stores

A while ago I eluded to the fact that I was revisiting Xamarin.Forms for cross platform mobile development – previous projects had used the ‘native’ Xamarin.Android and Xamarin.IOS toolkit.

I was interested to see how far Xamarin.Forms had come since my last encounter where I found it lacking in some critical functionality that was required for the project at hand – primarily when dealing with Maps.

When I was approached by a user of my FillLPG application to write something along a very similar line, i.e. a number of points of interest displayed on a map with clickable markers to display more details, for both Android and iOS I wondered whether Xamarin.Forms had matured enough to do the job.

The application is a companion to the Motorhome Stopover website which provides it’s members with access to over 600 locations around the UK where they can park overnight for free. While these are not campsites, facilities vary from location to location, they do provide a useful service when drivers are travelling across the country to their ultimate location (not everyone wants to drive from Edinburgh to Penzance in one day and being able to break the journey is a godsend).

The app requirements were very simple, for the minimum viable product (MVP) anyway.

Authenticated Motorhome Stopover members should be able to view all currently active locations on a map, view contact details of any location and the facilities it provides and, using the device’s built-in navigation capability, navigate a route from the users current location.

Essentially, with the addition of an FAQ and About page, the app boiled down to a map showing stopover locations and a page listing contact and facility details for a location when the user tapped on its marker. If Xamarin.Forms couldn’t deal with this then I was going to be surprised.

The client was an Android user so much of the initial development was undertaken with that in mind and I focused on getting that version to a level where it was functional and he was happy – then I would take a run at the iOS version.

Initial development was undertaken prior to the release of Xamarin.Forms 3.0 but later upgraded without any problems – nothing appeared to be broken and everything just worked.

Looking back at my previous forays into Xamarin.Forms I think that the biggest hurdle was Custom Renderers. The problem being that documentation was very sparse and with the base toolkit not providing the level of customisation I wanted I didn’t have the confidence to plough on and develop Map Renderers only to have to revert to native development.

This time around the documentation was there in abundance, along with GitHub samples and a Xamarin University course. How times have changed πŸ˜‰

That said, it wasn’t plain sailing and there were still a few speedbumps along the way – although many of these can be attributed to climbing the learning curve of Xamarin.Forms rather than problems with the toolkit itself.

The best thing was, when I turned my attention to the iOS version of the app there was very little to do once the Custom Renderer for the map was completed and wired up. Everything else pretty much worked as expected with the only additional development being that of addressing minor styling and layout differences as can be seen in the screenshots below.

Not withstanding the need for additional features such as searching and filtering there is still some work to do. This mainly centres around testing and everything that facilitates it, e.g. dependency injection in Xamarin.Forms and how to do this within a Unit Test.

The ease with which I was able to develop these applications and the level of code reuse has certainly confirmed to me that Xamarin.Forms is more than just a tool to create very simple applications, quick mock-ups or proof of concept apps.

Overall I’m pretty happy with the initial release of the applications. Yes they are a bit feature-light at the moment and need a bit of polish here and there, but I’ve learned the hard way that at some point you just you need to ship something otherwise it will never see the light of day!

By defining a clear Minimum Viable Product I was able to focus on the core functionality and not get bogged down in the minutiae.

Get it on Google Play

 

Starting Development of FillLPG v3.x

Overview

With the most recent update to the FillLPG application (v2.0.28.2) rolling out I will be ceasing all development of this version (unless some horrible bug raises it’s ugly head). But fear not loyal LPG users – that doesn’t mean the the app will be going away – far from it.

Technology moves on at pace and over time new skills are acquired and lessons are learned. The ‘problem’ is that to implement all of this it is easier to start over again – taking advantage of the new framework features, applying the new skills and remembering those sometimes painful lessons.

So, what’s on the horizon?

I suppose the ‘headline’ news is that an iOS version will soon be a reality! After years of focusing solely on the Android version our Apple-using LPG’ers will be getting some love too.

The aim will be to develop an iOS application with feature parity to the current Android version.

Now, don’t fret if you are an Android user – I’m not abandoning all of you who have helped make the app what it is today. The fact that I can essentially develop for two platforms at the same time is due to the advances made in the underlying framework used to develop the app. Previous versions didn’t really lend themselves to the type of mapping that is required for the FillLPG app – but that’s all changed now and mapping is now fairly straightforward to achieve on both platforms whilst sharing the maximum amount of code – which is good for maintainability (fix a bug in one place and it’s fixed for Android and iOS).

With the rest of the application mainly consisting of ‘Forms and Lists’ and these can easily be shared between the new platforms.

The result will be a more modern UI, lower impact on battery life and data usage.

Other planned features include:

  • Offline price updates (updates will be pushed when your device next has internet access)
  • “Route Planning” – display stations along a particular route allowing you to plan stops
  • Enable/Disable update alerts for favorite stations

But there’s more…

The webmaster of the FillLPG website is currently developing a new version with a new and improved webservice – which is how the app communicates with the site. This will expose a lot more data to the app, including:

  • Station notes
  • Opening Times
  • Flags such as ‘Disabled Friendly’ and ‘SafeFill Capable’
  • Ability to specify price currency
  • and more

Obviously I have no control over the timescales for the new website functionality but as soon as it is available I will be including it into the application as quickly as I can.

Please remember though that the FillLPG website and the mobile apps are ‘labours of love’ and that both myself and the site webmaster have other commitments. The website and apps are provided free of charge and with no ads.