Android

Handle AtomicPay’s webhook with Microsoft Azure (Part 3/3) – sending push notifications with Notification Hub

Handle AtomicPay’s webhook with Microsoft Azure (Part 3/3) – sending push notifications with Notification Hub

Series overview

  1. Handle the incoming notification with an Azure Function (first post)
  2. Verify the invoice state within the Azure Function, but store the API credentials in the most secure way (second post)
  3. Send a push notification via Azure Notification Hub to all devices that have linked a merchant’s account to it (this post)

Preparations…

With Azure Notification Hub, we have one of the most powerful tools for sending push notifications out to connected devices. It is designed to handle multiple platforms, so let’s create a new Notification Hub in the Azure Portal. After logging in, select ‘Create a resource‘, followed by ‘Mobile‘ and a final click on ‘Notification Hub‘:

Azure: create a new Notification Hub

Fill in the details of the new Hub. Remember to select your already existing Resource Group and the same region that is used for your Azure Function:

Azure: new Notification Hub creation details

After about a minute, your newly created Notification Hub is ready to use. Select ‘Go to resource‘ to open it.

Azure Deployment finished

Now we are already able to connect to our first platform. For this sample, I will focus on Android. Login to the Firebase console with your Google account. Select ‘Add project‘ and configure your Android app (or add your existing, if you have already one like I do):

Firebase: Add or select project

After following all (self-explanatory) steps, scroll a bit down in the General tab of your Firebase project. You will find an entry like this:

Firebase: download google-services.json file

Download the ‘google-services.json‘-file. We will need it later in our Android app. Now select the ‘Cloud Messaging‘ tab. You will be presented with two keys – copy the upper one:

Firebase: copy server key

Go back to the Azure portal and select ‘Google (GCM/FCM)‘ in ‘Settings’ . Paste the earlier copied key and hit the ‘Save‘-Button:

Azure: paste Firebase server key and save

Now we need to authenticate our Azure Function to the Notification Hub. Select ‘Access Policies‘ in the ‘Manage’ section of your Hub and copy the lower ConnectionString with the ‘Listen,Manage,Send permission:

Azure: copy server ConnectionString

Open your Azure Function in a new tab. In the ‘Application settings‘, add a new setting and paste the ConnectionString. Add another one for the NotificationHub’s name:

Azure Function add Hub name and ConnectionString to Application settings

Go back to the Notification Hub and save the upper ConnectionString locally, as we need that one in our Android application later on

Back to code…

Now that we have prepared the Notification Hub on Azure, let’s write some code that actually sends out our notifications once our Function verified our AtomicPay invoice. In the last post, we already rewrote some of the code in preparation of the final step, our push notifications.

Triggering push notifications

Before we will be able to modify our Function code to actually send the notification, we need to install an additional NuGet package: Microsoft.Azure.Webjobs.Extensions.NotificationHub. Please note that I only was able to get this all up and running with version 1.2.0, version 1.3.0 seems to be not compatible with v1 Functions.

Triggering push notifications can be broken down into these 3 steps:

  1. create a Hub client from the ConnectionString
  2. create the content of the notification
  3. finally send the notification

This translates into this Task inside our InvoiceVerifier class:

        private static async Task TriggerPushNotification(InvoiceInfoDetails invoiceInfoDetails, string accId)
        {
            //we need full shared access connection string (server side)
            var connectionString = ConfigurationManager.AppSettings["NotifHubConnectionString"];
            var hubName = ConfigurationManager.AppSettings["NotifHubName"];

            var hub = NotificationHubClient.CreateClientFromConnectionString(connectionString, hubName);

            var templateParams = new Dictionary<string, string>();
            templateParams["body"] = $"Received payment for invoice id: {invoiceInfoDetails.InvoiceId} ({invoiceInfoDetails.Status.ToString()})";

            var outcome = await hub.SendTemplateNotificationAsync(templateParams, $"accId:{accId}");

            _traceWriter.Info($"attempted to inform merchant {accId} of payment via push");
        }

We are loading the ConnectionString and the Hub’s name from our Function’s Application settings and create a new client connection using these two safely stored properties. To keep this sample simple, I am using a templated notification that can be used across all supported platforms. The receiver is responsible for the handling of this template (we’ll see how later in this post). Finally, we are sending out the notification to the native platforms, where they will be distributed (in our case, via Firebase Cloud Messaging). By including the accId:{accId}tag, we are sending the push notification only to the devices that were registered with that specific merchant account.

Of course, this nicely written method does nothing until we actually use it. Let’s update our Run method. we only need to add one line for our test in the switch that handles the returned invoiceInfoDetails:

switch (invoiceInfoDetails.Status)
{
	case AtomicPay.Entity.InvoiceStatus.Paid:
	case AtomicPay.Entity.InvoiceStatus.PaidAfterExpiry:
	case AtomicPay.Entity.InvoiceStatus.Overpaid:
	case AtomicPay.Entity.InvoiceStatus.Complete:
		log.Info($"invoice with id {invoiceInfoDetails.InvoiceId} is paid");
		await TriggerPushNotification(invoiceInfoDetails, accId);
		break;
	default:
		log.Info($"invoice with id {invoiceInfoDetails.InvoiceId} is not yet paid");
		//todo: this will trigger additional status handling in future
		break;
}

Publish your updated Azure Function. Our Azure Function is now connected to a Notification Hub and is able to send out push notifications. Of course, push notifications ending in Nomandsland are boring. So let’s go ahead.

Receiving the push notifications

Create a new Xamarin.Android app (with XAML or without, your choice). Of course, also here we have some additional setup to perform.

Import google-services.json

Add the google-services.json we downloaded before from Firebase to your project. Set its Build Action to GoogleServicesJson in the Properties window. I needed to restart Visual Studio to be able to select this option after adding the file.

VS-google-services-build-action

Installing NuGet packages

Of course, we also need to install some additional NuGet packages:

The second step involves some changes to the AndroidManifest, giving the Firebase package some permissions and handle its intents in the application tag:

<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
	<intent-filter>
		<action android:name="com.google.android.c2dm.intent.RECEIVE" />
		<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
		<category android:name="${applicationId}" />
	</intent-filter>
</receiver>

Next, we will add a new constants class:

public static class Constants
{
	public const string ListenConnectionString = "<Listen connection string>";
	public const string NotificationHubName = "<hub name>";
}

On the client, we are only using the lower permission ConnectionString we copied earlier from the Azure Notification Hub.

Connecting to Firebase

As our Azure Notification Hub sends notifications via Firebase, Google’s native messaging handler, we need a service that connects our app. The service requests a token (the Xamarin library does all that complex stuff for us) that we’ll need to actually register the device for the notifications. Add a new class called PlatformFirebaseIidService and decorate it with the Service attribute. Besides that, we need to register our interest on the com.google.firebase.INSTANCE_ID_EVENT, which will call into the OnTokenRefresh() method we will override. We’ll end up like this:

[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class PlatformFirebaseIidService : FirebaseInstanceIdService
{
	const string TAG = "PlatformFirebaseIidService";
	NotificationHub _hub;

	public override void OnTokenRefresh()
	{
		var refreshedToken = FirebaseInstanceId.Instance.Token;
		Log.Debug(TAG, "FCM token: " + refreshedToken);		
	}
}

Now that we hold a fresh Firebase instance token, we can register our app for receiving push notifications. To do this, we’re adding an new method:

void SendRegistrationToServer(string token, List<string> tags = null)
{
	// Register with Notification Hubs
	_hub = new NotificationHub(Constants.NotificationHubName, Constants.ListenConnectionString, this);

	if (tags == null)
		tags = new List<string>() { };

	var templateBody = "{\"data\":{\"message\":\"$(body)\"}}";

	//this one registers a template that can be used cross platform
	//just make sure the template is the same on iOS, Windows, etc.
	var registerTemplate = _hub.RegisterTemplate(token, "defaultTemplate", templateBody, tags.ToArray());
	Log.Debug(TAG, $"Successful registration of Template {registerTemplate.RegistrationId}");
}

Let me break this method down. Of course, we need to connect to our Notification Hub, which is responsible for the decision if our client is a valid receiver or not. If we add tags, they will get send together with the registration. We will add the merchant’s account Id to filter the receiver. As we are sending notifications using a template, we need to register for the template that gets filled by our Azure Function. One thing is left, calling this method after obtaining a token in the OnTokenRefresh override:

SendRegistrationToServer(refreshedToken, new List<string>() { "accId:<yourAccId>" });

Handling incoming firebase messages

Now that our client is registered with both Firebase and the Azure Notification Hub, of course we want it to be able to receive the pushed messages. To achieve this, we need another Service. Add a new class called PlatformFirebaseMessagingService and decorate it once again with the Service attribute. This time, we are interested in the com.google.firebase.MESSAGING_EVENT intent, so let’s add also this one. The service is responsible for parsing our payload and actually trigger a notification helper to send the notification. Here is the code of the service:

[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class PlatformFirebaseMessagingService : FirebaseMessagingService
{
	const string TAG = "PlatformFirebaseMessagingService";

	public override void OnMessageReceived(RemoteMessage message)
	{
		Log.Debug(TAG, "From: " + message.From);
		string title = "Azure Test message";
		string body = null;

		if (message.GetNotification() != null)
		{
			//These is how most messages will be received
			body = message.GetNotification().Body;
			title = message.GetNotification().Title;
			Log.Debug(TAG, $"Notification Message Body: {body}");
		}
		else
		{
			//Only used for debugging payloads sent from the Azure portal
			body = message.Data.Values.First();
		}

		var notification = NotificationHelper.Instance.GetNotificationBuilder(title, body);
		NotificationHelper.Instance.Notify(1001, notification);

	}
}

Of course, you are curious about the NotificationHelper class. Let’s have a look. Besides being a Singleton, we need to retrieve an instance of the system’s NotificationService. As we do not have multiple notification channels in this sample, it is enough to declare both the name and its id in two constants. In the constructor of the class, we are initializing the channel:

public class NotificationHelper : ContextWrapper
{
	private static NotificationHelper _instance;

	public static NotificationHelper Instance => _instance ?? (_instance = new NotificationHelper(Application.Context));
	
	const string NOTIFICATION_CHANNEL_ID = "default";
	const string NOTIFICATION_CHANNEL_NAME = "notif_test_channel";

	NotificationManager _manager;
	NotificationManager Manager => _manager ?? (_manager = (NotificationManager)GetSystemService(NotificationService));

	public NotificationHelper(Context context) : base(context)
	{
		var channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationImportance.Default);
		channel.EnableVibration(true);
		channel.LockscreenVisibility = NotificationVisibility.Public;
		
		this.Manager.CreateNotificationChannel(channel);
	}
}

Creating the Notifications involves the Notificiation.Builder class. We’re simplifying the process for us with this method:

public Notification.Builder GetNotificationBuilder(string title, string body)
{
	var intent = new Intent(this.ApplicationContext, typeof(MainActivity));
	intent.AddFlags(ActivityFlags.ClearTop);
	var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);

	return new Notification.Builder(this.ApplicationContext, NOTIFICATION_CHANNEL_ID)
		.SetContentTitle(title)
		.SetContentText(body)
		.SetSmallIcon(Resource.Drawable.ic_launcher)
		.SetAutoCancel(true)
		.SetContentIntent(pendingIntent);
}

