Wednesday, October 28, 2015

Choosing a Mobile Development Platform

I've written a lot about the subject of choosing a mobile development platform; how to compare mobile development platforms, which ones perform better and it what circumstance. A lot of what choosing the right mobile development platform comes down to is mitigating the risk of choosing the wrong platform for your organization's needs and having to engage in expensive refactoring or rewrites later in the process.

In my mind, the need for this decision normally comes into play when you have to create applications for more than one mobile platform. Quite frankly, I you have the luxury of only needing to develop for one platform use the native tool set; it will give you the platform vendor's vision on how apps should be developed in a no compromise fashion. Unless you have some existing preference for different development languages or eco-systems, the best choice for single mobile platform scenarios is usually to use the vendor's tool set.

However, for the vast majority of us that just isn't reality. Even within enterprises, the rise of bring your own device has created a situation where needing to develop for multiple platforms is extremely likely. With this in mind I've been increasingly trying to work out a more formulaic approach to thinking about and choosing the right mobile development platform for different situations. The approach I've come up with is STANCE.

STANCE is a system that looks at several pertinent factors in the requirements for a mobile application and then forces you to rank those factors. With this ranking, different development platforms are given a rating on the STANCE factors. With this in mind, you have the ability to measure how different mobile development platforms rate on the stance factors, and you should pay particular attention to the factors you rank the highest.

First let's take a look at those factors and what they mean:

Speed / performance - how important is it that your application perform CPU intensive tasks, rendering, external applications calls with the best performance possible? Do you really have a CPU intensive application that will push the bounds of the mobile platform or do you just need good enough?

Time to complete / Cost - Is the time and cost a significant factor? I would not underestimate or under-rank this metric.

Always working with the newest standards / APIs - Will your application always be using the latest technologies of the mobile platforms. For example, will you start using 3D Touch or the newest design standards shortly after they are released or will those types of changes not be a significant factor in your application until sometime after they are released?

Native user experience - How sensitive are your users to having a true native experience in your application? Will your users be put off if your Android application isn't using Material design or will they be OK if it's close enough or potentially even uses web design standards?

Complex hardware / platform API interactions - Will your application need different or very specific interactions with the device's hardware or APIs? For example, does your application need to have a check scanning algorithm utilizing the camera, direct access to Health Kit or precise control over the format and bit rate audio and video are being recorded at?

Enterprise Services and Tools - Are there some particular enterprise services or tool sets that have already been decided on or your organization has decided should be used. If the development technology doesn't work with one of these, will it mean that your app is a non starter for meeting corporate standards or communicating with corporate services?

Each of these factors should be rated against the others. This is done instead of a straight ordering to get a relative weight on each of the factors; just how more important is one compared to the others? To do the ranking you can use a chart like the following:


To use this chart look at each of the green cells and ask yourself which is more important, the one on the Y axis or the item on the X axis. For example, the first cell compares T(ime/cost) to S(peed/performance). If cost of the application is more important to the application draw a symbol pointing to the T, otherwise one pointing to the S. It may even be useful to have several different stakeholders fill this out to make sure there is agreement on what the priorities and requirements of the solution are. A filled out chart may look like the following:


To use this simply assign one point to each metric where it has been selected as the more important. In the above example we find the following rankings:

S - 2
T - 5
A - 2
N - 2
C - 1
E - 3

(Note: The total of all the ranking should always be 15)

In the above example, far and away the most important factor of making this application would seem to be keeping the cost low. It is more important to anything else; scoring a full five points. It would also appear that integrating with some enterprise services and tools is also reasonably important while complex hardware interactions do not appear to be particularly important to this application at all.

With this understanding we can now look at how they compare to some of the development platforms that are available. I have scored some of the ones we use at Magenic, but with a little research you could score other mobile development platforms as well (I have scored on a scale of 1-8 with the higher number being that the platform is better at delivering that metric).

Cordova:
The Cordova platform has many compromises but it also has one particular area where it shines. If you can work within the bounds of its plugins, don't have complex hardware interactions, are not overly concerned with it fully looking native and performance isn't a huge issue then Cordova will create cross platform applications faster and cheaper than any other mobile development technology on this list.

Xamarin Platform:
The Xamarin Platform has very few compromises. The largest compromise it does have is in Time / cost. It certainly does better than the native technologies but in our experience only 40-60% of code is shared, depending on the business logic of the application. The user interface is written once on each platform and mobile applications then to have a lot of user interface code and potentially platform specific API calls.

Some of you may notice that the Xamarin Platform didn't get a full score for always working with the newest standards / APIs. This would seem to be somewhat at odds with their day one support of new APIs that Xamarin is known for. The reason why I didn't score them fully here is that occasionally a change to an ecosystem is so fundamental that it takes Xamarin a while to implement. An example of this is when iOS started supporting 64 bit applications. It took the Xamarin Platform quite a while to re-architect for this change, only releasing a stable version within a month of when Apple stopped accepting new apps to the store that were not on the 64 bit standard. You can be reasonably confident that Xamarin will fulfill your needs for always working with the newest standards / APIs and also should be prepared for the off chance of a fundamental change happening where day one support does not appear.

Xamarin.Forms:
Xamarin.Forms is much more of a compromise than the Xamarin Platform. There is a slight Speed / performance penalty, it isn't as good as always using the latest standards / APIs (for example, it didn't implement elements of Android Material design for quite some time after it was released), there is not as much flexibility in the design and complex hardware interactions require writing platform specific code. But those penalties compared to the Xamarin Platform are offset by a better Time / Cost score. If your app can work with the limitations of forms then you can write cross platform applications at a cost advantage over the Xamarin Platform. The cost advantage isn't quite as good as it is for Cordova, but then again the other trade offs are not quite so severe.

Native:
When it comes to using the platform's native development technology  and creating cross platform applications there is one primary trade off that is being made, it is usually the most expensive way to do it. You will have to create and maintain two or more completely separate code bases. But in every other way the native development platform gets full marks. Even in Enterprise Services and Tools that all tend to tread the native development technologies as first class citizens, which is usually not the case with other mobile application development technologies. It is for this reason why when there is only one platform I usually starting thinking about native.

Now you might notice even though I scored the rankings of the factors that are required for the application I don't then take it the next step and formulaicly compare it to the ratings of the development platforms. I don't do this because it usually isn't a formulaic answer. For example, if you find it critical that your app work with some enterprise service or tool, then really what is required is some research to find out which mobile development platforms work with your selected enterprise services and that's what will matter.

