My New (First) Book and This Year

eBook: $40 | Print + eBook: $50

This has been a great year so far, I have released multiple new components on the Xamarin Component Store, committed thousands of lines of code into various repositories, and, finally had my book published!

It has been a long time coming, originally scheduled for about 6 months, but working full time had forced me to go a bit slower. So after 12 months of work, Packt Publishing, made my book, “Xamarin Mobile Development for Android Cookbook”, available to the world.

Beginning Writing

In September last year, they contacted me about authoring a book focused on more advanced concepts when developing Android apps using the Xamarin platform. I cover concepts ranging from using basic UI elements, to managing view states. I also show how one can make use of Bluetooth and NFC communication. Included in the topics are some that cover modern app development, such as making use of the Android support libraries to create modern apps that run on almost all versions of Android.

I won’t lie and say that the book was easy; writing is pretty hard. Once the topic is decided and the code ready, the actual readable text takes a bit of work. I feel that I was able to bring each recipe across in an easy-to-consume manner without compromising on the actual content. This is a lot of work in that it is sometimes hard to write a technical document without knowing the knowledge level of the reader.
In addition to that, sometimes I had to research why I did something. I have done something so many times that it has become automatic, and then I have to go and learn why. And then I sometimes realize that what I had been doing all this time was only one way…

All in all, I quite enjoyed writing, even if it meant very late nights. If I was to write another book, well, it might be some time in the future. I hope that my book sells well, not because of money, but it is an accomplishment. How many people can say they have written a book, and how many of those can say they wrote a good book. If this book sells well, then I would have achieved one of my life goals.

After I first found out about software development when I was 9 years old, I wanted to become a programmer. After the release of Windows, I wanted to be the new Bill Gates. I don’t think I’ll ever get to that level of awesomeness, but I can go for the other things. One of those things is to provide developers with tools that they can use to create the best that can be created.

Why I Started

When I started developing professionally, my projects were ASP.NET websites and Desktop applications. This is great, but typically those apps were company apps and only used during work hours. Mobile apps have always been a passion of mine in that they travel with the user. I have always liked being a back end developer as this is often the area where the “cool” work is done. The UI is great, don’t get me wrong, but almost all of them talk to some library or service.

During my years of development, I really grew to love my work more and more. This love grew into something that I want to share with the world. It started off by helping by brother do a bit of development. He now has built several games using many of the game creation tools. One of the coolest, and most cross-platform, is Scirra’s Construct 2. Recently, he has started using Unity 3D.

Another way I shared my love for development is though my code. I have several repositories on GitHub, which I try and update. I also use this account to update repositories in the community. Sometimes there is that awesome library, but just doesn’t have that feature… For example, there is this tiny library, NLipsum, that allows you to generate a chunk of lorerm ipsum. Although technically not very useful, it is often the simplest way to populate text fields. This library required no changes, but could only be used with desktop .NET platforms. In the age of mobile development, I was able to add a new project that created a Portable Class Library, which can be used everywhere. This is not a headlines-worthy change, but NLipsum is now more cross-platform than ever before.

Writing a book was just another way to share my knowledge and love of development with the world. I hope my book helps both the new guy on the block as well as the other guy that never got around to using In-App billing in his popular Android app. As a result, I am not going to tell you to buy my book… If you want to check it out, or use it to get started with Xamarin.Android apps, you can order it in both an ebook and/or print from Packt Publishing for $32.

Stretching Views with Auto Layout on iOS

I am busy porting my Windows Phone app to Android and iOS, and everything seems to be going quite well. I am using MvvmCross with Xamarin Platform Tools and there is much code reuse.

This is a simple app, literally two screens that could actually be merged into a single screen: A ID number entry form and a status page with a few lines of text. However an app is an app and an Android, iOS and Windows Phone app is still just awesome to have.

This is my first attempt at creating an iOS app from scratch. I have done a couple of Android apps for various companies, but iOS is still ultra new for me. So far as I can see, Apple has created a huge API with many great interfaces. The iOS API is more mature than the Android API, and this shows in many areas.

One of the awesome features that I came across is the Auto Layout features of creating interfaces. My app’s start screen has a view that contains the controls and an image view underneath. The controls view is of a fixed size as it just contains a text box and a button, but the image scaled to fit the remaining space.

On Windows Phone, I was just using a Grid with an expandable row and set the image to fill it. On Android, I placed the image view inside a LinearLayout and set the weight to 1. On iOS, I wasn’t sure… I recalled from my previous dabbling that there was some Autoresizing options, but after reading around, there seems to be something better, Auto Layout.

Eventually, I discovered that this is quite powerful, but a little more complex. What I needed to do was set the image view to be “anchored” at various points. In this case, the image was to expand to fill the space, so I naturally set the top, left bottom and right sides to be pinned at a nice space from the edge of the screen.