To read more about creation notifications, have a look at the docs for local (= client side) notifications.

Last but not least, we need to inform the system’s notification service to show the notification. The final helper method to this looks like this:

public void Notify(int id, Notification.Builder notificationBuilder)
{
	this.Manager.Notify(id, notificationBuilder.Build());
}

To test the notification, we have two options – one is to send a test notification via the Notification Hub, the other is to use Postman once again to create to trigger our Azure Function. In both cases, your result should be a notification on your device (after you deployed and run the application without the debugger being attached).

atomicpay-webhook-notification

Conclusion

In this last post of the series, I showed you all steps that are needed to send out push notifications utilizing an Azure Notification Hub. It takes a bit of setup in the beginning, but the code involved is pretty easy and straight forward.

Now that the series is complete, you can have a look at the source code on Github. You need to add your own google-services.json file and your own keys as well to run the sample. As always, I hope this post, as well as this series, is helpful for some of you.

Until the next post, happy coding, everyone!
Posted by msicc in Android, Azure, Dev Stories, Xamarin, 1 comment
Xamarin Forms, the MVVMLight Toolkit and I: Command Chaining

Xamarin Forms, the MVVMLight Toolkit and I: Command Chaining

The problem

Sometimes, we want to invoke a method that is available via code for a control. Due to the abstraction of our MVVM application, the ViewModel has no access to all those methods that are available if we would access the control via code. There are several approaches to solve this problem. In one of my recent projects, I needed to invoke a method of a custom control, which should be routed into the platform renderers I wrote for such a custom control. I remembered that I have indeed read quite a few times about command chaining for such cases and tried to implement it. In the beginning, it may sound weird to do this, but the more often I see this technique, the more I like it.

Simple Demo control

For demo purposes, I created this really simple Xamarin.Forms user control:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XfMvvmLight.Controls.CommandChainingDemoControl">
  <ContentView.Content>
      <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
            <Label x:Name="LabelFilledFromBehind" Margin="12" FontSize="Large" />   
        </StackLayout>
  </ContentView.Content>
</ContentView>

As you can see, there is just a label without text. We will write the necessary code to fill this label with some text just by invoking a method in the code behind. To be able to do so, we need a BindableProperty (once again) to get our foot into the door of the control:

public static BindableProperty DemoCommandProperty = BindableProperty.Create(nameof(DemoCommand), typeof(ICommand), typeof(CommandChainingDemoControl), null, BindingMode.OneWayToSource);

public ICommand DemoCommand
{
    get => (ICommand)GetValue(DemoCommandProperty);
    set => SetValue(DemoCommandProperty, value);
}

The implementation is pretty straightforward. We have done this already during this series, so you should be familiar if you were following. One thing, however, is different. For this BindableProperty, we are using BindingMode.OneWayToSource. By doing so, we are basically making it a read-only property, which sends its changes only down to the ViewModel (the source). If we would not do this, the ViewModel could change the property, which we do not want here.

Now we have the BindableProperty in place, we need to create an instance of the Command that will be sent down to the ViewModel. We are doing this as soon as the control is instantiated in the constructor:

public CommandChainingDemoControl()
      {
          InitializeComponent();

          this.DemoCommand = new Command(() =>
          {
              FillFromBehind();
          });
      }

      private void FillFromBehind()
      {
          this.LabelFilledFromBehind.Text = "Text was empty, but we used command chaining to show this text inside a control.";
      }

That’s all we need to do in the code behind.

ViewModel

For this demo, I created a new page and a corresponding ViewModel in the demo project. Here is the very basic ViewModel code:

using System.Windows.Input;
using GalaSoft.MvvmLight.Command;

namespace XfMvvmLight.ViewModel
{
    public class CommandChainingDemoViewModel : XfNavViewModelBase
    {
        private ICommand _invokeDemoCommand;
        private RelayCommand _demo1Command;

        public CommandChainingDemoViewModel()
        {
        }

        public ICommand InvokeDemoCommand { get => _invokeDemoCommand; set => Set(ref _invokeDemoCommand, value); }

        public RelayCommand Demo1Command => _demo1Command ?? (_demo1Command = new RelayCommand(() =>
        {
            this.InvokeDemoCommand?.Execute(null);
        }));
    }
}

As you can see, the ViewModel includes two Commands. One is the pure ICommand implementation that gets its value from the OneWayToSource-Binding. We are not using MVVMLight’s RelayCommand here to avoid casting between types, which always led to an exception when I tested the implementation first. The second command is bound to a button in the CommandChainingDemoPage and will be the trigger to execute the InvokeDemoCommand.

Final steps

The final steps are just a few simple ones. We need to connect the  InvokeDemoCommand to the user control we created earlier, while we need to bind the Demo1Commandto the corresponding button in the view. This is the page’s code after doing so:

<?xml version="1.0" encoding="utf-8" ?>
<baseCtrl:XfNavContentPage
    xmlns:baseCtrl="clr-namespace:XfMvvmLight.BaseControls" xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:ctrl="clr-namespace:XfMvvmLight.Controls;assembly=XfMvvmLight"
             x:Class="XfMvvmLight.View.CommandChainingDemoPage" RegisteredPageKey="{Binding CommandChainingDemoPageKey, Source=Locator}">
    <ContentPage.BindingContext>
        <Binding Path="CommandChainingDemoVm" Source="{StaticResource Locator}" />
    </ContentPage.BindingContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <ctrl:CommandChainingDemoControl Grid.Row="0" DemoCommand="{Binding InvokeDemoCommand, Mode=OneWayToSource}" Margin="12"></ctrl:CommandChainingDemoControl>

        <Button Text="Execute Command Chaining" Command="{Binding Demo1Command}" Margin="12" Grid.Row="1" />

    </Grid>
</baseCtrl:XfNavContentPage>

One thing to point out is that we are also specifying the OneWayToSource binding here once again. It should work with normal binding, but it I recommend to do like I did, which makes the code easier to understand for others (and of course yourself). That’s all – we have now a working command chain that invokes a method inside the user control from our ViewModel.

Conclusion

Command chaining can be a convenient way to invoke actions on controls that are otherwise not possible due to the abstraction of layers in MVVM. Once you got the concept, they are pretty easy to implement. This technique is also usable outside of Xamarin.Forms, so do not hesitate to use it out there. Just remember the needed steps:

  • create a user control (or a derived one if you need to call a method on framework controls)
  • add a BindableProperty/DependecyProperty and set its default binding mode to OneWayToSource
  • instantiate the BindableProperty/DependecyProperty inside the constructor of the user control
  • pass the method call/code into the Action part of the newly created Command  instance
  • create the commands in the ViewModel
  • connect the Commands to your final view implementation

Like I wrote earlier, I came across this (again) when I was writing a custom Xamarin.Forms control with renderers, where I had to invoke methods inside the renderer from my ViewModel. Other techniques that I saw to solve this is using Messengers (be it the one from MVVMLight or the Xamarin.Forms Messenger implementation) or the good old Boolean switch implementation (uses also a BindableProperty/DependecyProperty). I decided to use the command chaining approach as it is pretty elegant in my eyes and not that complicated to implement.