In many cases there are usually other more subjective factors that come into play or ones that are very context sensitive. For example, if your entire development team is familiar with .Net, in which technology would they be more likely to create well architected, stable and maintainable applications? Another factor that may complicate these ratings are the design of the UI itself. I have seen many digital agencies create mobile application designs that are more akin to websites than native mobile applications. In such cases HTML based technologies such as Cordova really start becoming more attractive.

The STANCE metrics do not lead you to the absolute, in all circumstance,s correct mobile development platform based on your needs. There are just too many situational and subjective factors involved to make a completely formulaic approach. Instead, it gives you a tool to start thinking about what factors are more and less relevant to your mobile efforts and from that what tools are more and less likely to fulfill those needs. STANCE won't, in and of itself, clearly identify the one and only mobile development platform for your problem, but it will help you mitigate risk so you are more likely to choose the one that best fits your needs.

Monday, August 17, 2015

Accessing Azure AD information from .Net Azure Mobile Services and the Xamarin Client

I've been busy, really busy of late but recently I encountered an interesting problem while working on a while paper comparing Xamarin with PhoneGap. I wanted to back this all by Azure Mobile Services and also use Azure AD for authentication. There are lots of articles out there that explain exactly how to tie the two together and it worked great. This is one such article that is very useful: Authenticate your app with Active Directory Authentication Library Single Sign-On.

The instructions in there are simple enough to follow and getting this to work in my Android application is similarly simple. But when I authenticate, what exactly is it that I get back? Take the following code called in my mobile application:

var token = await service.LoginAsync(this, MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory);

When I look at the token object I find that it contains two properties; MobileServiceAuthenticationToken and UserId. Neither of these looks like anything but binary goo. That's fine, but I want to show the user of the application things like their name stored in AD, AD id, find out what roles they are in and do things like find all the users in a role. How do I do this with .Net Azure Mobile Service backed by Azure AD?

First I found some articles that gave me some clues. Nick's .Net Travels talked about doing this with the Azure AD Graph API. and this is fine but he used the ActiveDirectoryClient class. This worked great for me but I noticed that some of the versions of the required dependencies of Microsoft Azure Active Directory (Microsoft.Azure.ActiveDirectory.GraphClient) Nuget package were of a different version than is required by Microsoft Azure Mobile Services .NET (WindowsAzure.MobileServices.Backend.Entity) version 1.0.470. As of the time of this writing Microsoft Azure Mobile Services .NET, which I needed for my .Net Azure Mobile Service backend, had some dependencies such as one on System.spacial version 5.6.2 and only version 5.6.2. The current version of Microsoft.Azure.ActiveDirectory.GraphClient uses a minimum version of 5.6.4. I tried updating the version that the .Net Azure Mobile Services project used under the hood to 5.6.4 but eventually my Azure Mobile Service stopped working with an error complaining about the version 5.6.2 not being installed. I then found this article on Nick's .Net Travels that illustrated the same problem.

The upshot of the deal, You cannot use any version of the Microsoft.Azure.ActiveDirectory.GraphClient library that uses the ActiveDirectoryClient class introduced in version 2.0.0. Instead you must use version 1.0.3 or earlier of the Nuget package. I ended up editing the Packages.config and project files manually to point to this older version. Since I can't use the ActiveDirectoryClient class, I'm stuck using the older GraphConnection class. With all that in mind, let's look at how I solved two common scenarios using a .Net back end of Azure Mobile Services authenticating with Azure AD.

Problem 1: I want to get information about the logged in user other than the binary parts of the token I get back from the login request.

I want to show the user their AD id or their full names after having logged in, but none of that is returned from the Azure Mobile Services client in Xamarin Android or iOS. I don't want the client trying to hit Azure AD directly so in my .Net Windows Azure Mobile service project I create a new ProfileController that inherits from ApiController to get the currently logged in user's profile information from Active Directory:

[AuthorizeLevel(AuthorizationLevel.User)]
[RoutePrefix("api/Profile")]
public class ProfileController : ApiController
{
    // GET api/Profile
    public async Task<UserProfile> Get()
    {
        var authenticationResult = await Utils.AdIntegration.GetAuthenticationTokenAsync();
        var credentials = await Utils.AdIntegration.GetCredentialsAsync(User);
        var graphConnection = new GraphConnection(authenticationResult.AccessToken);
        var adUser = graphConnection.Get<User>(credentials.ObjectId);
        var groups = graphConnection.GetLinkedObjects(adUser, LinkProperty.MemberOf, null, -1);

       var returnValue = new UserProfile
       {
            FullName = adUser.DisplayName,
            FirstName = adUser.GivenName,
            LastName = adUser.Surname,
            UserId = adUser.UserPrincipalName,
            Manager = groups.Results.ToList().Any(g => g.ObjectId == CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.ManagerAdGroup))
        };
        return returnValue;
    }
}

Some things to notice off the top, the line [AuthorizeLevel(AuthorizationLevel.User)] decorating the class locks this class down so only logged in users can call the get method. It is marked async because I'm about to make asynchronous I/O calls out to get information from Azure AD.

First thing I did was get the Authentication token for the currently logged on user.  To do this I implemented the following GetAuthenticationTokenAsync method:

public async static Task<AuthenticationResult> GetAuthenticationTokenAsync()
{
    ClientCredential clientCred = new ClientCredential(CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.ClientId), CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.ClientSecret));
    AuthenticationContext authenticationContext = new AuthenticationContext(string.Format(CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.Authority), CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.AdSite)), false);
    return await authenticationContext.AcquireTokenAsync(Constants.AdIntegration.Graph, clientCred);
}

The Azure AZ class's ClientCredential takes as constructors the client id and client secret you created when connecting your Azure Mobile Services Account to Azure AD. In my example I'm storing these in the Azure Mobile Service's configuration. With that I get the authentication context using the Authority and AD site name setup for Azure AD. In my case it was: https://login.windows.net/{0} and testincidentqueue.onMicrosoft.com. Finally I returned the token from the AcquireTokenAsync method on the authentication context.

With my token in hand, I now needed to get my credentials. To do that I called the GetCredientalsAsync Method I created. This method appears as the following:

public async static Task<AzureActiveDirectoryCredentials> GetCredentialsAsync(IPrincipal user)
{
    var serviceUser = (ServiceUser)user;
    var identities = await serviceUser.GetIdentitiesAsync();
    return (identities != null && identities.Count > 0) ? (AzureActiveDirectoryCredentials)identities[0] : null;
}