I expected the view, if pinned at the top and at the bottom, would grow as the points moved apart, unfortunately for me, there was something that I missed. The height. When I looked around, there was a little icon showing that there was a problem with my constraints. It picked up that there was a problem with the heights of my views, but I wasn’t sure what to do exactly.

My first solution to the problem, but actually wasn’t a solution was to see if there was a way to tell the image view to be expandable. For some reason it did not occur to me that if it was growing horizontally and not vertically, I needed to check to see what was different there. But anyway, I found a little option called “Intrinsic Size” and if I set this to “Placeholder” all the errors went away, but sadly for me, this has little to do with my problem. Intrinsic Size is for when there is shadows or other decoration features that the layout engine should ignore. Even though there were no errors, the actual app on the device just failed and the image was stretched over everything. Sad.

So, it finally occurred to me that if my image was anchored below the controls view, I may actually need to specify a height for the controls. This is not exactly intuitive as it should use the designer’s size automatically, but that’s just me. Anyway, after giving the controls view a height, the running app now correctly stretched my image from the bottom of the view to the bottom of the screen, or, filled the space. Yay!

Because I am cool with images, and Balsamiq Mockups, I have prepared an image for the viewers:

Auto Layout on iOS

Genetics for Xamarin.Android

As with all my development, I try to do as little as possible 🙂 The more code you type, the more you have to maintain and bugfix.

Now, being that I enjoy working on libraries/backends rather than on UI/frontends, I like my code to be neat and clean. Sure, the final app must be good, but I read the code.

So, I looked around and found a simple way to reduce the overall boilerplate code, as well as improve the final code. Although good code doesn’t mean a good app, bad code often results in a poor app.

A Practical Example

This library is focused around only one small things, but that one small thing is done over and over again everywhere… boilerplate! This one thing is getting hold of an Android View or Resource based on the ID.

For example, if we have an Activity with X amount of UI widgets that we need to access:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:padding="8dp">
  <TextView
    android:id="@+id/myLabel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textSize="50sp" />
  <Button
    android:id="@+id/myButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp" />
  <ListView
    android:id="@+id/myListView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:layout_margin="10dp" />
</LinearLayout>

Then, usually we would have X number of FindViewById method calls and X fields:

private TextView myLabel;
private Button myButton;
private ListView myListView;

protected override void OnCreate(Bundle savedInstanceState)
{
  base.OnCreate(savedInstanceState);

  SetContentView(Resource.Layout.MyActivityLayout);

  myLabel = this.FindViewById<TextView>(Resource.Id.myLabel);
  myButton = this.FindViewById<Button>(Resource.Id.myButton);
  myListView = this.FindViewById<ListView>(Resource.Id.myListView);
}

This is not much code as it stands, but it is a bit monotonic if you ask me… especially if you have a good few widgets on the screen.

Now, this is where Genetics comes in. We can replace all those FindViewById methods with a single Splice method call, and annotate the fields, or properties, with the [Splice] attribute:

[Splice(Resource.Id.myLabel)]
private TextView myLabel;
[Splice(Resource.Id.myButton)]
private Button myButton;
[Splice(Resource.Id.myListView)]
private ListView myListView;

protected override void OnCreate(Bundle state)
{
  base.OnCreate(state);

  SetContentView(Resource.Layout.MyActivityLayout);

  Geneticist.Splice(this);
}

And that’s all there is to it!

Resources

Not only can we avoid all the FindViewById method calls, but we can also avoid querying the Resources object for the various values. Given the resource file:

<resources> 
  <string name="titleText">Genetics</string> 
</resources>

We can automatically populate the field or property in the same way as with the views.

[Splice(Resource.String.loginError)]
private string loginErrorMessage;

protected override void OnCreate(Bundle state)
{
  // ...

  Geneticist.Splice(this);
}

Fragments

A special case exists when the target object instance that contains the widgets is not an Activity, Dialog or View. This is most commonly used when inflating views, as when using a Fragment:

public class MyFragment : Fragment
{
  [Splice(Resource.Id.textView)]
  private TextView textView;

  public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle state)
  {
    var view = inflater.Inflate(Resource.Layout.MyFragmentLayout, container, false);

    Geneticist.Splice(this, view);

    return view;
  }
}

List Views

Another popular case is when working with a ListView and the view holder pattern for the list items:

public class SimpleAdapter : BaseAdapter
{ 
    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        ViewHolder holder;
        if (convertView != null)
        {
            holder = (ViewHolder)convertView.Tag;
        }
        else
        {
            convertView = inflater.Inflate(Resource.Layout.SimpleListItem, parent, false);
            holder = new ViewHolder(convertView);
            convertView.Tag = holder;
        }

        holder.word.Text = ...;
        holder.length.Text = ...;
        holder.position.Text = ...;