The series’ sample project is updated and available here on Github. Like always, I hope this post is useful for some of you.

Happy coding, everyone!


all articles of this series

title image credit

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 7 comments
Xamarin.Forms, Akavache and I: ensuring protection of sensitive data

Xamarin.Forms, Akavache and I: ensuring protection of sensitive data

Recap

Some of you might remember my posts about encryption for Android, iOS and Windows 10. If not, take a look here:

Xamarin Android: asymmetric encryption without any user input or hardcoded values

How to perform asymmetric encryption without user input/hardcoded values with Xamarin iOS

Using the built-in UWP data protection for data encryption

It is no coincidence that I wrote these three posts before starting with this Akavache series, as we’ll use those techniques to protect sensitive data with Akavache. So you might have a look first before you read on.

Creating a secure blob cache in Akavache

Akavache has a special type for saving sensitive data  – based on the interface ISecureBlobCache. The first step is to extend the IBlobCacheInstanceHelperinterface we implemented in the first post of this series:

    public interface IBlobCacheInstanceHelper
    {
        void Init();

        IBlobCache LocalMachineCache { get; set; }

        ISecureBlobCache SecretLocalMachineCache { get; set; }
    }

Of course, all three platform implementations of the IBlobCacheInstanceHelperinterface need to be updated as well. The code to add for all three platform is the same:

public ISecureBlobCache SecretLocalMachineCache { get; set; }     

private void GetSecretLocalMachineCache()
{
    var secretCache = new Lazy<ISecureBlobCache>(() =>
                                                 {
                                                     _filesystemProvider.CreateRecursive(_filesystemProvider.GetDefaultSecretCacheDirectory()).SubscribeOn(BlobCache.TaskpoolScheduler).Wait();
                                                     return new SQLiteEncryptedBlobCache(Path.Combine(_filesystemProvider.GetDefaultSecretCacheDirectory(), "secret.db"), new PlatformCustomAkavacheEncryptionProvider(), BlobCache.TaskpoolScheduler);
                                                 });

    this.SecretLocalMachineCache = secretCache.Value;
}

As we will use the same name for all platform implementations, that’s already all we have to do here.

Platform specific encryption provider

Implementing the platform specific code is nothing new. Way before I used Akavache, others have already implemented solutions. The main issue is that there is no platform implementation for Android and iOS (and maybe others). My solution is inspired by this blog post by Kent Boogart, which is (as far as I can see), also broadly accepted amongst the community. The only thing I disliked about it was the requirement for a password – which either would be something reversible or causing a (maybe) bad user experience.

Akavache provides the IEncryptionProviderinterface, which contains two methods. One for encryption, the other one for decryption. Those two methods are working with byte[]both for input and output. You should be aware and know how to convert your data to that.

Implementing the  IEncryptionProvider interface

The implementation of Akavache’s encryption interface is following the same principle on all three platforms.

  • provide a reference to the internal TaskpoolSchedulerin the constructor
  • get an instance of our platform specific encryption provider
  • get or create keys (Android and iOS)
  • provide helper methods that perform encryption/decryption

Let’s have a look at the platform implementations. I will show the full class implementation and remarking them afterwards.

Android

[assembly: Xamarin.Forms.Dependency(typeof(PlatformCustomAkavacheEncryptionProvider))]
namespace XfAkavacheAndI.Android.PlatformImplementations
{
    public class PlatformCustomAkavacheEncryptionProvider : IEncryptionProvider
    {
        private readonly IScheduler _scheduler;

        private static readonly string KeyStoreName = $"{BlobCache.ApplicationName.ToLower()}_secureStore";

        private readonly PlatformEncryptionKeyHelper _encryptionKeyHelper;

        private const string TRANSFORMATION = "RSA/ECB/PKCS1Padding";
        private IKey _privateKey = null;
        private IKey _publicKey = null;

        public PlatformCustomAkavacheEncryptionProvider()
        {
            _scheduler = BlobCache.TaskpoolScheduler ?? throw new ArgumentNullException(nameof(_scheduler), "Scheduler is null");

            _encryptionKeyHelper = new PlatformEncryptionKeyHelper(Application.Context, KeyStoreName);
            GetOrCreateKeys();
        }

        public IObservable<byte[]> DecryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block cannot be null");
            }

            return Observable.Start(() => Decrypt(block), _scheduler);
        }

        public IObservable<byte[]> EncryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block cannot be null");
            }

            return Observable.Start(() => Encrypt(block), _scheduler);
        }


        private void GetOrCreateKeys()
        {
            if (!_encryptionKeyHelper.KeysExist())
                _encryptionKeyHelper.CreateKeyPair();

            _privateKey = _encryptionKeyHelper.GetPrivateKey();
            _publicKey = _encryptionKeyHelper.GetPublicKey();
        }


        public byte[] Encrypt(byte[] rawBytes)
        {
            if (_publicKey == null)
            {
                throw new ArgumentNullException(nameof(_publicKey), "Public key cannot be null");
            }

            var cipher = Cipher.GetInstance(TRANSFORMATION);
            cipher.Init(CipherMode.EncryptMode, _publicKey);

            return cipher.DoFinal(rawBytes);
        }

        public byte[] Decrypt(byte[] encyrptedBytes)
        {
            if (_privateKey == null)
            {
                throw new ArgumentNullException(nameof(_privateKey), "Private key cannot be null");
            }

            var cipher = Cipher.GetInstance(TRANSFORMATION);
            cipher.Init(CipherMode.DecryptMode, _privateKey);

            return cipher.DoFinal(encyrptedBytes);
        }
    }

As you can see, I am getting Akavache’s  internal TaskpoolSchedulerin the constructor, like initial stated. Then, for this sample, I am using RSA encryption. The helper methods pretty much implement the same code like in the post about my KeyStore implementation. The only thing to do is to use these methods in the EncryptBlock and DecyrptBlock method implementations, which is done asynchronously via Observable.Start.

iOS

[assembly: Xamarin.Forms.Dependency(typeof(PlatformCustomAkavacheEncryptionProvider))]
namespace XfAkavacheAndI.iOS.PlatformImplementations
{
    public class PlatformCustomAkavacheEncryptionProvider : IEncryptionProvider
    {
        private readonly IScheduler _scheduler;

        private readonly PlatformEncryptionKeyHelper _encryptionKeyHelper;


        private SecKey _privateKey = null;
        private SecKey _publicKey  = null;

        public PlatformCustomAkavacheEncryptionProvider()
        {
            _scheduler = BlobCache.TaskpoolScheduler ??
                         throw new ArgumentNullException(nameof(_scheduler), "Scheduler is null");

            _encryptionKeyHelper = new PlatformEncryptionKeyHelper(BlobCache.ApplicationName.ToLower());
            GetOrCreateKeys();
        }

        public IObservable<byte[]> DecryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block can't be null");
            }

            return Observable.Start(() => Decrypt(block), _scheduler);
        }

        public IObservable<byte[]> EncryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block can't be null");
            }

            return Observable.Start(() => Encrypt(block), _scheduler);
        }


        private void GetOrCreateKeys()
        {
            if (!_encryptionKeyHelper.KeysExist())
                _encryptionKeyHelper.CreateKeyPair();

            _privateKey = _encryptionKeyHelper.GetPrivateKey();
            _publicKey = _encryptionKeyHelper.GetPublicKey();
        }

        private byte[] Encrypt(byte[] rawBytes)
        {
            if (_publicKey == null)
            {
                throw new ArgumentNullException(nameof(_publicKey), "Public key cannot be null");
            }

            var code = _publicKey.Encrypt(SecPadding.PKCS1, rawBytes, out var encryptedBytes);

            return code == SecStatusCode.Success ? encryptedBytes : null;
        }

        private byte[] Decrypt(byte[] encyrptedBytes)
        {
            if (_privateKey == null)
            {
                throw new ArgumentNullException(nameof(_privateKey), "Private key cannot be null");
            }

            var code = _privateKey.Decrypt(SecPadding.PKCS1, encyrptedBytes, out var decryptedBytes);

            return code == SecStatusCode.Success ? decryptedBytes : null;
        }

    }
}

The iOS implementation follows the same schema as the Android implementation. However, iOS uses the KeyChain, which makes the encryption helper methods itself different.

UWP

[assembly: Xamarin.Forms.Dependency(typeof(PlatformCustomAkavacheEncryptionProvider))]
namespace XfAkavacheAndI.UWP.PlatformImplementations
{
    public class PlatformCustomAkavacheEncryptionProvider : IEncryptionProvider
    {
        private readonly IScheduler _scheduler;

        private string _localUserDescriptor = "LOCAL=user";
        private string _localMachineDescriptor = "LOCAL=machine";

        public bool UseForAllUsers { get; set; } = false;

        public PlatformCustomAkavacheEncryptionProvider()
        {
            _scheduler = BlobCache.TaskpoolScheduler ??
                         throw new ArgumentNullException(nameof(_scheduler), "Scheduler is null");
        }

        public IObservable<byte[]> EncryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block can't be null");
            }