This method takes the ApiController's User object for the currently logged in user as a property and casts it into a ServiceUser. If the user is logged into Azure Mobile Services using Azure AD, this should always be a valid cast. With this object I return the first identity found in the GetIdentitiesAsync method, there should only be one.

With the credentials I now have the access token of the current user and with the identity I have the user's AD object Id that I can query against. I use these to tell the AD graph that I want the user with the Id I returned from the identity.  I also query the linked objects of that returned AD user to find out what AD groups this user is a member of. The rest is just returning the results to the caller.

From my client I can now make the following call to my mobile services to get information about the logged in user in Azure AD:

var profile = await service.InvokeApiAsync<UserProfile>("Profile", HttpMethod.Get, null);

Problem 2: I want to get information about all the users in the system who belong to a particular AD group.

This is a similar problem to what I solved before. However, in this case I need to know the AD object Id of the group I'm querying for. In my case it was always the same group so I stored the group Id in the mobile service's configuration. My class looked like this:

[AuthorizeLevel(AuthorizationLevel.User)]
[RoutePrefix("api/WorkerList")]
public class WorkerListController : ApiController
{
    // GET api/WorkerList
    public async Task<IList<UserProfile>> Get()
    {
        var authenticationResult = await AdIntegration.GetAuthenticationTokenAsync();
        var graphConnection = new GraphConnection(authenticationResult.AccessToken);
        var adWorkers = graphConnection.Get<Group>(CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.WorkerAdGroup));
        var members = graphConnection.GetLinkedObjects(adWorkers, LinkProperty.Members, null, -1);

        var returnValue = new List<UserProfile>();
        foreach (var member in members.Results)
        {
            var user = member as User;
            if (user != null && (!user.AccountEnabled.HasValue || user.AccountEnabled.Value))
            {
                var groups = graphConnection.GetLinkedObjects(user, LinkProperty.MemberOf, null, -1);
                returnValue.Add(new UserProfile
                    {
                        FullName = user.DisplayName,
                        FirstName = user.GivenName,
                        LastName = user.Surname,
                        UserId = user.UserPrincipalName,
                        Manager = groups.Results.ToList().Any(g => g.ObjectId == CloudConfigurationManager.GetSetting(Constants.ConfigurationKeys.ManagerAdGroup))
                    });                    
            }
        }
        return returnValue;
    }
}

I started the same way as last time, I ensured there was a user logged in to access the Get method and then got the authentication token for the currently logged on user that I can use to connect to Azure AD. Like last time I query AD but instead of querying the User objects with a user's object Id, I query the groups with the group Id stored in the service's configuration. Calling GetLinkedObjects on a group gets me the members of a group, which is exactly what I want. With this it is simply a matter of enumerating through the group members and sending the results back to the caller.

To use this I make a similar call from the client as last time:

var workers = await service.InvokeApiAsync<IList<UserProfile>>("WorkerList", HttpMethod.Get, null);

That's it. Making simple queries against Azure AD is possible as long as you use the correct version of the libraries and know how to call into the old API.

All code and a working Azure Mobile Service .Net project can be found in the development branch under the Azure folder of the following repository:

https://github.com/Magenic/WhitepaperPerformance/tree/develop

Wednesday, April 29, 2015

Microsoft's Windows 10 Allows You to Run Android and iOS Apps

Today Microsoft made an announcement that Windows 10 will allow Android applications to run in an Android AOSP subsystem. Additionally, Objective-C applications can be compiled and run on Windows 10 as well as universal applications. These announcements, particularly the later, surprised and excited many of us. I've been speaking with a lot of people both inside and outside of Magenic on what all of this means, or could possibly mean, given our limited understanding. (For details See Kevin McLaughlin's article and Mary Jo Foley's article)

First there are some pretty important technical questions raised by this:
- What will the applications look like in Windows 10? If the Android applications are just running in a ASOP subsystem then presumably you would have a bunch of applications looking and navigating like native Android applications on your Windows 10 device. That may be OK for some applications but probably not others.

- How about access to system services and 3D rendering? If I need access to the hardware GPS can one application running in the Android subsystem do that while a Windows 10 application tries to get at it at the same time. This could be handled but I'm curious as to the level to which it is handled or if there be dragons.

- For Objective-C what if my application is accessing HealthKit? I assume HealthKit is not available in Windows 10 when I port my code. When running an Android application how about Google services, can I install them in the subsystem?

- It seems Apple is putting a huge effort behind Swift but MS only mentioned Objective-C; will there be Swift support some time in the future? I just finished writing a white paper on when to use Objective-C vs. Swift. Until and unless MS also supports doing this with Swift, this could change the equation for applications that ever may be expected to run on Windows 10. For that concern, Objective-C would be the one that could work.

- I've heard that Objective-C apps may support porting over Xibs but not Storyboards. If true that could limit the applications that can be ported over without refactoring.

I look forward to learning more and getting some answers to some of these questions. Early days! :)

Even with all those questions, there are a few conclusions that we can come to with what we currently know today.

- One question I've seen floating around is do we still need solutions like Xamarin or NativeScript. The answer is absolutely yes. These new capabilities allow us to more easily run Android applications written in Java to our Windows 10 devices and compile Objective-C code into unified applications for Windows 10. What they don't do is allow you to run your applications written in Objective-C on an Android device or in Java on iOS. For this type of cross platform work you need a different cross platform tool. Then there is the question of will it look right on the platform? Technologies like Xamarin and NativeScript solve that problem, this will not.

- I've heard a comparison with when OS/2 was designed to run Windows applications to help capture the market from Windows and it did it poorly with the conclusion that Microsoft should expect the same result with Android and iOS apps running on Windows 10. Does this argument have any legs? Maybe in some ways, but not too much of a worry. OS/2 failed for many reasons, many of which had nothing to do with having Windows compatibility. But there is one area in particular where the analogy partially seems to hold true, handheld mobile devices. Like OS/2, Windows is not the dominant player in this space and is fighting entrenched leaders. But even then I don't give the argument too many legs. Like OS/2, Windows 10 will will likely stand or fall based on its strengths in the tablet space and will have an uphill battle in the mobile space just because there is so much momentum behind the leaders. If there is any detrimental impact of Android or Objective-C code on Windows 10 will be small next to that. Given the potential upside of additional applications, certainly a viable and likely small risk.