        return convertView;
    }

    private class ViewHolder : Java.Lang.Object
    {
        [Splice(Resource.Id.word)] 
        public TextView word;
        [Splice(Resource.Id.length)] 
        public TextView length;
        [Splice(Resource.Id.position)] 
        public TextView position;

        public ViewHolder(View view)
        {
            Geneticist.Splice(this, view);
        }
    }
}

Downloading & Using

There is lots more that can be done, or rather, not done, using Genetics. The best way to get hold of this library is either through the Xamarin Components Store or from NuGet.

This library is really tiny, and has no dependencies other than Android…

Lots more information can be found on the Getting Started guide as well as in the github.

Self-Signed Certificates and Xamarin.Android

Recently, I had the opportunity to work with Android and self-signed certificates. This is both simple and complex at the same time. In order for Android to be able to handle self-signed certificates, those certificates have to be registered with the SSLSocketFactory.

The HTTP Client

What we will need to do is create a new SSLSocketFactory, and pass that to the HTTP client. In this case, we are using OkHttpClient to communicate over the network. OkHttp is an HTTP+SPDY client for Android applications, and can be found:

Once we have the socket factory, we pass it to the OkHttpClient using the SetSslSocketFactory method:

// get the socket factory
var socketFactory = GetSocketFactory();
// create a new OkHttpClinet 
var client = new OkHttpClient();
// add the socket factory to the client
client.SetSslSocketFactory(socketFactory);
// now we can use the client as usual
Request request = new Request.Builder().Url(&quot;https://&lt;yourserver&gt;&quot;).Build();
Response response = await client.NewCall(request).ExecuteAsync();
var body = await response.Body().StringAsync();

SSL The Socket Factory

In order to create the socket factory, we will need the self-signed certificate. This can be downloaded from the website, or obtained from the source. Then, we must include it in the app. In this instance, I have added it as a raw resource. Loading the certificate into the socket factory consists of a few steps:

  1. Load the certificate out of the resources/assets and into a Certificate instance
  2. Create a new KeyStore instance, and add the Certificate
  3. Create a new TrustManagerFactory instance from the KeyStore
  4. Get the IX509TrustManager from the TrustManagerFactory
  5. Create the new SSLContext, and initialize with the IX509TrustManager
  6. Get the SocketFactory from the SSLContext

Here is the code that does this:

/// &lt;summary&gt;
/// This method returns the configured SSLSocketFactory that contains
/// the self-signed certificate.
/// &lt;/summary&gt;
public static SSLSocketFactory GetSocketFactory()
{
    // Load our certificate from resources (we created this one using OpenSSL and 
    // saved as a .cer using Windows' certlm console)
    var certificateFactory = CertificateFactory.GetInstance(&quot;X.509&quot;);
    Certificate certificate;
    using (var stream = Application.Context.Resources.OpenRawResource(Resource.Raw.selfsigned)) {
      certificate = certificateFactory.GenerateCertificate(stream);
    }

    // Create a KeyStore containing our trusted CAs
    var keyStore = KeyStore.GetInstance(KeyStore.DefaultType);
    keyStore.Load(null, null);
    keyStore.SetCertificateEntry(&quot;ca&quot;, certificate);

    // Create a TrustManager that trusts the CAs in our keystore
    var algorithm = TrustManagerFactory.DefaultAlgorithm;
    var trustManagerFactory = TrustManagerFactory.GetInstance(algorithm);
    trustManagerFactory.Init(keyStore);
    var trustManagers = trustManagerFactory.GetTrustManagers();
    var trustManager = trustManagers[0].JavaCast&lt;IX509TrustManager&gt;(); 

    // Create an SSLContext that uses our TrustManager
    var context = SSLContext.GetInstance(&quot;TLSv1.2&quot;);
    context.Init(null, new ITrustManager[]{ new CompleteX509TrustManager(trustManager) }, null);    

    // return the final socket factory
    return context.SocketFactory;
}

The Trust Manager

Because we are usinmg a custom trust manager with a custom keystore that only contsins the one self-signed certificate, all other certificates will be rejected. To avoid this, we wrap the trust manager in a new trust manager that first tries the default trust manager. Only when the default trust manager fails to verify the certificate, we try the custom trust manager:

/// &lt;summary&gt;
/// This trust manager wraps a custom socket factory and provides a
/// fallback to the default trust manager with the system certificates.
/// This allows the app to communicate not only with a self-signed 
/// server, but also servers with certificates from a CA.
/// &lt;/summary&gt;
public class CompleteX509TrustManager : Java.Lang.Object, IX509TrustManager
{
    private readonly IX509TrustManager defaultTrustManager;
    private readonly IX509TrustManager localTrustManager;

    public CompleteX509TrustManager(IX509TrustManager localTrustManager)
    {
        this.localTrustManager = localTrustManager;

        var algorithm = TrustManagerFactory.DefaultAlgorithm;
        var defaultTrustManagerFactory = TrustManagerFactory.GetInstance(algorithm);
        defaultTrustManagerFactory.Init((KeyStore)null);
        var trustManagers = trustManagerFactory.GetTrustManagers();
        defaultTrustManager = trustManagers[0].JavaCast&lt;IX509TrustManager&gt;();
    }

    public void CheckClientTrusted(X509Certificate[] chain, string authType)
    {
        // we are the client
    }

    public void CheckServerTrusted(X509Certificate[] chain, string authType)
    {
        try {
            defaultTrustManager.CheckServerTrusted(chain, authType);
        } catch (CertificateException) {
            localTrustManager.CheckServerTrusted(chain, authType);
        }
    }

    public X509Certificate[] GetAcceptedIssuers()
    {
        // we are not the server
        return null;
    }
}

Some of the namespaces used are in the Java and Javax namespaces:

using Java.Interop;
using Java.Net;
using Java.Security;
using Java.Security.Cert;
using Javax.Net.Ssl;

Enabling TLS v1.2 on Android 4.2

While I was busy making self-signed certificates work on Android, I had to add support for TLS version 1.2 on Android 4.2. Although it is supported, it is disabled by default.

The SSL Socket Factory

Enabling TLS support is relatively easy in that we just wrap the DefaultSSLSocketFactory in a new SSLSocketFactory, and when a socket is created, we enable all the supported protocols:

private class CompleteSSLSocketFactory : SSLSocketFactory
{
  private readonly SSLSocketFactory innerFactory;

  public CompleteSSLSocketFactory()
  {
    this.innerFactory = HttpsURLConnection.DefaultSSLSocketFactory;
  }

  public override string[] GetDefaultCipherSuites()
  {
    return innerFactory.GetDefaultCipherSuites();
  }

  public override string[] GetSupportedCipherSuites()
  {
    return innerFactory.GetSupportedCipherSuites();
  }

  public override Socket CreateSocket()
  {
    return MakeSocketSafe(innerFactory.CreateSocket());
  }

  public override Socket CreateSocket(Socket s, string host, int port, bool autoClose)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(s, host, port, autoClose));
  }

  public override Socket CreateSocket(string host, int port)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(host, port));
  }

  public override Socket CreateSocket(string host, int port, InetAddress localHost, int localPort)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(host, port, localHost, localPort));
  }

  public override Socket CreateSocket(InetAddress host, int port)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(host, port));
  }

  public override Socket CreateSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
  {
    return MakeSocketSafe(innerFactory.CreateSocket(address, port, localAddress, localPort));
  }

  private Socket MakeSocketSafe(Socket socket)
  {
    var sslSocket = socket as SSLSocket;
    if (sslSocket != null) {
      // enable all supported protocols for this socket
      sslSocket.SetEnabledProtocols(sslSocket.GetSupportedProtocols());
      sslSocket.SetEnabledCipherSuites(sslSocket.GetSupportedCipherSuites());
    }
    return socket;
  }
}

