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 🙂

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

 

So, what will 2018 be the year of?

They say that life is what you make it so time to make some resolutions …… yes?

Well, if John Sonmez from Simple Programmer is to be believed – maybe not!

I receive regular email updates from the Simple Programmer website and the one I received on 27th December caused me to stop and think.

Probably based on one of John’s blogs posts from 2016, the subject of the email was ‘Dont make resolutions the New Year, make a commitment’. Now I initially thought that these amounted to the same thing but changed my mind after reading the parting shot of the email which read:

Let me put it this way, when you need to take a taxi to the airport, do you want your taxi driver to resolve to be there at 8:30 AM or do you want him to commit to being there at that time?

The answer is obvious (hopefully) so I’ve decided to make some commitments for 2018:

  • I will watch at least one Pluralsight course a month
    • My technology focus will be .NET Core, Azure, ReactJs
  • I will watch at least one Xamarin University session (attending those required to maintain my certification)
  • I will blog twice a month (not including the Online Tool of the Month posts)
    • To keep me honest I will probably post findings from my Pluralsight courses and Xamarin investigations (proving that I’ve actually honoured the above commitments)
    • Other topics will include Privacy and Encryption which seem to be bad words these days

So that’s what I will commit to this year – maybe I’ll be in a position to commit to more but I’ll review my progress mid-2018 and see how I’m doing.

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.