            return Observable.Start(() => Encrypt(block).GetAwaiter().GetResult(), _scheduler);
        }

        public IObservable<byte[]> DecryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block can't be null");
            }

            return Observable.Start(() => Decrypt(block).GetAwaiter().GetResult(), _scheduler);
        }


        public async Task<byte[]> Encrypt(byte[] data)
        {
            var provider = new DataProtectionProvider(UseForAllUsers ? _localMachineDescriptor : _localUserDescriptor);

            var contentBuffer = CryptographicBuffer.CreateFromByteArray(data);
            var contentInputStream = new InMemoryRandomAccessStream();
            var protectedContentStream = new InMemoryRandomAccessStream();

            //storing data in the stream
            IOutputStream outputStream = contentInputStream.GetOutputStreamAt(0);
            var dataWriter = new DataWriter(outputStream);
            dataWriter.WriteBuffer(contentBuffer);
            await dataWriter.StoreAsync();
            await dataWriter.FlushAsync();

            //reopening in input mode
            IInputStream encodingInputStream = contentInputStream.GetInputStreamAt(0);

            IOutputStream protectedOutputStream = protectedContentStream.GetOutputStreamAt(0);
            await provider.ProtectStreamAsync(encodingInputStream, protectedOutputStream);
            await protectedOutputStream.FlushAsync();

            //verify that encryption happened
            var inputReader = new DataReader(contentInputStream.GetInputStreamAt(0));
            var protectedReader = new DataReader(protectedContentStream.GetInputStreamAt(0));

            await inputReader.LoadAsync((uint)contentInputStream.Size);
            await protectedReader.LoadAsync((uint)protectedContentStream.Size);

            var inputBuffer = inputReader.ReadBuffer((uint)contentInputStream.Size);
            var protectedBuffer = protectedReader.ReadBuffer((uint)protectedContentStream.Size);

            if (!CryptographicBuffer.Compare(inputBuffer, protectedBuffer))
            {
               return protectedBuffer.ToArray();
            }
            else
            {
                return null;
            }
        }

        public async Task<byte[]> Decrypt(byte[] encryptedBytes)
        {
            var provider = new DataProtectionProvider();

            var encryptedContentBuffer = CryptographicBuffer.CreateFromByteArray(encryptedBytes);
            var contentInputStream = new InMemoryRandomAccessStream();
            var unprotectedContentStream = new InMemoryRandomAccessStream();

            IOutputStream outputStream = contentInputStream.GetOutputStreamAt(0);
            var dataWriter = new DataWriter(outputStream);
            dataWriter.WriteBuffer(encryptedContentBuffer);
            await dataWriter.StoreAsync();
            await dataWriter.FlushAsync();

            IInputStream decodingInputStream = contentInputStream.GetInputStreamAt(0);

            IOutputStream protectedOutputStream = unprotectedContentStream.GetOutputStreamAt(0);
            await provider.UnprotectStreamAsync(decodingInputStream, protectedOutputStream);
            await protectedOutputStream.FlushAsync();

            DataReader reader2 = new DataReader(unprotectedContentStream.GetInputStreamAt(0));
            await reader2.LoadAsync((uint)unprotectedContentStream.Size);
            IBuffer unprotectedBuffer = reader2.ReadBuffer((uint)unprotectedContentStream.Size);

            return unprotectedBuffer.ToArray();
        }
    }   
}

Last but not least, we have also an implementation for Windows applications. It is using the DataProtection API, which does handle all that key stuff and let’s us focus on the encryption itself. As the API is asynchronously, I am using .GetAwaiter().GetResult()Task extensions to make it compatible with Observable.Start.

Conclusion

Using the implementations above paired with our instance helper makes it easy to protect data in our apps. With all those data breach scandals and law changes around, this is one possible way secure way to handle sensitive data, as we do not have hardcoded values or any user interaction involved.

For better understanding of all that code, I made a sample project available that has all the referenced and mentioned classes implemented. Feel free to fork it and play with it (or even give me some feedback). For using the implementations, please refer to my post about common usages I wrote a few days ago. The only difference is that you would use SecretLocalMachineCacheinstead of LocalMachineCache for sensitive data.

As always, I hope this post is helpful for some of you.

Until the next post, happy coding!


P.S. Feel free to download my official app for msicc.net, which – of course – uses the implementations above:
iOS Android Windows 10

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 0 comments
Xamarin.Forms, Akavache and I: storing, retrieving and deleting data

Xamarin.Forms, Akavache and I: storing, retrieving and deleting data

Caching always has the same job: provide data that is frequently used in very little time. As I mentioned in my first post of this series, Akavache is my first choice because it is fast. It also provides a very easy way to interact with it (once one gets used to Reactive Extensions). The code I am showing here is living in the Forms project, but can also be called from the platform projects thanks to the interface we defined already before.

Enabling async support

First things first: we should write our code asynchronously, that’s why we need to enable async support by adding using System.Reactive.Linq;to the using statements in our class. This one is not so obvious, and I read a lot of questions on the web where this was the simple solution. So now you know, let’s go ahead.

Simple case

The most simple case of storing data is just throwing data with a key into the underlying database:

//getting a reference to the cache instance
var cache = SimpleIoc.Default.GetInstance<IBlobCacheInstanceHelper>().LocalMachineCache;
var dataToSave = "this is a simple string to save into the database";
await cache.InsertObject<string>("YourKeyHere", dataToSave);

Of course, we need a reference to the IBlobCacheinstance we have already in place. I am saving a simple string here for demo purposes, but you can also save more complex types like a list of blog posts into the cache. Akavache uses Json.NET , which will serialize the data into a valid json string that you can be saved. Similarly, it is very easy to get the data deserialized from the database:

var dataFromCache = cache.GetObject<string>("YourKeyHere");

That’s it. For things like storing Boolean values, simple strings (unencrypted), dates etc., this might already be everything you need.

Caching data from the web

Of course it wouldn’t be necessary to implement an advanced library if we would have only this scenario. More often, we are fetching data from the web and need to save it in our apps. There are several reasons to do this, with saving (mobile) data volume and performance being the two major reasons.

Akavache provides a bunch of very useful Extensions. The most prominent one I am using is the GetOrFetchObject<T>method. A typical implementation looks like this:

var postsCache = await cache.GetOrFetchObject<List<BlogPost>>(feedName,
    async () =>
    {
        var newPosts = await _postsHandler.GetPostsAsync(BaseUrl, 20, 20, 1, feedName.ToCategoryId()).ConfigureAwait(false);

        await cache.InsertObject<List<BlogPost>>(feedName, newPostsDto);

        return newPosts;
    });

The GetOrFetchObject<T>method’s minimum parameters are the key of the cache entry and an asynchronous function that shall be executed when there is no data in the cache. In the sample above, it loads the latest 20 posts from a WordPress blog (utilizing my WordPressReader lib) and saves it into the cache instance before returning the downloaded data. The method has an optional parameter of DateTimeOffset, which may be interesting if you need to expire the saved data after some time.

Saving images/documents from the web

If you need to download files, be it images or other documents, from the web, Akavache provides another helper extension:

byte[] bytes = await cache.DownloadUrl("YourFileKeyHere", url);

Personally, I am loading all files with this method, even though there are some special image loading methods available as well (see the readme at Akavache’s repo). The main reason I am doing so is that until now, I always have a platform specific implementation for such cases – mainly due to performance reasons. I one of the following blog posts you will see such an implementation for image caching using a custom renderer on each platform.

Deleting data from the cache

When working with caches, one cannot avoid the situation that data needs to be removed manually from the cache.

//delete a single entry by key:
cache.Invalidate("KeyToDelete");

//delete all entries with the same type:
cache.InvalidateAllObjects<BlogPost>();

//delete all entries
cache.InvalidateAll();

If you want to continue with some other action after deletion completes, you can use the Subscribe method to invoke this action:

cache.InvalidateAll().Subscribe(x => YourMethodToInvoke());

Conclusion

Even though Akavache provides more methods to store and retrieve data, the ones I mentioned above are those that I use frequently and without problems in my Xamarin.Forms applications, while still being able to invoke them in platform specific code as well. If you want to have a look at the other methods that are available, click the link above to the GitHub repo of Akavache. As always, I hope this blog post is helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 1 comment
Xamarin.Forms, Akavache and I: Initial setup (new series)

Xamarin.Forms, Akavache and I: Initial setup (new series)

Caching is never a trivial task. Sometimes, we can use built-in storages, but more often, these take quite some time when we are storing a large amount of data (eg. large datasets or large json strings). I tried quite a few approaches, including:

  • built-in storage
  • self handled files
  • plugins that use a one or all of the above
  • Akavache (which uses SQLite under the hood)

Why Akavache wins

Well, the major reason is quite easy. It is fast. Really fast. At least compared to the other options. You may not notice the difference until you are using a background task that relies on the cached data or until you try to truly optimize startup performance of your Xamarin Android app. Those two where the reason for me to switch, because once implemented, it does handle both jobs perfectly. Because it is so fast, there is quite an amount of apps that uses it. Bonus: there are a lot of tips on StackOverflow as well as on GitHub, as it is already used by a lot of developers.

Getting your projects ready