The HTTP Client

Now, we just pass an instance of the factory to the client using SetSslSocketFactory. Although, we caould probably create a singleton for the factory:

// create a new OkHttpClinet 
var client = new OkHttpClient();
// only for the older Androids do we do this
if (Android.OS.Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) {
    client.SetSslSocketFactory(new CompleteSSLSocketFactory()); 
}

HttpClient and Xamarin.iOS Unified

I was creating a NuGet that was dependent on several other NuGets, one of them being Microsoft.Net.Http. This brings in the great HttpClient for all platforms.

However, there is a small problem right now: Microsoft has not yet updated their NuGet to support Xamarin.iOS Unified. They are working on it, but in the meantime what can we do to still create a NuGet that relies on HttpClient?

Well, we don’t actually need the Microsoft.Net.Http NuGet on the Xamarin platforms as the HttpClient type comes with the actual framework. This is because the Xamarin platforms target the 4.5 version of .NET.

So, we can update our .nuspec to exclude these NuGet dependencies on the Xamarin platforms. If our current .nuspec is similar to this:

<dependencies>
    <dependency id="Microsoft.Bcl" version="1.1.9" />
    <dependency id="Microsoft.Bcl.Build" version="1.0.14" />
    <dependency id="Microsoft.Bcl.Compression" version="3.9.85" />
    <dependency id="Microsoft.Net.Http" version="2.2.28" />
    <dependency id="Rx-Core" version="2.2.5" />
    <dependency id="Rx-Interfaces" version="2.2.5" />
    <dependency id="Rx-Linq" version="2.2.5" />
    <dependency id="Rx-Main" version="2.2.5" />
    <dependency id="Rx-PlatformServices" version="2.2.5" />
</dependencies>

All we have to do is move it into a general “ and add a specific group to the offending Xamarin.iOS platform:

<dependencies>
    <!-- for all platforms -->
    <group>
        <dependency id="Microsoft.Bcl" version="1.1.9" />
        <dependency id="Microsoft.Bcl.Build" version="1.0.14" />
        <dependency id="Microsoft.Bcl.Compression" version="3.9.85" />
        <dependency id="Microsoft.Net.Http" version="2.2.28" />
        <dependency id="Rx-Core" version="2.2.5" />
        <dependency id="Rx-Interfaces" version="2.2.5" />
        <dependency id="Rx-Linq" version="2.2.5" />
        <dependency id="Rx-Main" version="2.2.5" />
        <dependency id="Rx-PlatformServices" version="2.2.5" />
    </group>
    <!-- no Microsoft on iOS Unified -->
    <group targetFramework="XamariniOS1.0">
        <dependency id="Rx-Core" version="2.2.5" />
        <dependency id="Rx-Interfaces" version="2.2.5" />
        <dependency id="Rx-Linq" version="2.2.5" />
        <dependency id="Rx-Main" version="2.2.5" />
        <dependency id="Rx-PlatformServices" version="2.2.5" />
    </group>
</dependencies>

This works, as NuGet will use the more specific for Xamarin.iOS, but fall back to the empty for all other platforms. We can use this mechanism for all platforms. We can even use this for the various files as well. In fact, this is how Microsoft does it now: They include everything for all platforms, and then exclude the specific ones that already have HttpClient built in.

When Microsoft updates their NuGet, all we need to do is drop the “ group from the .nuspec and everything is back to normal.

SurfaceView, MediaPlayer and Prepare Failed

I was trying to get a video to play on a SurfaceView, but I kept getting an exception:

IOException: Prepare failed.: status=0x1

After looking around, I still was not able to find out how to get the video to play. It was working fine in a VideoView, but as soon as I tried the MediaPlayer, it threw. When I called the Prepare method, it threw, but if I called PrepareAsync, it just failed with an error to the log.

I eventually found the problem, it was just a single line. I am not sure if this is a bug, or there is some other reason:

mediaPlayer.SetDataSource(path);

If I specify the path to the video using a Uri, all works fine:

mediaPlayer.SetDataSource(this, Uri.Parse(path));

So that was annoying, but it’s all over now.

Playing a video on a SurfaceView using a MediaPlayer is very useful if you want to create your own custom media playback controls. The VideoView with the MediaController is great, but there is no way to easily customize the actual controls.

Here is the snippet of code that can be used to play video. It is assumed that the surface has been created already and available in the holder variable:

var path = string.Format(
    "android.resource://{0}/{1}", 
    PackageName, Resource.Raw.video);

// create the player
var mediaPlayer = new MediaPlayer();
mediaPlayer.SetDataSource(this, Uri.Parse(path));
mediaPlayer.SetAudioStreamType(Stream.Music);
mediaPlayer.SetDisplay(holder);

// prepare the player and the surface
bool isPrepared = false;
bool isSizeSet = false;
mediaPlayer.Prepared += (sender, e) => {
    isPrepared = true;
    if (isPrepared && isSizeSet) {
        mediaPlayer.Start();
    }
};
mediaPlayer.VideoSizeChanged += (sender, e) => {
    holder.SetFixedSize(e.Width, e.Height);
    isSizeSet = true;
    if (isPrepared && isSizeSet) {
        mediaPlayer.Start();
    }
};

// start the process
mediaPlayer.PrepareAsync();

Tasks: ContinueWith on UI Thread

Sometimes we need to perform a task in the background, but then we want to update the UI when it is completed.

We can make use of a Task and the ContinueWith method so that we can chain tasks together. To ensure that a task is performed on a specific thread, we specify which TaskSheduler to use. To get the UI thread scheduler, we can use TaskScheduler.FromCurrentSynchronizationContext() when we are on the UI thread:

If we are going to run a background task:

var uiThread = TaskScheduler.FromCurrentSynchronizationContext();
Task.Run(() =&gt; {
    // do some work on a background thread
}).ContinueWith(task =&gt; {
    // do some work on the UI thread
}, uiThread);

If we need to carry a result from the previous background task:

var uiThread = TaskScheduler.FromCurrentSynchronizationContext();
Task.Run(() =&gt; {
    // do some work on a background thread

    // return a value for the next task
    return true;
}).ContinueWith(task =&gt; {
    // do some work on the UI thread

    if (task.Result) {
        // make use of the result from the previous task
    }
}, uiThread));

The Quick How & Why of Xamarin Components

We at Xamarin were working hard around Christmas to get the new version of Xamarin.iOS out to you guys!

Cool Updates

After a short delay to finish fixing the last few bugs and getting in a few extra improvements, we released Xamarin.iOS 8.6 and updated some of our other products. The Profiler got a new preview and Xamarin.Forms recieved many enhancements.

We, The Components Team, updated hundreds of iOS components to add support for the 64-bit Unified API. There are a few components still outstanding, so if you are the owner, be sure to update them as soon as possible so that they can be used in many more apps!

From inside the team, I can see a great many new components being added daily. Be sure to update or create new components and get them out to developers.