- Applications that rely on platform specific services like HealthKit or Google Play Services are unlikely to just work. The upshot of the deal, if you are writing an Objective-C or Android Java applications that accesses those services then all of the cross platform concerns come into play, just like they do writing a Xamarin application. Suddenly you have to think clearly about things like inversion of control patterns around platform specific services and writing a different implementation for the Windows platform that may change or even disable functionality.

- Microsoft has made a big deal of giving away Windows 10 and trying to get people to move. Now we see part of the reason as these capabilities are unlikely to be back ported to Windows 8.1 or Windows Phone. So the quicker users move the better. However, the enterprise is notoriously slow to move. How much this lag will carry over to the tablet space remains to be seen but it has been a much faster cycle for mobile phones.

- This move has obviously been made because it is very difficult to attract developers to a platform when there are few users and users to a platform when there are few applications. By lowering the bar to run many existing applications on Windows 10 they have made moves to help solve that equation and completely changed the price point to entry. However, this does have its limits. If I'm currently writing a native Android or iOS app, getting it to work on Windows is still not free. If I'm very lucky all I'm looking at is increased platform testing and perhaps compilation costs in terms of Objective-C. If I'm not lucky I'm re-architecting portions of my application to abstract out capabilities and services I can't access or otherwise don't work on Windows 10. For public facing apps on smart phone devices, software companies will still have to determine if that reduced cost is worth the 3% of US smart phone marketshare. Such investment may be much easier to justify in places like Europe where Windows Phone holds a 10% share.

Final thoughts
If this works well it will undoubtedly increase the attractiveness of the Windows 10 platform, particularly in the tablet space. No matter how you cut it, it is just another example in a long line of examples of how Microsoft has changed and become a very different company than it was a few short years ago. Microsoft continues to show us that it is a fighter and willing to make fundamental changes to stay relevant.

I feel great knowing that I can find enhanced utility in my ability to write Java and Objective-C. However, for my clients that need cross platform applications they almost always are looking at the two big smart phone players; Android and iOS. For that, I will continue to use tools like Xamarin and .Net.

I do wonder if this portends some future movement of MS into Xamarin's space. There were talks of acquisition last year that never materialized. Xamarin is a small player and that can work if they can hide in a niche. I see MS and Xamarin working more an more together so Microsoft is definitely getting interested in that niche. I know a lot of guys at Xamarin and they are a nice and passionate bunch that deserve credit and reward for what they have done to advance the cause and capabilities of X-Platform mobile development. No matter how this turns out I hope they receive the recognition and reward they deserve for their pioneering work.

This move by Microsoft makes a large shift in how I think about the different platforms and their capabilities and I look forward to continuing to evaluate the impact of this as we know more.

Sunday, March 22, 2015

Starting with Microsoft Band and Xamarin

Recently Xamarin released their API for Microsoft Band that works with Android, iOS and Windows Phone. It was a tough choice on what to play with before vacation;  a new Xamarin Forms preview that works with Windows Store and Windows Phone 8.1 was released as well as Xamarin Everywhere that hits Android Wear and Apple Phone. A complete overload of super cool stuff.

But ... last week I got a new Microsoft Band and you know, time to play.  First off, the Band isn't really a Smart Watch.  It's more a like a fitness device on steroids.  You can pull all kinds of sensor information out of it, you can also send notifications to it and play with it's appearance. What you can't really do is input information into the Band and have to do something on the phone. That is to say the band is about collecting sensor information and consuming information but not for inputting information like a "true" smart watch allows.

Xamarin has wrapped the Microsoft platform APIs, pretty much verbatim. One thing they have done which is nice is if the calls are asynchronous on Android, they have Task returning versions. However, like the Microsoft platform specific versions the APIs do not match from platform to platform so making cross platform code will still be challenging unless you wrap them in your own unified interface.  Xamarin has a nice page on the component store that explains the basics of the APIs which are pretty easy to use.  They can be found here:

https://components.xamarin.com/view/microsoft-band-sdk

With that in mind I set out to give this a try.  Since my Band is currently synchronized with an Android device I am working with the Android version of the API.  First I figured I'd try to add and then remove an icon from my Band that could receive notifications and messages.  I created a class to open and close the connection.

public class BandConnection : IDisposable
{
    private IBandClient bandClient;
    private Activity context;

    public BandConnection(Activity context)
    {
        this.context = context;
        var pairedBands = BandClientManager.Instance.GetPairedBands();

        if (pairedBands != null && pairedBands.Length >= 1)
        {
            bandClient = BandClientManager.Instance.Create(context, pairedBands[0]);
        }
    }

    public async Task ConnectAsync()
    {
        if (bandClient == null)
        {
            throw new InvalidOperationException("BandClient is not set");
        }
        await bandClient.ConnectTaskAsync();
    }

    public async void Dispose()
    {
        if (bandClient != null && bandClient.IsConnected)
        {
            await bandClient.DisconnectTaskAsync().ConfigureAwait(false);
        }
    }
}

The class just takes in the current activity and then gets the first band registered with the device. If you were making a "real" application it may be a good idea to make some sort of screen to choose what Band the user wanted to connect to if there were more than one.  The ConnectAsync method opens the connection to the Band.  As you can see I use the ConnectTaskAsync method of the BandClient instead of ConnectAsync.  All the asynchronous Android APIs seem to be wrapped up with Task returning operations with that naming convention.  When the class is disposed, if the bandClient is connected, the connection is closed.

I added a simple method to create a new tile on my band if there is room for one.

public async Task AddTileAsync(string tileId, string tileName, BandIcon largeIcon, BandIcon smallIcon)
{
    if (bandClient == null)
    {
        throw new InvalidOperationException("BandClient is not set");
    } 
    var tiles = await bandClient.TileManager.GetTilesTaskAsync().ConfigureAwait(false);
    var id = UUID.FromString(tileId);

    var spacesRemaining = await bandClient.TileManager.GetRemainingTileCapacityTaskAsync().ConfigureAwait(false);
    if (spacesRemaining > 0 && !tiles.Any(t => t.TileId.ToString() == tileId))
    {
        var tileBuilder = new BandTile.Builder(id, tileName, largeIcon);
        if (smallIcon != null)
        {
            tileBuilder.SetTileSmallIcon(smallIcon);
        }
        var tile = tileBuilder.Build();
        await bandClient.TileManager.AddTileTaskAsync(context, tile);
    }
}