Well, as often, it all starts with the installation of NuGet packages. As I am trying to follow good practices wherever I can, I am using .netStandard whenever possible. The latest stable version of Akavache does work partially in .netStandard projects, but I recommend to use the latest alpha (by the time of this post) in your .netStandard project (even if VisualStudio keeps telling you that a pre release dependency is not a good idea). If you are using the package reference in your project files, there might be some additional work to bring everything to build and run smoothly, especially in a Xamarin.Android project.

You mileage may vary, but in my experience, you should install the following dependencies and Akavache separately:

After installing this packages in your Xamarin.Forms and platform projects, we are ready for the next step.

Initializing Akavache

Basically, you should be able to use Akavache in a very simple way, by just defining the application name like this during application initialization:

BlobCache.ApplicationName = "MyAkavachePoweredApp";

You can do this assignment in your platform project as well as in your Xamarin.Forms project, both ways will work. Just remember to do this, as also to get my code working, this is a needed step.

There are static properties  like BlobCache.LocalMachineone can use to cache data. However, once your app will use an advanced library like Akavache, it is very likely that he complexity of your app will force you into a more complex scenario. In my case, the usage of a scheduled job on Android was the reason why I am doing the initialization on my own. The scheduled job starts a process for the application, and the job updates data in the cache that the application uses. There were several cases where the standard initialization did not work, so I decided to make the special case to a standard case. The following code will also work in simple scenarios, but keeps doors open for more complex ones as well. The second reason why I did my own implementation is the MVVM structure of my apps.

IBlobCacheInstanceHelper rules them all

Like often when we want to use platform implementations, all starts with an interface that dictates the functionality. Let’s start with this simple one:

public interface IBlobCacheInstanceHelper
{
    void Init();
    IBlobCache LocalMachineCache { get; set; }
}

We are defining our own IBlobCacheinstance, which we will initialize with the Init() method on each platform. Let’s have a look on the platform implementations:

[assembly: Xamarin.Forms.Dependency(typeof(PlatformBlobCacheInstanceHelper))]
namespace [YOURNAMESPACEHERE]
{
    public class PlatformBlobCacheInstanceHelper : IBlobCacheInstanceHelper
    {
        private IFilesystemProvider _filesystemProvider;

        public PlatformBlobCacheInstanceHelper() { }

        public void Init()
        {
            _filesystemProvider = Locator.Current.GetService<IFilesystemProvider>();
            GetLocalMachineCache();
        }

        public IBlobCache LocalMachineCache { get; set; }

        private void GetLocalMachineCache()
        {

            var localCache = new Lazy<IBlobCache>(() => 
                                                  {
                                                      _filesystemProvider.CreateRecursive(_filesystemProvider.GetDefaultLocalMachineCacheDirectory()).SubscribeOn(BlobCache.TaskpoolScheduler).Wait();
                                                      return new SQLitePersistentBlobCache(Path.Combine(_filesystemProvider.GetDefaultLocalMachineCacheDirectory(), "blobs.db"), BlobCache.TaskpoolScheduler);
                                                  });

            this.LocalMachineCache = localCache.Value;
        }

        //TODO: implement other cache types if necessary at some point
    }
}

Let me explain what this code does.

As SQLite, which is powering Akavache, is file based, we need to provide a file path. The Init() method assigns Akavache’s internal IFileSystemProviderinterface to the internal member. After getting an instance via Splat’s Locator, we can now use it to get the file path and create the .db-file for our local cache. The GetLocalMachineCache()method is basically a copy of Akavache’s internal registration. It lazily creates an instance of BlobCache through the IBlobCacheinterface. The create instance is then passed to the LocalMachineCacheproperty, which we will use later on. Finally, we will be using the DependencyServiceof Xamarin.Forms to get an instance of our platform implementation, which is why we need to define the Dependency attribute as well.

Note: you can name the file whatever you want. If you are already using Akavache and want to change the instance handling, you should keep the original names used by Akavache. This way, your users will not lose any data.

This implementation can be used your Android, iOS and UWP projects within your Xamarin.Forms app. If you are wondering why I do this separately for every platform, you are right. Until now, there is no need to do it that way. The code above would also work solely in your Xamarin.Forms project. Once you are coming to the point where you need encrypted data in your cache, the platform implementations will change on every platform. This will be topic of a future blog post, however.

If you have been reading my series about MVVMLight, you may guess the next step already. This is how I initialize the platform implementation within my ViewModelLocator:

//register:
var cacheInstanceHelper = DependencyService.Get<IBlobCacheInstanceHelper>();
if (!SimpleIoc.Default.IsRegistered<IBlobCacheInstanceHelper>())
     SimpleIoc.Default.Register<IBlobCacheInstanceHelper>(()=> cacheInstanceHelper);

//initialize:
//cacheInstanceHelper.Init();
//or
SimpleIoc.Default.GetInstance<IBlobCacheInstanceHelper>().Init();

So that’s it, we are now ready to use our local cache powered by Akavache within our Xamarin.Forms project. In the next post, we will have a look on how to use akavache for storing and retrieving data.

Until then, happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 1 comment
Xamarin Android: asymmetric encryption without any user input or hardcoded values

Xamarin Android: asymmetric encryption without any user input or hardcoded values

The problem

Android is often said to be one of the most unsecure platforms one can use. This problem is home-made, as there is still a lot of fragmentation. There are thousand of models that do not get the latest updates and security patches, mostly because OEMs (seem to) not care (for different reasons, biggest reason is of course money). On the other side, there are still developers that save user names and passwords in plain text (which is the worst) or have hardcoded values in their code that make it way to easy to compromise encrypted data.

In the past, a lot of us developers made some of those mistakes. Be it because most of the popular samples around the web use hardcoded values (e. g. for the IV) or because of blindly copy & pasting from other websites or by using badly implemented libraries. Everyone should stop using these and use methods that are more secure. One of the most secure ways to do so is to use asymmetric encryption with a private/public key pair. The Android OS is doing a lot to help us generating such a key pair, and I am going to show you how to use it.

AndroidKeyStore

As the name already implies, Android uses the AndroidKeyStoreto keep keys secure. TheAndroidKeyStore is derived from the Java Security implementations and provides:

  • generation of keys and key pairs
  • key material that is maintained out of any application process
  • the key material can be bound to security hardware
  • additional usage limits are implemented in the OS
  • certificate store

Read more on that topic in the official Android documentation.

Encryption with a key pair explained

If you want to handle sensitive data securely in your app (and you should), there are only two ways. Either you are not saving them (which will often keep users not returning to your app or even uninstalling it just because they must type them in over and over again) or encrypt these data before saving it. One of the more secure ways to encrypt data is to use a private/public key pair, also known as asymmetric encryption (because you use one key for encryption and the other for decryption).

The private key is only known to the issuer of the key. In the case of Android, it is the OS or the security hardware that is in built into the device. The private key should always be private, and Android does handle this for us. The public key can be given to external parties (like us developers) to use them for decryption of sensitive data. The OS adds an additional layer and makes sure that only your app(s) are able to use the public key (aka ‘key access validation’).

Of course Google does not make all and everything about that encryption and validation process public (for obvious reasons).

In this post, I will focus on the creation of such a key pair, on how to retrieve a key from the AndroidKeyStoreand in the end, we will of course encrypt some data. My implementation is based on this article series, which provides a whole lot of explanation. If you want to know more about this topic, I absolutely recommend reading it. I will not go to deep into details, if you want to know more, once again, just read the articles linked above.

Let the OS create a key pair for you

The Android OS has two generators – a KeyGenerator and a KeyPairGenerator. The KeyGenerator provides a single key, while we will focus on the KeyPairGenerator, which will give us a brand new private/public key pair.

The first step is to initialize the KeyStore itself, which I am doing in the constructor of my helper class:

       public PlatformEncryptionKeyHelper(Context context, string keyName)
       {
           _context = context;
           _keyName = keyName.ToLowerInvariant();

           _androidKeyStore = KeyStore.GetInstance(KEYSTORE_NAME);
           _androidKeyStore.Load(null);
       }

The essential step here is to load the instance with null, otherwise all other operations will not work. You should also never change the keystore’s name unless you know exactly what you are doing.

Now that we have the KeyStore initialized, let’s go ahead and create a new key pair. As I support Android 5.0 (Lollipop) in my apps, I have also a fallback in place, as the current iteration is only available for device with Android 6 (Marshmallow) and above. Here is the code:

        public void CreateKeyPair()
        {
            DeleteKey();

            KeyPairGenerator keyGenerator =
                KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, KEYSTORE_NAME);

            if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr2 &&
                Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
            {
                var calendar = Calendar.GetInstance(_context.Resources.Configuration.Locale);
                var endDate = Calendar.GetInstance(_context.Resources.Configuration.Locale);
                endDate.Add(CalendarField.Year, 20);

                //this API is obsolete after Android M, but I am supporting Android L
#pragma warning disable 618
                var builder = new KeyPairGeneratorSpec.Builder(_context)
#pragma warning restore 618
                              .SetAlias(_keyName).SetSerialNumber(BigInteger.One)
                              .SetSubject(new X500Principal($"CN={_keyName} CA Certificate"))
                              .SetStartDate(calendar.Time)
                              .SetEndDate(endDate.Time).SetKeySize(KeySize);

                keyGenerator.Initialize(builder.Build());
            }
            else if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
            {
                var builder =
                    new KeyGenParameterSpec.Builder(_keyName, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
                        .SetBlockModes(KeyProperties.BlockModeEcb)
                        .SetEncryptionPaddings(KeyProperties.EncryptionPaddingRsaPkcs1)
                        .SetRandomizedEncryptionRequired(false).SetKeySize(KeySize);

                keyGenerator.Initialize(builder.Build());
            }

            keyGenerator.GenerateKeyPair();
        }