Creating Components

If you find a great native Objective-C or Java control or library that you would like to see in the component store, you don’t have to re-write the whole library. Just create a binding and package that, and, when the original author updates, you can too.

You can also create what we call “Empty Shell Components”. This is simply a component that does not include any actual assemblies, but references a NuGet from NuGet.org. The component still has to include the required docs and samples, but will be featured on the component store.

Creating components can be done in many ways:

  • “traditional” components that include iOS and Android assemblies in the package
  • “empty shell” components that reference a NuGet
  • “hybrid” components that include assemblies and have a dependency on a NuGet

I get my code for the components from many sources:

  • “managed” source code that is compiled into assemblies
  • “bindings” of native libraries
  • “NuGet” packages just packaged along with docs and samples
  • “GitHub” repositories and add new Xamarin projects

If you are faced with a library that does not have support for iOS or Android, you can help that developer out and create the bit he needs. GitHub is a place where you can fork, add Xamarin support and pull. Maybe in the next release there will be a Xamarin library in the NuGet for you to componentize!

NuGet vs Component

You might ask why you need to create a component when you can just create a NuGet. Well, the NuGet store is like a large pit with everything in, and the component store is like a shelf with labels. Also, many of the NuGets can’t be used in iOS or Android. If you submit to the component store, developers know that the library has been tested and approved for iOS and/or Android apps.

It is not that NuGet is bad, don’t get me wrong, but I can never find anything new. The Xamarin component store also supports extra features such as ratings and reviews that can help you find that great library. I think that the component store is like NuGet with Intellisense.

Why not just create a NuGet and then create an empty shell component? You get support for both worlds with only a tiny bit of extra work, and you can get you library directly to Xamarin developers.

Downloading Expansion Files in Xamarin.Android

Google Play currently requires that our APK file be no more than 50MB. For most apps, this is plenty of space for all the app’s code and assets. However, some apps need more space for high-fidelity graphics, media files, or other large assets. Google Play allows us to attach two large expansion files that supplement our APK.

Google Play hosts the expansion files for our app and serves them to the device at no cost to us. The expansion files are saved to the device’s shared storage location (the SD card or USB-mountable partition, also known as the “external” storage) where our app can access them. On most devices, Google Play downloads the expansion file(s) at the same time it downloads the APK, so our app has everything it needs when the user opens it for the first time. In some cases, however, our app must download the files from Google Play when our app starts.

We can obtain the library from NuGet or we can compile the code directly from GitHub.

The Expansion Files

Expansion files are treated as opaque binary blobs (obb) and each may be up to 2GB in size. Android does not perform any special processing on these files after they are downloaded – the files can be in any format that is appropriate for the app. Conceptually, each expansion file plays a different role:

  • The main expansion file is the primary expansion file for additional resources
  • The patch expansion file is optional and intended for small updates to the main expansion file

When Google Play downloads our expansion files to a device, it saves them to the system’s shared storage location. To ensure proper behavior, we must not delete, move, or rename the expansion files. In the event that our app must perform the download from Google Play itself, we must save the files to the exact same location. Any updates to the expansion files overwrite the existing files.

The specific location for our expansion files is:
[shared-storage]/Android/obb/[package-name]/

  • [shared-storage] is the path to the shared storage space, available from Environment.ExternalStorageDirectory
  • [package-name] is our app’s Java-style package name, available from PackageName

Each expansion file we upload will be renamed to match the pattern:
[main|patch].[expansion-version].[package-name].obb

  • [main|patch] specifies whether the file is the main or patch expansion file. There can be only one main file and one patch file for each APK
  • [expansion-version] is an integer that matches the version code of the APK with which the expansion is first associated
    “First” is emphasized because although the Developer Console allows we to reuse an uploaded expansion file with a new APK, the expansion file’s name does not change – it retains the version applied to it when we first uploaded the file*
  • [package-name] the Java-style app package name

For example, suppose our APK version is 23 and our package name is com.example.app. If we upload a main expansion file, the file is renamed to main.23.com.example.app.obb.

Getting Things Ready

We will need to obtain the base64-encoded RSA public key. More information on this in the Getting Things Ready section of this post.

Implementing the Downloader

Once we have installed the library and have our key, we need to ensure that the app has the appropriate permissions to access Play, the licensing service, the Internet, the network state and the external storage:

    [assembly: UsesPermission(Manifest.Permission.Internet)]
    [assembly: UsesPermission(Manifest.Permission.WriteExternalStorage)]
    // required to poll the state of the network connection
    // and respond to changes
    [assembly: UsesPermission(Manifest.Permission.AccessNetworkState)]
    // required to keep CPU alive while downloading files
    [assembly: UsesPermission(Manifest.Permission.WakeLock)]
    [assembly: UsesPermission(Manifest.Permission.AccessWifiState)]
    [assembly: UsesPermission("com.android.vending.CHECK_LICENSE")]

