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));