I have added two images to my Android project, as per the API specs. One image is 24x24 and the other 48x48.  I create them and convert them into the BandIcon format. The following code is what I used to call the AddTileAsync method.

using (var bandConnection = new BandConnection(this))
{
    if (bandConnection.BandClient != null)
    {
        await bandConnection.ConnectAsync().ConfigureAwait(false);
        var smallIconBitmap = ((BitmapDrawable)Resources.GetDrawable(Resource.Drawable.PhoneFinderSmall)).Bitmap;
        var smallIcon = BandIcon.ToBandIcon(Bitmap.CreateScaledBitmap(smallIconBitmap, 24, 24, false));
        var largeIconBitmap = ((BitmapDrawable)Resources.GetDrawable(Resource.Drawable.PhoneFinderLarge)).Bitmap;
        var largeIcon = BandIcon.ToBandIcon(Bitmap.CreateScaledBitmap(largeIconBitmap, 48, 48, false));

        await bandConnection.AddTileAsync(BandConstants.TileId, "Band Test", largeIcon, smallIcon).ConfigureAwait(true);
    }
}

When using this code it automatically sinks up to the device.  The tile is identified by a unique identifier that I added as a constant to my code. When running it will first ask the user if they want to add the new tile to the Band. You can see my "awesome" abilities as an icon designer:


After choosing allow the band synchronizes the new tile onto the Band.


By scrolling the tiles on the band the newly added tile appears.


I then added a method to remove the tile I just added.

public async Task RemoveTileAsync(string tileId)
{
    if (bandClient == null)
    {
        throw new InvalidOperationException("BandClient is not set");
    } 
    var tiles = await bandClient.TileManager.GetTilesTaskAsync().ConfigureAwait(false);
    var id = UUID.FromString(tileId);
    if (tiles.Any(t => t.TileId.ToString() == tileId))
    {
        await bandClient.TileManager.RemoveTileTaskAsync(id).ConfigureAwait(false);
    }
}

This worked without incident and the tile from my band went away.

Sending a message to the band was also simple. The API reference contains the following description on the difference between a message and a dialog:

App notifications come in two flavors:
- Dialogs – dialog notifications are popups meant to quickly display information to the user. Once the user dismisses the dialog, the information contained therein does not persist on the Band.
- Messages – message notifications are sent and stored in a specific tile, and a tile can keep up to 8 messages at a time. Messages may display a dialog as well.

I added this method to my class to create a message:

public async Task ShowMessageAsync(string tileId, string title, string body, DateTime date, bool showMessage)
{
    if (bandClient == null)
    {
        throw new InvalidOperationException("BandClient is not set");
    }
    var id = UUID.FromString(tileId);
    await bandClient.NotificationManager.SendMessageTaskAsync(id, title, body, date, showMessage);
}

This method calls into my ShowMessageAsync method and gets the device location, converts it to an address and displays it to the user.

using (var bandConnection = new BandConnection(this))
{
    if (bandConnection.BandClient != null)
    {
        await bandConnection.ConnectAsync().ConfigureAwait(false);

        var geocoder = new Geocoder(this);
        var addressList = await geocoder.GetFromLocationAsync(_currentLocation.Latitude, _currentLocation.Longitude, 10).ConfigureAwait(false);

        var address = addressList.FirstOrDefault();
        if (address != null)
        {
            var deviceAddress = new StringBuilder();
            for (int i = 0; i < address.MaxAddressLineIndex; i++)
            {
                deviceAddress.Append(address.GetAddressLine(i))
                .AppendLine(",");
            }

            await bandConnection.ShowMessageAsync(BandConstants.TileId, 
                "Test Message", 
                string.Format("Current address: {0}", deviceAddress), 
                DateTime.Now, 
                true).ConfigureAwait(true);
        }
    }       
}

The message comes across to the band as expected.


Additionally, as expected, a message indicator appears with our tile stating that one new message was received.


When selecting the tile the message appears fully (I blocked out my address).


Sending a dialog is similarly easy.  But as this test indicates the amount of text that can be displayed in the dialog is limited and there is no down button (see more) as with the message.  Dialogs should only be used for very short notifications.

public async Task ShowDialogAsync(string tileId, string title, string body)
{
    if (bandClient == null)
    {
        throw new InvalidOperationException("BandClient is not set");
    }
    var id = UUID.FromString(tileId);
    await bandClient.NotificationManager.ShowDialogTaskAsync(id, title, body);
}

When sending this over it shows up as a popup but does not add to the message counter or add to the message history. As the API documentation stated, the dialog is not retained.


That's it for my first go.  Vibrating the band was similarly easy. Next I'll poke around at getting data from the Band and perhaps customizing its appearance.  Generally I was pleased at how easy it was to work with but cross platform applications may want to create a unified interface.

Tuesday, March 3, 2015

Direct casting vs. As and Linq Single, SingleOrDefault, First, FirstOrDefault

There are tons of articles on these two topics but I still see it so many times I'm putting out a quick reminder.

This:

var someVariable = someOtherVariable as SomeType;

Or this:

var someVariable = (SomeType)someOtherVariable;

I come across people doing the first when they should be direct casting (the second) all the time in code reviews.  When I come across the first the first thing I look for, somewhere very soon after in the code, is a null check.  Why? because using the syntax of the first means that you expect that someOtherVariable may be not castable to SomeType and when that happens someVariable will be set to null.  That is to say that since it may be something other than SomeType, you need to handle that case in code.

If however, someOtherVariable should always have at value that is castable to SomeType and anything else is a logic error somewhere in the code, then you should be using direst casting.  Direct casting will throw an exception right then and there if it is not SomeType and that's what you want. Why?  Because somewhere in your code you have a logic error and you want to find out about it as soon as possible.  Pretty simple to remember.

OK, what are the differences between these Linq statements:

var someVariable = someOtherVariable.First(r => r.SomeValue == "value");

var someVariable = someOtherVariable.FirstOrDefault(r => r.SomeValue == "value");

var someVariable = someOtherVariable.Single(r => r.SomeValue == "value");

var someVariable = someOtherVariable.SingleOrDefault(r => r.SomeValue == "value");

Here is my easy way to remember:

First: ( 1 .. n) It is valid to have one or more results and you want/get the first.  If there are no results that is a logic error and should throw an exception.

FirstOrDefault: ( 0 .. n) It is valid to have zero, one or more valid results and you want/get the first.  Generally if you have no valid result someVariable will be set to null, similar to the "as" syntax above.