Once we have permission, we can then create a DownloaderService service that will manage the downloads of the expansion files. In addition to the download management, the service will create an alarm to resume downloads and build and update a notification that displays download progress. We can create the service by simply overriding three properties:

    [Service]
    public class SampleDownloaderService : DownloaderService
    {
        // the API key used to access Play
        protected override string PublicKey
        {
            get { return "Base64 API Public Key"; }
        }

        // the salt used to encrypt the cached server response
        protected override byte[] Salt
        {
            get { return new byte[] { ... }; }
        }

        // the name of the broadcast reciever that will resume 
        // the downloads if the service is stopped
        protected override string AlarmReceiverClassName
        {
            get { return "namespace.ClassName"; }
        }
    }

Finally, we will need to implement a BroadcastReciever that will be used to resume any downloads if the service is stopped:

    [BroadcastReceiver(Exported = false)]
    public class SampleAlarmReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            // start the service if necessary
            DownloaderService.StartDownloadServiceIfRequired(
                context, intent, typeof(SampleDownloaderService));
        }
    }

Starting the Check

Once we have the download service and the broadcast receiver, we can then start the downloading. Before we start any downloads, we should make sure that we have not already downloaded all the files:

    // get a list of all the downloaded expansion files
    var downloads = DownloadsDatabase.GetDownloads();
    if (!downloads.Any())
    {
        // start the download as nothing is here
    }
    foreach (var file in downloads)
    {
        if (!Helpers.DoesFileExist(this, file.FileName, file.TotalBytes, false))
        {
            // start the download as this file is incomplete
            break;
        }
    }

If the expansion files are not there or not complete, we need to start the download from the OnCreate method. In order to start the service, we need to provide an Intent that will be used to launch the app when the user taps the notification:

    // build the intent that launches this activity.
    Intent launchIntent = this.Intent;
    var intent = new Intent(this, typeof(SuperSimpleActivity));
    intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop);
    intent.SetAction(launchIntent.Action);
    if (launchIntent.Categories != null)
    {
        foreach (string category in launchIntent.Categories)
        {
            intent.AddCategory(category);
        }
    }

    // build PendingIntent used to open this activity when user 
    // taps the notification.
    PendingIntent pendingIntent = PendingIntent.GetActivity(
        this, 0, intent, PendingIntentFlags.UpdateCurrent);

Now that we have the Intent, we can start the service. Starting the service will return a result that indicates whether the service was started:

    // request to start the download
    var startResult = DownloaderService.StartDownloadServiceIfRequired(
        this, pendingIntent, typeof(SampleDownloaderService));

If the service was started, we obtain an IDownloaderServiceConnection to the service which will be used to communicate with the service from the activity:

    // the DownloaderService has started downloading the files
    if (startResult != DownloadServiceRequirement.NoDownloadRequired)
    {
        // create the connection to the service so that we can show progress.
        // when creating the marshaller, we pass in the IDownloaderClient
        // that will be used to handle the updates from the service
        connection = ClientMarshaller.CreateStub(
          this, typeof(SampleDownloaderService));
    }
    else
    {
        // all files have finished downloading already
    }

Once we have started the downloader and created a connection, we need to connect and disconnect in line with the activity’s lifecycle. In the OnResume method of the activity, we connect to the service:

    if (connection != null)
    {
        connection.Connect(this);
    }

And, in the OnStop method, we disconnect from the service:

    if (connection != null)
    {
        connection.Disconnect(this);
    }

Receiving Download Progress Updates

As the download progresses, we will receive updates such as the number of bytes downloaded, the download speed and various network states. We can use all of this to display information on the user interface. This is all in addition to the notification that is automatically created and managed by the service.

In order to receive updates, we need to get hold of an IDownloaderService from the IDownloaderServiceConnection. To do this, we have to implement the IDownloaderClient somewhere, such as on the activity:

    public class SuperSimpleActivity : Activity, IDownloaderClient
    {
        public void OnServiceConnected(Messenger m)
        {
            // create the proxy that is used to communicate with the service
            service = ServiceMarshaller.CreateProxy(m);
            // let the service know about us and request an update
            service.OnClientUpdated(connection.GetMessenger());
        }
        public void OnDownloadProgress(DownloadProgressInfo progress)
        {
            // handle download progress updates
        }
        public void OnDownloadStateChanged(DownloaderState newState)
        {
            // handle download states, such as completion or pause
        }
    }

Managing the Service

Once we have the service started and the download going, we may want to be able to pause the download. We can request the download be paused using the IDownloaderService:

    service.RequestPauseDownload();

Similarly, we can resume a download:

    service.RequestContinueDownload();