As you can see, the creation of such a key pair is way easier with Android 6 (Marshmallow) and above. I will focus on this part, details for the fallback solution can be found in the articles I linked above. I am requesting a RSA key pair for encryption and decryption, which needs to be specified explicitly. We are using the so called ‘ Electronic Codebook’ encryption mode, which will cut the data to encrypt into blocks that will be encrypted. Also important: the key’s size. A bigger key means more security, but also more time for operations done with it. Android defaults to a key size of 2048 bits, which provides a good average of security and execution time. With this method in place, we are already able to create a brand new key pair.

Note: The DeleteKey()method call beforehand just makes sure we have only one valid key pair with that name available. I am also following Google’s recommendations by calling it before creating a new key.

Retrieving the public key for encryption

Now that the AndroidKeyStoreholds a key pair for us, let us have a look on how to retrieve the public key, which is used for encryption:

public IKey GetPublicKey()
{
    if (!_androidKeyStore.ContainsAlias(_keyName))
        return null;

    return _androidKeyStore.GetCertificate(_keyName)?.PublicKey;
}

Android internally creates a self signed certificate for the key pair (that’s why we had to perform this action manually before Android 6 (Marshmallow). The API makes this visible to us in the case of the retrieval of the public key. Xamarin provides the IKey interface, which is once again inherited from the Java Security APIs.

Retrieving the private key for decryption

Of course, we want to decrypt the data we encrypted at some point. That is as easy as getting the public key:

public IKey GetPrivateKey()
{
    if (!_androidKeyStore.ContainsAlias(_keyName))
        return null;

    return _androidKeyStore.GetKey(_keyName, null);
}

As we did not set a password during the key pair creation, we are passing null in here to get our private key.

Deleting a key pair

There may be situations where you want to delete a key. The AndroidKeyStore has an API available for that as well. You may guess it, it is also very easy to use:

public bool DeleteKey()
{
    if (!_androidKeyStore.ContainsAlias(_keyName))
        return false;

    _androidKeyStore.DeleteEntry(_keyName);
    return true;
}

Usage

As you probably remember, I created a helper class for handling all things related to the AndroidKeyStore. Let’s have a look on how to encrypt and decrypt a string with the help of this class.

_encryptionKeyHelper = new PlatformEncryptionKeyHelper(Application.Context, KeyStoreName);
_encryptionKeyHelper.CreateKeyPair();

_privateKey = _encryptionKeyHelper.GetPrivateKey();
_publicKey = _encryptionKeyHelper.GetPublicKey();

After instantiating the helper class, we use the CreateKeyPair()method to get a key pair. In the full class I will share later in this post, I have another helper that will check if the key already exists. You can use this class to step over the creation part if there is already a key pair.

Now let’s see how encryption works:

//we used these values to create the keys
//now we need to tell the OS to use the same values during encryption/decryption
var transformation = "RSA/ECB/PKCS1Padding";

var stringToEncrypt = "This is a simple string for demo purposes only. Nothing special here.";

var cipher = Cipher.GetInstance(transformation);
cipher.Init(CipherMode.EncryptMode, _publicKey);

var encryptedData = cipher.DoFinal(Encoding.UTF8.GetBytes(stringToEncrypt));

We are using the Cipher class provided by Xamarin, which inherits from the Java Crypto API. The transformation string consists of “algorithm/mode/padding” and needs to be passed to the cipher instance. After specifying that we want to encrypt with the public key, the DoFinalmethod encrypts the string and returns it as a byte array, which can be saved pretty easy.

Decryption works in a similar way:

var transformation = "RSA/ECB/PKCS1Padding"; 

var cipher = Cipher.GetInstance(transformation);
cipher.Init(CipherMode.DecryptMode, _privateKey);

var decryptedBytes = cipher.DoFinal(encyrptedData);
var finalString = Encoding.UTF8.GetString(decryptedBytes);

Once again, we are using the Cipherclass. Remember to initialize the cipher instance once again, because we are using now the decryption mode. The DoFinalmethod will decrypt the encrypted byte array, which can be turned into a string once again.

I did not create a sample project this time. However, the full helper class is available here on my GitHub account as Gist.

Xamarin.Forms tipp: You can make this class available by extracting an interface from it and use the DependencyService to get access from your forms project if necessary.

Conclusion

The security of your user’s data should always be something you are concerned about. With this little helper, we are using the OS (and in some cases also the device) to secure data in your Xamarin.Android app. Sadly, a lot of samples require user interaction or even use some hardcoded values. This should not be used in a production app. Feel free to use my helper class as a starting point.

As always, I hope this post is helpful for some of you. In the next post, I will show you how to use a similar mechanism in your Xamarin.iOS app.

Until then, happy coding, everyone!

 

Posted by msicc in Android, Dev Stories, Xamarin, 9 comments
#XfQaD: Limit maximum lines of Label and indicate text truncation

#XfQaD: Limit maximum lines of Label and indicate text truncation

The problem

Xamarin.Forms.Labelhas a common set of properties we can use to configure how our text is shown. However, it does miss a property to limit the maximum of text lines and a proper indication of eventually truncated text. Knowing that UWP, Android and iOS have working and easy-to-use implementations on their platform controls used for the Xamarin.Forms.Label, there is only one solution to the problem: exposing a custom control and its platform renderers. That’s what we are going to do in this #XfQaD.

XfMaxLines Label implementation

Let’s have a look at the Xamarin.Forms implementation first. I am just adding a BindablePropertyto a derived class implementation to define the maximum of lines I want to see:

public class XfMaxLinesLabel : Label
{
    public XfMaxLinesLabel(){ }

    public static BindableProperty MaxLinesProperty = BindableProperty.Create("MaxLines", typeof(int), typeof(XfMaxLinesLabel), int.MaxValue, BindingMode.Default);

    public int MaxLines
    {
        get => (int)GetValue(MaxLinesProperty);
        set => SetValue(MaxLinesProperty, value);
    }
}

UWP

The UWP renderer uses the TextBlock properties MaxLinesto limit the amount of shown lines, while the TextTrimmingproperty is set to ellipsize the last word before reaching the limit. The implementation is pretty straight forward:

[assembly: ExportRenderer(typeof(XfMaxLinesLabel), typeof(XfMaxLinesLabelRenderer))]
namespace MaxLinesLabel.UWP
{
    public class XfMaxLinesLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (((XfMaxLinesLabel)e.NewElement).MaxLines == -1 || ((XfMaxLinesLabel)e.NewElement).MaxLines == int.MaxValue)
                return;

            this.Control.MaxLines = ((XfMaxLinesLabel)e.NewElement).MaxLines;
            this.Control.TextTrimming = Windows.UI.Xaml.TextTrimming.WordEllipsis;
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == XfMaxLinesLabel.MaxLinesProperty.PropertyName)
            {
                if (((XfMaxLinesLabel)this.Element).MaxLines == -1 || ((XfMaxLinesLabel)this.Element).MaxLines == int.MaxValue)
                    return;

                this.Control.MaxLines = ((XfMaxLinesLabel)this.Element).MaxLines;
                this.Control.TextTrimming = Windows.UI.Xaml.TextTrimming.WordEllipsis;
            }
        }
    }
}

Android

The Android implementation uses the MaxLinesproperty of Android’s TextView control to limit the maximum visible lines. The Ellipsizeproperty is used to show the three dots for truncation at the end of the last visible line. Once again, pretty straight forward.

[assembly: ExportRenderer(typeof(XfMaxLinesLabel), typeof(XfMaxLinesLabelRenderer))]
namespace MaxLinesLabel.Droid
{
    class XfMaxLinesLabelRenderer : LabelRenderer
    {
        public XfMaxLinesLabelRenderer(Context context) : base(context)
        {
        }


        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (((XfMaxLinesLabel)e.NewElement).MaxLines == -1 || ((XfMaxLinesLabel)e.NewElement).MaxLines == int.MaxValue)
                return;
            this.Control.SetMaxLines(((XfMaxLinesLabel)e.NewElement).MaxLines);
            this.Control.Ellipsize = TextUtils.TruncateAt.End;
        }


        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == XfMaxLinesLabel.MaxLinesProperty.PropertyName)
            {
                if (((XfMaxLinesLabel)this.Element).MaxLines == -1 || ((XfMaxLinesLabel)this.Element).MaxLines == int.MaxValue)
                    return;
                this.Control.SetMaxLines(((XfMaxLinesLabel)this.Element).MaxLines);
                this.Control.Ellipsize = TextUtils.TruncateAt.End;
            }
        }
    }
}