Single: ( 1 .. 1 ) It is valid to have one and only one result.  Anything else (zero or more than one) is considered a logic error and will throw an exception.  Great for unique Ids when you know the record should be in the collection

SingleOrDefault: ( 0 .. 1): There should be zero or one result, more than one matching result will throw an exception.  Generally if you have no valid result someVariable will be set to null, similar to the "as" syntax above.  Great for unique Ids when you don't know if the record has been added to the collection and if it isn't in there, you need to add it.

I see these misused all the time too, particularly people favoring FirstOrDefault.  When I've asked them about it misuse usually comes from not understanding the statements or aversion to throwing an exception (i.e they think to themselves, but what if there are no, or many results).

The aversion to throwing an exception in these cases is wrong headed thinking.  Yes, exceptions that get to the user are bad, but logic errors can be similarly bad.  Even worse is logic errors that you don't catch immediately that lead to exceptions later on and now you have the unenviable task of trying to trace back and figure out many lines of code before your variable was set to null in a situation that never should have happened and you didn't handle.

Using the "as" syntax or FirstOrDefault out of a desire to avoid exceptions is a bad practice similar to swallowing exceptions.  Don't do it.  Fail right away and you as the developer will likely find the problem, and if you don't QA has a better chance to than if you simply don't throw and exception and keep going.  By swallow the problem by using "as" or FirstOrDefault you increases the chance that the person finding an issue will be the end user and you will likely have a harder time tracking down the problem and some egg on your face.

Wednesday, February 4, 2015

Mobile Development Platform Performance Part 2 (Native, Cordova, Classic Xamarin, Xamarin.Forms)