We may also want to change various properties, such as whether to download over mobile or not when the download is paused due to Wi-Fi being unavailable. To do this we use the SetDownloadFlags method on the IDownloaderService:

    public void OnDownloadStateChanged(DownloaderState newState)
    {
        if (newState == DownloaderState.PausedNeedCellularPermission ||
            newState == DownloaderState.PausedWifiDisabledNeedCellularPermission)
        {
            // let the service know that it can download over mobile
            service.SetDownloadFlags(ServiceFlags.FlagsDownloadOverCellular);
            // resume the download
            service.RequestContinueDownload();
        }
    }

Reading the Expansion Files

Because the expansion files are saved to a specific location, namely [shared-storage]/Android/obb/[package-name]/, we could read the files using any file means available.

If we must unpack the contents of our expansion files, do not delete the .obb expansion files afterwards and do not save the unpacked data in the same directory. We should save our unpacked files in the directory specified by GetExternalFilesDir(). However, if possible, it’s best if we use an expansion file format that allows we to read directly from the file instead of requiring we to unpack the data. The reason for this is that the expansion files will now exist twice on the device.

Using a ContentProvider

One way in which we can read the expansion files is to make use of a content provider that can read them. In the library, there is a special content provider, the ApezProvider, that can read uncompressed zip files. If all the expansion resources are bundled in an uncompressed, storage zip archive, this provider allows access to the individual resources without having to first extract them.

Using this provider is simple and easy to implement:

    [ContentProvider(new[] { ContentProviderAuthority }, Exported = false)]
    [MetaData(ApezProvider.MetaData.MainVersion, Value = "14")]
    [MetaData(ApezProvider.MetaData.PatchVersion, Value = "14")]
    public class ZipFileContentProvider : ApezProvider
    {
        public const string ContentProviderAuthority = "expansiondownloader.sample.ZipFileContentProvider";

        protected override string Authority
        {
            get { return ContentProviderAuthority; }
        }
    }

The [MetaData] attributes let the provider know what version of the expansion files to load. For example, if we have uploaded the app with a version number of 5 and new expansion files, the version we place in the attributes will be 5. When we update the app, we may choose to use the same expansion files. So, our new app version will be 6, but because we selected the old expansion files, they are still version 5. Thus, the provider will still use the version numbers of 5 in the attributes.

If we want to access a file in this provider, we can use a Uri to the resource in the provider:

    var uri = Uri.Parse(string.Format(
        "content://{0}/relative/path/to/movie.mp4",
        ZipFileContentProvider.ContentProviderAuthority));
    videoView.SetVideoURI(uri);

It is important to note that the provider uses file descriptors and cannot support reading compressed expansion files.

Using the Zip Archive

Another way to access the files is to access them directly by filename. We can use the ApkExpansionSupport type to obtain the files stored in each expansion file:

    var files = ApkExpansionSupport.GetApkExpansionZipFile(context, 14, 14);
    var entry = files.GetEntry("relative/path/to/file.extension");
    using (var zip = new ZipFile(entry.ZipFileName))
    using (var stream = zip.ReadFile(entry))
    {
        // process the stream of the contained file
    }

Files accessed this way can be stored in a compressed format as a decompression stream is provided. This stream can be processed using typical .NET means, such as providing this stream to a deserializer or some other reader.

The ApkExpansionSupport.GetApkExpansionZipFile method returns a combined collection of all the items in either of the expansion files. We can then query this for a specific item using the GetEntry method on the collection. We pass a relative path to the item in expansion file. Once the entry is returned, we can then create a ZipFile using the path of the entry’s containing expansion file. And, after we have the zip file, we read the stream of the item inside using the ReadFile method.

Testing the Downloader

Testing the download manager is very similar to testing the licensing. More information on this in the Testing the Licensing section of this post. The downloader performs the license check internally, and in the response, it receives the expansion files URIs from Play. It then uses these to initiate the download.

In order to be able to download the expansion files, we have to have uploaded them when updating the app. The first upload does not allow the expansion files to be added, but we can just re-upload the same package twice. On the second time, we can upload the expansion files with the actual app package, remembering to increase the version number beforehand.

We can start testing our app by checking its ability to read the expansion files. We can do this by placing and naming the files just as the downloader would. Because the downloader always places the files at the [shared-storage]/Android/obb/[package-name]/ location, with the name [main|patch].[expansion-version].[package-name].obb, we just have to place our files there. By skipping the downloading, we don’t have to upload the app first.

Once we are sure that the app can access and use the expansion files, we can upload the files with the app to Play and publish to any channel to test the download. Any channel can be used, including Alpha and Beta.

Important Things to Remember

Testing the expansion files, from downloading to reading, requires that we have the various bits in place:

  1. The app version on the device must be the same as the app that is on the store
  2. Make sure that the app is indeed published, and not in draft
  3. Ensure that the Expansion files have been associated with the app
  4. Make sure that the response in “Settings” is set to “RESPOND_NORMALLY” as this is the only response that returns the expansion files
  5. Make sure the app has all the required permissions, there are 6 at least