iOS

Like Android and Windows, also the UILabel control on iOS has a MaxLinesproperty. You’re right, we’ll use this one to limit the count of visible lines. Using the LineBreakModeproperty, we can automate the text truncation indicator equally easy as on Android and UWP:

[assembly: ExportRenderer(typeof(XfMaxLinesLabel), typeof(XfMaxLinesLabelRenderer))]
namespace MaxLinesLabel.iOS
{
    public class XfMaxLinesLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (((XfMaxLinesLabel)e.NewElement).MaxLines == -1 || ((XfMaxLinesLabel)e.NewElement).MaxLines == int.MaxValue)
                return;

            this.Control.Lines = ((XfMaxLinesLabel)e.NewElement).MaxLines;
            this.Control.LineBreakMode = UILineBreakMode.TailTruncation;
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == XfMaxLinesLabel.MaxLinesProperty.PropertyName)
            {
                if (((XfMaxLinesLabel)this.Element).MaxLines == -1 || ((XfMaxLinesLabel)this.Element).MaxLines == int.MaxValue)
                    return;

                this.Control.Lines = ((XfMaxLinesLabel)this.Element).MaxLines;
                this.Control.LineBreakMode = UILineBreakMode.TailTruncation;
            }
        }
    }
}

Conclusion

As you can see, it is pretty easy to create a line limited, truncation indicating custom Label for your Xamarin.Forms app. The implementation is done in a few minutes, but it makes writing your cross platform app a bit easier. I don’t know why this is not (yet) implemented in current Xamarin.Forms iterations, but I do hope they’ll do so to further reduce the number of needed custom renderers.

In the meantime, feel free to check the sample code on GitHub and use it in your apps. As always, I hope this post is helpful for some of you.

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 1 comment
#XfQaD: read package identity and version from platform project with Xamarin.Forms

#XfQaD: read package identity and version from platform project with Xamarin.Forms

All of my apps, no matter on which platform, need to know their version number (for displaying in app) and their package identifier (for opening them in their store). If you are following around for some time, you know I prefer own solutions in a lot of use cases – that’s why I created another #XfQaD for this task, even if there are plugins around for that.

The concept

Once again, I am utilizing the built-in Xamarin.FormsDependencyService for this task. So the concept is pretty easy:

  • interface that dictates the available options
  • platform implementations that execute the code and return the values I want

Let’s have a look at

The interface

namespace PackageInfo
{
    public interface IAppDataHelper
    {
        string GetApplicationPackageName();

        string GetApplicationVersion();

        string GetApplicationVersionName();
    }
}

The interface provides three string returning methods. As the versioning is different on all three platforms, I return two different version strings to cover that fact.

UWP implementation

The UWP implementation uses the Package class, which provides access to the package information, including those we are interested in. As the UWP has just one version type, it returns the same value for version and version name:

using PackageInfo.UWP;
using Windows.ApplicationModel;
using Xamarin.Forms;

[assembly: Dependency(typeof(AppDataHelper))]
namespace PackageInfo.UWP
{
    public class AppDataHelper : IAppDataHelper
    {
        private Package _package;

        public AppDataHelper()
        {
            _package = Package.Current;
        }

        public string GetApplicationPackageName()
        {
            return _package.Id.FamilyName;
        }

        public string GetApplicationVersion()
        {
            return  $"{_package.Id.Version.Major}.{_package.Id.Version.Minor}.{_package.Id.Version.Build}.{_package.Id.Version.Revision}";
        }

        public string GetApplicationVersionName()
        {
            return $"{_package.Id.Version.Major}.{_package.Id.Version.Minor}.{_package.Id.Version.Build}.{_package.Id.Version.Revision}";
        }
    }
}

Android implementation

The Android implementation uses the PackageManager class, which uses the GetPackageInfo method to provide the information about the currently installed package. As Android has a different version structure (see more info here), it returns two different strings for version and version name:

using Android.Content;
using Android.Content.PM;
using PackageInfo.Droid;
using Xamarin.Forms;

[assembly: Dependency(typeof(AppDataHelper))]
namespace PackageInfo.Droid
{
    public class AppDataHelper : IAppDataHelper
    {
        private readonly Context _context;
        private readonly PackageManager _packageManager;
        public AppDataHelper()
        {
            _context = Android.App.Application.Context;
            _packageManager = _context.PackageManager;
        }

        public string GetApplicationPackageName()
        {
            return _context.PackageName;
        }

        public string GetApplicationVersion()
        {
            return _packageManager.GetPackageInfo(_context.PackageName, 0).VersionCode.ToString();
        }

        public string GetApplicationVersionName()
        {
            return _packageManager.GetPackageInfo(_context.PackageName, 0).VersionName;
        }
    }
}

iOS implementation

Even iOS provides a way to get the package identity and version. It uses the NSBundle.MainBundle implementation to get the info. To get those we are interested in, we just query the InfoDictionarythe MainBundleholds:

using Foundation;
using PackageInfo.iOS;
using Xamarin.Forms;

[assembly: Dependency(typeof(AppDataHelper))]
namespace PackageInfo.iOS
{
    public class AppDataHelper : IAppDataHelper
    {
        private readonly NSDictionary _infoDictionary;

        public AppDataHelper()
        {
            _infoDictionary = NSBundle.MainBundle.InfoDictionary;
        }

        public string GetApplicationPackageName()
        {
            return _infoDictionary[new NSString("CFBundleIdentifier")].ToString();
        }

        public string GetApplicationVersion()
        {
            var appVersionString = NSBundle.MainBundle.ObjectForInfoDictionary("CFBundleShortVersionString").ToString();
            var appBuildNumber = NSBundle.MainBundle.ObjectForInfoDictionary("CFBundleVersion").ToString();

            return $"{appVersionString}.{appBuildNumber}";
        }

        public string GetApplicationVersionName()
        {
            return NSBundle.MainBundle.ObjectForInfoDictionary("CFBundleShortVersionString").ToString();
        }
    }
}

That’s all it takes to get your application’s package identity and version. You can have a look yourself in this GitHub sample and play around with it. If you want to extend and read more information, the above implementation is easily expandable.

As always, I hope this post will be helpful for some of you. Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, UWP, 0 comments
Xamarin Forms, the MVVMLight Toolkit and I: loading bundled assets in the Forms project

Xamarin Forms, the MVVMLight Toolkit and I: loading bundled assets in the Forms project

The scenario …

The reason I came up with this is that I am writing on an Xamarin.Forms web reader app. It is an app that uses a  WebView to display the contents of web articles. Of course, I am using a CSS-file to style the content that gets displayed. I am using the default font of every platform, plus some platform specific settings in there. The easiest way to get it working right is to give every platform its own CSS-file. In the Xamarin.Forms project however, I just want to call one method that gets the thing done.

For this scenario, the well documented Files access in Xamarin.Forms does not work.

This post will not yet be reflected in my ongoing XfMvvmLight project on Github as I have another one building on top of this in my queue. Once the second one is written, the project will show these changes, too. This post will contain the full classes however, so you could C&P them if you want/need.

DependencyService and another interface

If you are following this series already, you might already know that the easiest way to achieve my goal is to use the built-in Xamarin.FormsDependencyService and the needed interface with the native implementations.

So let’s start with the interface:

namespace XfMvvmLight.Abstractions
{
    public interface IAssetPathHelper
    {
        string GetResourceFolderPath(string folderName, bool forWeb = false);

        string GetResourcePath(bool forWeb = false);

        string GetResourceFilePath(string folder, string fileName, bool forWeb = false);
    }
}

The interface dictates three string-returning methods that will either return the base path of the platform resources, a specific folder or the full path to the bundled file. This interface covers most usage scenarios I came across. Feel free to leave any feedback if I am missing out a common one.

The only thing left to do is to register the interface in our ViewModelLocator, like we did already before in the RegisterServices() method:

var assetPathHelper = DependencyService.Get();
SimpleIoc.Default.Register(()=> assetPathHelper);

We are getting the platform implementation via the built in DependecyService and assign in to our Xamarin.Forms interface (like we have done already before). By registering it with our SimpleIoc instance, we can now use it wherever we want in our Xamarin.Forms project.

Platform implementations

Android

If you add files in the Resources folder, you can easily access them via the Resource class in your Android project. However, files like CSS-files are normally placed within the Assets folder of your Xamarin.Android project.

Depending on the usage scenario, we have two ways to access the files in the ‘Assets’ folder. If we are residing in the Xamarin.Android project and want to access the content of those bundled assets, we are able to access them using the Android.App.Context.Assets property and assign it to the Android.Content.Res.AssetManager class. We can then use streams to get the data contained in those files.

This does not help however if we want to access those files from a WebView (both in the Android and the Xamarin.Forms project), that’s why we have to use the ‘file:///android_asset‘ uri-scheme. Here is the platform implementation:

using XfMvvmLight.Abstractions;
using XfMvvmLight.Droid.PlatformImplementation;
using System.Diagnostics;
using System.IO;

[assembly: Xamarin.Forms.Dependency(typeof(AssetPathHelper))]
namespace XfMvvmLight.Droid.PlatformImplementation;
{
    public class AssetPathHelper : IAssetPathHelper
    {
        public string GetResourceFolderPath(string folderName, bool forWeb = false)
        {
            return Path.Combine(GetResourcePath(),folderName);
        }

