Google Play Services is a rapidly evolving library that Google has been using to combat fragmentation on the platform, and ensure their developers have access to great new API’s without having to worry about what Android version their users are actually on.
The rate at which this library has evolved recently has been especially challenging for us to keep pace with in getting bindings out for Xamarin.Android, but, rest assured, we are committed to bringing out a great Google Play Services experience in your Xamarin apps. Here are some of the improvements we’ve been making that are now available as pre-release!
Latest and Greatest
Google has rapidly iterated in the last few revisions. We went from 6.5 to 7.0 to 7.3 very quickly, and we’re happy to say we’re shipping the latest and greatest and expect to keep a better track record going forward on getting the latest out quickly!
NOTE: As of this post, the improvements are available on NuGet as 24.0.0-rc1 versioned pacakges.
NuGet what you Want
We’ve now split up Google Play Services into many NuGet packages to match the changes Google made to split them up into many .jar files. Using NuGet we’re able to manage the dependencies between all of the packages. For example, all packages depend on the Google Play Services - Base package, while others such as Location depend on Maps as well.
You can now grab only the packages you need in your app without bringing in everything else. This should help keep your app size down as Google continues to expand Play Services adding more and more features and API’s.
Finally, the old Google Play Services - All package has been kept around to help make the transition easier. It now depends on all of the individual NuGet packages.
Breaking Changes, Nicer Naming
In the process of binding libraries to make them more C# friendly, we often run into cases where casing is different between java and C#. For example, in java, we have
cast.Cast which in C# translates into
Cast.Cast. Since we cannot have a class named the same as its namespace in C#, this presents a problem. Traditionally we have renamed the class, for example to
Cast.CastClass. This isn’t always very discoverable or nice to look at.
We’ve now decided to change the namespaces instead of renaming the conflicting classes. All namespaces now have Sdk appended to them, so we now have
CastSdk.Cast for instance. This should be much more consistent and discoverable going foward.
The other area where this is a problem is with fields in java. For instance,
Fitness.FitnessApi in java both transform into
Fitness.FitnessApi in a C# binding by default. To avoid conflicts and bring consistency across the bindings, we’ve decided to keep the java naming conventions in the C# binding.
You’ll now use the upper-cased
Fitness.FITNESS_API fields to specify an Api to add in your
IGoogleApiClient.AddApi (..) calls, whereas you’ll use the lower-cased
Fitness.FitnessApi fields to actually invoke methods of the given Api.
Happier C# Developers
Our binding tooling generally does a good job at making java libraries more C#-ified. Google Play Services has a number of cases that are less friendly to our tooling and often this has created a sub-par developer experience from a C# perspective.
We’re continuing to work at improving this story in Google Play Services, and there are a couple of changes that should make life better:
A very common pattern in Google Play Services is to make use of the interface
IPendingResult. This is sort of like a
Task - it’s a promise or a future. You can
.Await() it in a blocking manner (though you must do so off the UI thread), or you can
.SetResultCallback (IResultCallback) which means you need to pass in an implementation of the interface which usually means creating an implementor class with some Actions or Events to make the code a bit less ugly (since we don’t have anonymous classes in C#).
You now have more options with
IPendingIntent instances through some extension methods:
1 2 3 4 5 6 7 8 9
Helper Implementor Classes
There’s still a lot of areas that require you pass in some sort of class implementing a listener type of interface.
ILocationListener is a good example. Instead of having to build your own class which implements this simple interface, we’ve added a class
LocationListener which implements
ILocationListener and exposes an event for you. Nothing earth-shattering here, but hopefully it saves you from writing the same boiler plate code over and over.
You can expect more implementation classes like this going forward.
The first place you’ll probably notice the heavy use of interfaces is in the
.AddConnectionCallbacks (..) and
.AddOnConnectionFailedListener (..) methods both require instances of interface implementations as parameters. You can still call these methods like normal, but now there’s extension methods allowing you to pass Action’s into them as appropriate. Again, this is code you could easily write, but shouldn’t have to.
Less p0, p1, p2
This has always been a bit of an eye-sore, to see poorly named parameters. We’ve made some improvements in our tooling that are going to continue to help get better parameter names. We’ve started trying some of these techniques out already in Google Play Services!
I don’t always get to explore all of the API’s inside Google Play Services on a day to day basis, so I’m not always aware of where the pain points are.
I’m very open to feedback if there’s other areas you’d like to see some C# improvements to like we’ve started.
Please don’t be shy, mention me on twitter with any suggestions you have!