This is the second in the series comparing sample test applications using vendor native development technologies (Objective-C, Java), Cordova (using Microsoft's Multi-Device Hybrid Apps), classic Xamarin and Xamarin Forms.  This time I decided to focus on IO using the different frameworks.  For this I used SqLite to save and retrieve records and also just writing and reading from plain text files.

For some background on testing methodology using Android and iOS.

The Development Platforms
- Native (Objective-C 64 bit and Java)
- Cordova (Multi-Device Hybrid Apps) using Intel's App Framework for the UI
- Classic Xamarin (64 bit unified beta for iOS)
- Xamarin.Forms (64 bit unified beta for iOS with Xamarin Forms version 1.3.1)

The Devices
- iPad Mini (non Retina) running iOS 8.1.1 (12B435)
- ASUS K00F running Android 4.2.2

The Test Apps
Applications were made for each of the development platforms that are functionally similar. There was little (if no) effort to make them look exactly the same or even look "good".  But they looked about the same.

The Timing Methodology
Due to difficulties in knowing when things are "done", particularly with JavaScript, timings were handled via stopwatch.  Each timing was taken ten times and the results were averaged.  It should noted that hand timings have an accuracy of about 2/10 of a second so that does give us an approximate margin of error.  In the previous post I showed the 10 individual timings and the average.  This time to save me some typing I'm just showing the average of the ten timings.

Test 1: Test App Size
As mentioned in the last set of test, the size of the application can impact how much bandwidth it takes to deploy and also have some impact on load times.  For Android the size of the APKs was examined.  For iOS I looked ipa files for ad-hoc deployment.


Development PlatformSize
Android
Java921kb
Cordova417kb
Classic Xamarin2.1mb
Xamarin.Forms3.4mb
iOS
Objective-C (64 bit)55kb
Cordova621kb
Classic Xamarin2.95mb
Xamarin.Forms8.17mb

A few interesting things to look at here.  First is the Cordova apk is actually smaller than the vendor native tools on Android.  I suspect this has to do with differences in size of the SqLite libraries for both of the platforms.  Also while the Xamarin APKs are larger, they are not as large as they were on the first set of tests.  For this I used the linking option of Link All Assemblies.  This was probably important for Xamarin Forms which is, of course, just a library on top on Classic Xamarin.  For whatever reason I was not able to get the Link All Assemblies option to stay with Xamarin iOS and you see the results with Link SDK assemblies only instead.

Test 2: Load Times
Like the last test I verified how long the applications took to load into memory.  The results were similar to the set of tests I did previously.

Development PlatformTest Avg.
Android
Java1.044
Cordova4.068
Classic Xamarin1.689
Xamarin.Forms3.032
iOS
Objective-C1.14
Cordova2.138
Classic Xamarin1.204
Xamarin.Forms1.928

As last time vendor native technologies load the fastest.  Xamarin Classic follows closely with Xamarin Forms somewhat after that.  In all cases, Cordova is the slowest loading.  It is interesting that on iOS Xamarin Forms loaded almost as slowly as the Cordova app.  Of course for iOS, nothing really took that long to load.

Test 3: Adding 1,000 records to SqLite
I originally wanted to add 10,000 records but found that too slow on my Android device and also it didn't scroll well under Cordova where my implementation had no auto paging.  Offline storage is a common need with mobile applications and SqLite is one of the few solutions that span all platforms.

* I have had a few comments that there are better performing ways to do this test.  For example I could have inserted 1,000 records in the same transaction or if I wanted to do it one one record in one transaction at a time, I could have done it asynchronously.  Both of these points are undoubtedly true.  Through SqLite you can get 1,000 records into the local database in much quicker ways on all platforms than this tests indicates.  What this test is doing is looking at synchronously saving a single record in a single implicit transaction and doing that 1,000 times for all platforms.  It would probably not be too difficult to do the other tests as suggested and they may be the source of a future post.  Thank you to everyone who commented.

Java:
public void addRecord(String firstName, String lastName, int index, String misc) throws Exception {
    if (dbConn == null) {
        openConnection();
    }

    ContentValues values = new ContentValues();
    values.put("firstName", firstName);
    values.put("lastName", lastName + index);
    values.put("misc", misc);
    dbConn.insertOrThrow(TABLE_NAME, null, values);
}

Objective-C:
- (void)addRecord:(NSString*)firstName withLastName:(NSString*)lastName withIndex:(int)index withMisc:(NSString*)misc withError:(NSError**)error {
    NSString *sqlStatement = NULL;
    char *errInfo;
    *error = nil;

    if (dbConn == nil) {
        [self openConnection:error];
        return;
    }
    
    sqlStatement = [NSString stringWithFormat:@"%@%@%@%@%d%@%@%@", @"INSERT INTO testTable (firstName, lastName, misc) VALUES ('", firstName, @"', '", lastName, index, @"', '", misc, @"')"];
    
    int result = sqlite3_exec(dbConn, [sqlStatement UTF8String], nil, nil, &errInfo);
    
    if (result != SQLITE_OK) {
        NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
        [errorDetail setValue:[NSString stringWithFormat:@"%@%s", @"Error writing record to database: ", errInfo] forKey:NSLocalizedDescriptionKey];
        *error = [NSError errorWithDomain:@"testDomain" code:101 userInfo:errorDetail];
    }
}

JavaScript:
function addRecords() {
    $.ui.blockUI();
    var maxValue = 999;
    var successCount = 0;
    var db = window.sqlitePlugin.openDatabase({ name: "testDB.db" });

    for (var i = 0; i <= maxValue; i++) {
        var lastName = "person" + i.toString();
        db.executeSql("INSERT INTO testTable (firstName, lastName, misc) VALUES (?,?,?)", ["test", lastName, "12345678901234567890123456789012345678901234567890"], function (res) {
            successCount++;
            if (successCount === maxValue) {
                $.ui.popup({
                    title: "Success",
                    message: "All records written to database",
                    doneText: "OK",
                    cancelOnly: false
                });
                $.ui.unblockUI();
            }
        }, function (e) {
            $.ui.popup({
                title: "Error",
                message: "An error has occurred adding records: " + e.toString(),
                doneText: "OK",
                cancelOnly: false
            });
            $.ui.unblockUI();
            return;
        });
    }
}

Xamarin (All Versions):
public void AddRecord(string fName, string lName, int i, string m)
{
    if (dbConn == null)
    {
        OpenConnection();
    }

    var testRecord = new TestTable {firstName = fName, id = 0, lastName = lName + i, misc = m};

    dbConn.Insert(testRecord);
}

Xamarin Android Alternate:
public void AddRecord(string fName, string lName, int i, string m)
{
    if (dbConn == null)
    {
        OpenConnection();
    }

    var testRecord = new TestTable {firstName = fName, id = 0, lastName = lName + i, misc = m};

    dbConn.Insert(testRecord);
}

Development PlatformTest Avg.
Android
Java18.569
Cordova24.126
Classic Xamarin32.55
Xamarin.Forms30.873
Xamarin Classic Alternate18.341
iOS
Objective-C8.044
Cordova14.944
Classic Xamarin8.151
Xamarin.Forms8.137
*results in seconds

Right off the bat you might notice that Xamarin on Android did poorly.  Very poorly.  Slower than native Android or Cordova by a large margin.  One thing I noticed is that in native Android I used the SQLiteOpenHelper but this is only available in the Android API.  I used the method I did because it was cross platform and you can see the results on Android.  SQLiteOpenHelper is available in the SqLite Xamarin Library for Android and on a hunch I tried it instead and you can see those timings under Xamarin Classic Alternate for Android and the timing were virtually the same as they were for Java.  I suspect if I used this for Xamarin.Forms I would have gotten about the same advantages.  The lesson from this is just because there is a cross platform version of the API, it doesn't mean it will perform well.  Buyer beware.

Test 4: Querying SqLite Records
I wanted to test reading the 1,000 records I just wrote.  I only did the 1,000 I originally wrote because I didn't want to deal with paging solutions for Cordova.  A 10,000 record test performed very poorly when just creating a 10,000 for HTML table.

Java:
public ArrayList<String> getAllRecords() throws Exception {
    if (dbConn == null) {
        openConnection();
    }

    ArrayList<String> returnValue = new ArrayList<String>();
    String sqlStatement = "SELECT * FROM " + TABLE_NAME;
    Cursor cursor = dbConn.rawQuery(sqlStatement, null);

    if (cursor.moveToFirst()) {
        do {
            returnValue.add(cursor.getString(1) + " " + cursor.getString(2));
        } while (cursor.moveToNext());
    }

    return returnValue;
}

Objective-C:
- (NSMutableArray*)getAllRecords:(NSError**) error {
    NSString *sqlStatement = NULL;
    NSMutableArray *results;
    sqlite3_stmt *sqlResult;
    char *errInfo;
    *error = nil;
    
    if (dbConn == nil) {
        [self openConnection:error];
        return nil;
    }
    
    sqlStatement = @"SELECT * FROM testTable";
    results = [[NSMutableArray alloc] init];

    int result = sqlite3_exec(dbConn, [sqlStatement UTF8String], nil, nil, &errInfo);
    
    result = sqlite3_prepare_v2(dbConn, [sqlStatement UTF8String], -1, &sqlResult, nil);
    
    if (result == SQLITE_OK) {
        while (sqlite3_step(sqlResult)==SQLITE_ROW) {
            NSString* firstName = [NSString stringWithFormat:@"%s", (char*)sqlite3_column_text(sqlResult, 1)];
            NSString* lastName = [NSString stringWithFormat:@"%s", (char*)sqlite3_column_text(sqlResult, 2)];
            NSString* fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
        
            [results addObject:fullName];
        }
        sqlite3_finalize(sqlResult);
        return results;
    } else {
        NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
        [errorDetail setValue:@"Error loading records" forKey:NSLocalizedDescriptionKey];
        *error = [NSError errorWithDomain:@"testDomain" code:101 userInfo:errorDetail];
        return nil;
    }
}

JavaScript:
function showSqlRecords(sql) {
    var db = window.sqlitePlugin.openDatabase({ name: "testDB.db" });
    db.executeSql(sql, [], function (res) {
        try {
            var lstRecords = $("#lstRecords");
            lstRecords.empty();
            var lastValue = res.rows.length;
            for (var i = 0; i < lastValue; i++) {
                var listItem = "<li>" + res.rows.item(i).firstName + " " + res.rows.item(i).lastName + "</li>";
                lstRecords.append(listItem);
            }
        } catch (err) {
            alert(err.toString());
        }
    });
}

Xamarin (All Versions):
public IList<string> GetAllRecords()
{
    if (dbConn == null)
    {
        OpenConnection();
    }

    var results = (from t in dbConn.Table<TestTable>() select t ).ToList(); 

    var returnList = new List<string>();

    foreach (var result in results)
    {
        returnList.Add(string.Format("{0} {1}", result.firstName, result.lastName));    
    }
    return returnList;
}

Xamarin Android Alternate:
public IList<string> GetAllRecords() 
{
    if (dbConn == null) {
        OpenConnection();
    }

    var returnValue = new List<String>();
    var sqlStatement = "SELECT * FROM " + TABLE_NAME;
    var results = dbConn.RawQuery(sqlStatement, null);

    if (results.MoveToFirst()) {
        do 
        {
            returnValue.Add(results.GetString(1) + " " + results.GetString(2));
        } while (results.MoveToNext());
    }
    return returnValue;
}


Development PlatformTest Avg.
Android
Java0.551
Cordova1.117
Classic Xamarin1.144
Xamarin.Forms0.89
Xamarin Classic Alternate0.601
iOS
Objective-C0.792
Cordova1.1745
Classic Xamarin0.799
Xamarin.Forms0.735
*results in seconds

Reading records in Android was similarly bad for Xamarin on Android until I switched to the SQLiteOpenHelper implementation and then performance came online with the native example.  As usual the interpreted JavaScript in Cordova slower but probably won't be a factor unless there is a large operation reading thousands of lines.

Test 5: Writing Lines to a File
I also wanted to test writing lines to a text file and how that performs.  For each platform I write 1,000 lines to a file.

Java:
public void writeLineToFile(String line) throws Exception {
    if (!textFile.exists()) {
        this.createFile();
    }
    if (fileHandle == null) {
        this.openFile();
    }

    fileHandle.write(line);
}

Objective-C:
- (void)writeLineToFile:(NSError**)error withTextToWrite:(NSData*)textToWrite {
    *error = nil;

    if (fileHandle == nil) {
        [self openFile:error];
    }
    
    if (*error == nil) {
        [fileHandle seekToEndOfFile];
        [fileHandle writeData:textToWrite];
    }
}

JavaScript:
file.createWriter(function (fileWriter) {
    fileWriter.seek(fileWriter.length);
    var count = 0;
    var line;
    var message = "Writing line to file at index: ";
    var maxLines = 999;
    fileWriter.onwriteend = function(evt) {
        count += 1;
        if (count <= maxLines) {
            line = message + count + "\\n";
            fileWriter.write(line);
        } else {
            $.ui.unblockUI();
            $.ui.popup({
                title: "Success",
                message: "All lines written to file.",
                doneText: "OK",
                cancelOnly: false
        });
    }
};
line = message + count + "\\n";
fileWriter.write(line);

Xamarin (All Versions):
public void WriteLineToFile(String line) 
{
    if (!File.Exists(filePath)) 
    {
        this.CreateFile();
    }
    if (streamWriter == null) 
    {
        this.OpenFile();
    }

    streamWriter.WriteLine(line);
}

Development PlatformTest Avg.
Android
Java0.504
Cordova3.045
Classic Xamarin0.658
Xamarin.Forms0.715
iOS
Objective-C0.835
Cordova4.721
Classic Xamarin1.217
Xamarin.Forms1.17
*results in seconds

When it comes to writing lines to a text file the vendor native technologies are the undisputed leaders in high performance.  Xamain on iOS is close and a little slower on Android.  Cordova comes in at 3-4 times slower than the other technologies.  Some of this may come from the interpreted looping logic and not the plugin but the reality is that the overhead of the interpreted code that calls into the plug happens if you write one line or a thousand.

Test 6: Reading Lines from a File
Compliment to test 5, reading those 1,000 lines from a file and displaying them on a list.

Java:
public ArrayList<String> readFileContents() throws Exception {

    BufferedReader reader = new BufferedReader(new FileReader(textFile));
    String line;
    ArrayList<String> returnValue = new ArrayList<String>();

    while((line = reader.readLine()) != null){
        returnValue.add(line);
    }
    reader.close();
    return returnValue;
}

Objective-C:
- (NSArray*)readFileContents:(NSError**)error {
    *error = nil;

    if (fileHandle == nil) {
        [self openFile:error];
    }
    
    if (*error == nil) {
        [fileHandle seekToFileOffset: 0];
        NSData* fileContents = [fileHandle readDataToEndOfFile];
        NSString *fileString = [[NSString alloc] initWithData:fileContents encoding:NSUTF8StringEncoding];
        return [fileString componentsSeparatedByString:@"\r\n"];
        
    } else {
        return nil;
    }
}

JavaScript:
file.file(function(innerFile) {
    var reader = new FileReader();

    reader.onerror = function(e) {
        alert("Error");
    }
    reader.onloadend = function (e) {
        var lines = e.target.result.split("\\n");
        var lstFileLines = $("#lstFileLines");
        lstFileLines.empty();
        if (lines.length > 1) {
            for (var i = 0; i < lines.length - 2; i++) {
                var listItem = "<li>" + lines[i] + "</li>";
                lstFileLines.append(listItem);
            }
        }
    };
    reader.readAsText(innerFile);
}, function(ex) {
    $.ui.popup({
        title: "Error",
        message: "Error occurred opening file: " + ex.description,
        doneText: "OK",
        cancelOnly: false
});

Xamarin (All Versions):
public IList<string> ReadFileContents()
{
    if (!File.Exists(filePath))
    {
        this.CreateFile();
    }

    var returnValue = new List<String>();

    using (var streamReader = new StreamReader(filePath))
    {
        string line;
        while ((line = streamReader.ReadLine()) != null)
        {
            returnValue.Add(line);
        }
    }
    return returnValue;
}


Development PlatformTest Avg.
Android
Java0.438
Cordova1.126
Classic Xamarin0.596
Xamarin.Forms0.847
iOS
Objective-C0.727
Cordova1.16
Classic Xamarin0.706
Xamarin.Forms0.776
*results in seconds

You want fast, go for native.  Xamarin is as good or nearly as good except for Form on Android.  This may have more to do with the performance of the list display than the actual reading of the list.  That should be comparable to classic Xamarin.  Same comments on Cordova as before, it's slower.  If this is a factor or not depends a lot about the type of application.

I hope some of you find these comparisons helpful.  The lessons I learned from this set of tests were:
- It is self-evident that not all implementations of code even on the same development platform perform the same.  Having said that, be careful of wrappers around libraries that have unified APIs to allow for cross platform code.  It may not perform as well as the specialized libraries for Android or iOS.
- While it is hard to differentiate slowness in code that comes from it being interpreted and what comes from the libraries they are using, to some extent it doesn't matter.  In production apps the Cordova JavaScript code will be interpreted as it calls into plugins like SqLite so both will be a factor.
- The linking settings on Xamarin can have a huge difference in the size of the app.  If you are using external libraries where you are not likely to use all the functionality use the Link All Assemblies option if possible.

Thanks everyone.

Source code for the tests can be found here: Performance Tests Source