        public string GetResourcePath(bool forWeb = false)
        {
            //reminding ourselves to double check if this way is really necessary
            if (!forWeb)
            {
                Debug.WriteLine("**********************************");
                Debug.WriteLine("You should consider using AssetManager if you are not using this in a WebView.");
                Debug.WriteLine("See: https://developer.xamarin.com/guides/android/application_fundamentals/resources_in_android/part_6_-_using_android_assets/");
                Debug.WriteLine("**********************************");
            }
            
            //but we are always returning the uri scheme 
            return $"file:///android_asset"; 
        }

        public string GetResourceFilePath(string folder, string fileName, bool forWeb = false)
        {
            var folderPath = string.IsNullOrEmpty(folder) ? GetResourcePath() : GetResourceFolderPath(folder);

            return Path.Combine(folderPath,fileName);
        }
    }
}

The implementation is pretty straight forward. Although we could call all three methods, the one we use probably the most is the GetResourceFilePath method. It will give us the complete path to the resource file, which we can then use in our calling code of our Xamarin.Forms project.

By using the Path.Combine method we make sure we get a valid file path string, which is exactly what we need if we are accessing assets in this way. As most of the scenarios for accessing assets could be easily covered by using AssetManager (see above), I am printing a reminder message that it exists to the output window of VisualStudio.

Important: you have to make sure the Build Action of your files is set to AndroidAsset, otherwise you’ll see nothing, in some scenarios it will even throw exceptions. This accounts for the AssetManager as well as for the AssetPathHelper implementations.

iOS

On iOS, we are able to access bundled assets via the NSBundle class. The implementation is even easier than the one for Android, as this is the only way to get those assets. That’s why we are ignoring the forWeb parameter in this case. Here is the implementation:

using System.IO;
using Foundation;
using XfMvvmLight.Abstractions;
using XfMvvmLight.iOS.PlatformImplementation;

[assembly: Xamarin.Forms.Dependency(typeof(AssetPathHelper))]
namespace XfMvvmLight.iOS.PlatformImplementation
{
    //forWeb is ignored on iOS!
    public class AssetPathHelper : IAssetPathHelper
    {
        public string GetResourceFolderPath(string folderName, bool forWeb = false)
        {
            return Path.Combine(GetResourcePath(), folderName);
        }

        public string GetResourcePath(bool forWeb = false)
        {
            return NSBundle.MainBundle.BundlePath;
        }

        public string GetResourceFilePath(string folder, string fileName, bool forWeb = false)
        {
            var folderPath = string.IsNullOrEmpty(folder) ? GetResourcePath() : GetResourceFolderPath(folder);

            return Path.Combine(folderPath, fileName);
        }
    }
}

Important: Make sure your files have the Build Action set to BundleResource, because otherwise you will once again get some errors flying around your head.

UWP

The implementation of the UWP Assets is once again the one with the most places involved. Let’s have a look at the implementation itself first:

using System.IO;
using XfMvvmLight.Abstractions;

namespace XfMvvmLight.UWP.PlatformImplementations
{
    public class AssetPathHelper : IAssetPathHelper
    {
        public string GetResourceFolderPath(string folderName, bool forWeb = false)
        {
            return Path.Combine(GetResourcePath(forWeb),folderName);
        }

        public string GetResourcePath(bool forWeb = false)
        {
            if (forWeb)
            {
                return $"ms-appx-web:///";
            }
            else
            {
                return $"ms-appx:///";
            }
        }

        public string GetResourceFilePath(string folder, string fileName, bool forWeb = false)
        {
            var folderPath = string.IsNullOrEmpty(folder) ? GetResourcePath(forWeb) : GetResourceFolderPath(folder, forWeb);

            return Path.Combine(folderPath,fileName);
        }
    }
}

The UWP platform uses a separate uri-scheme for all web related things. That’s where the  forWeb parameter comes in handy. If we are not loading a bundled asset for the web, we can use this implementation for other resources as well (bundled placeholder images are a good example here).

The next step is to add the assembly again to the list of assemblies that must be included, like we have done before in the OnLaunched method within App.xaml.cs:

//modified for .NET Compile
//see https://developer.xamarin.com/guides/xamarin-forms/platform-features/windows/installation/universal/#Target_Invocation_Exception_when_using_Compile_with_.NET_Native_tool_chain
List<Assembly> assembliesToInclude =
    new List<Assembly>
    {
        typeof(OsVersionService).GetTypeInfo().Assembly,
        typeof(PlatformDialogService).GetTypeInfo().Assembly, 
        typeof(AssetPathHelper).GetTypeInfo().Assembly
    };

The last step involved in the UWP project is to register the implementation with the DependencyService
after the Xamarin.Forms framework is initialized:

Xamarin.Forms.DependencyService.Register<AssetPathHelper>();

The resources should be packed with a Build Action of Content for the UWP platform.

Back to the Xamarin.Forms project

Now that we have everything in place on our platform projects as well as our Xamarin.Forms project, we finally can start using these methods. Here is an example of loading a CSS-file into a string. We can pass this string together with an HTML-string into a HtmlWebViewSource:

private static string GetCssString(string cssFileName)
{
    var resourcePath = SimpleIoc.Default.GetInstance<IAssetPathHelper>().GetResourceFolderPath("HtmlResources", true);

    return $"<link rel=\"stylesheet\" href=\"{resourcePath}/{cssFileName}\">";
}

Summary

Using the DependencyService of Xamarin.Forms allows us once again to use platform specific functionality very easily. When we are working with WebView and HTML, this comes in handy. If you have other valid scenarios for this implementations or even ideas on how to improve them, feel free to leave a comment below or ping me on my social network accounts. Otherwise, I hope this post is helpful for some of you.

As this is the last post before xmas, I wish you all a merry xmas in addition to my traditional

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 1 comment
[Updated] A workaround for Xamarin Forms 2.5 bug that prevents resource declaration in App.xaml

[Updated] A workaround for Xamarin Forms 2.5 bug that prevents resource declaration in App.xaml

Update: Xamarin appearently solved this problem with Service Release 3 for Xamarin Forms 2.5. I can confirm it works in the app that caused me to write this post.

Additional note: the forms:prefix is no longer needed, just insert the <ResourceDictionary>tag.


If you have a Windows background like I do, one of the most normal things for applications is to create keyed Resources in App.xaml to make them available throughout the app. Something like this should look familiar:

<forms:ResourceDictionary >
    <viewModels:ViewModelLocator x:Key="Locator"></viewModels:ViewModelLocator>
    <forms:Color x:Key="MainAccentColor">#1e73be</forms:Color>
    <forms:Color x:Key="LightAccentColor">#61a1f1</forms:Color>
    <forms:Color x:Key="DarkAccentColor">#00488d</forms:Color>
    <forms:Color x:Key="MainBackgroundColor">#f4f4f4</forms:Color>
</forms:ResourceDictionary>

This is also possible in Xamarin.Forms. Sadly, Xamarin.Forms 2.5 introduced an ugly bug where this declarations throw an ArgumentException, telling us the key(s) already exist in the dictionary (see Bugzilla here). I can confirm that this bug affects at least UWP, Android and iOS applications which use such an implementation.

As this is a show-stopping bug, I had to find a way to work around it for the moment. In such cases, I always try to find a way that has only very little impact. For this particular bug, I just moved the declaration of the resources into the code-behind file, which keeps the rest of my code unchanged. I just created a method that does the work I originally had in the .xaml-file:

//needed because of Xamarin Bug  https://bugzilla.xamarin.com/show_bug.cgi?id=60788
private void CreateResourceDictionary()
{
    //making sure there is only one dictionary
    if (this.Resources == null)
        this.Resources = new ResourceDictionary();

    //making sure there is only one key
    if (!this.Resources.ContainsKey("Locator"))
    {
        this.Resources.Add("Locator", ViewModels.ViewModelLocator.Instance);
    }

    if (!this.Resources.ContainsKey("MainAccentColor"))
    {
        this.Resources.Add("MainAccentColor", Color.FromHex("#1e73be"));
    }

    if (!this.Resources.ContainsKey("LightAccentColor"))
    {
        this.Resources.Add("LightAccentColor", Color.FromHex("#61a1f1"));
    }

    if (!this.Resources.ContainsKey("DarkAccentColor"))
    {
        this.Resources.Add("DarkAccentColor", Color.FromHex("#00488d"));
    }

    if (!this.Resources.ContainsKey("MainBackgroundColor"))
    {
        this.Resources.Add("MainBackgroundColor", Color.FromHex("#f4f4f4"));
    }
}

This makes the application running again like it did before. Once the bug in Xamarin.Forms is fixed, I just have to delete this method and uncomment the XAML-declarations to get back to the state where I was prior to Xamarin.Forms 2.5.

If you are experiencing the same bug, I recommend to also comment on the Bugzilla-Entry (link).

As always, I hope this post is helpful for some of you.

Happy coding!

 

 

Posted by msicc in Android, Dev Stories, iOS, UWP, Xamarin, 4 comments