Embedding Xamarin.Forms in Native Apps

Xamarin.Forms is really cool! It allows you to almost write your app once and then compile for many platforms. With Xamarin.Forms, you can quickly produce multiple apps, but, you can also take advantage of some awesome features – such as cross-platform UIs in XAML, data binding, sharing code and much more.

Xamarin.iOS, Xamarin.Android and UWP are also fantastic! You can get 100% of the platform APIs and you can produce apps that are super fast and polished.

Most of the time you have to choose between one or the other. Sure, you can do custom renderers or effects in Xamarin.Forms to get more platform API access. And sure, you can use frameworks that help you share code with native Xamarin and Windows apps. Before today, you had one of two choices:

  • Xamarin.Forms for 100% shared code and UI
  • Xamarin/Windows Native for polished, platform-specific APIs and UIs

But… why not have both? Recently Xamarin/Microsoft shared on the blog that Xamarin.Forms can be embedded into native apps. This means that you can take your existing (or new) native app and just drop in a Xamarin.Forms page without doing anything special. You lose nothing, and gain a whole lot more. You can still use XAML, data binding, converters, effects and everything else that comes with Xamarin.Forms – but now from within you native app code and UI.

I have a nice sample app that you can pull from GitHub. Be sure to check it out and let me know what you think of this new functionality. I will try and keep that repository up to date with any new developments.

Xamarin.Forms embedded in native apps

Getting the Bits

To embed Xamarin.Forms into your native app, you just need to install a preview NuGet from the Xamarin.Forms pre-release feed:

https://www.myget.org/F/xamarinforms-dev/api/v3/index.json

Then, you want to install the 3.0.0.100-embeddingpreview NuGet into any Xamarin.Forms projects as well as into the native app projects.

That is it! Now you should be able to create your shared page.

If you have any questions or comments you can do this using the Xamarin discussion (Preview: Xamarin.Forms Embedding) on the forums.

It is important to note that this is a pre-release and functionality may change with subsequent releases.

Creating Shared Pages

Let’s take an example of an existing app that you want to add the ability to register and/or login to save user preferences on some cloud service – such as Azure. Your app is out and in the wild, users are loving it, and, you have just received feedback that they want to login across devices and keep their preferences.

What do you do? Well you could create a few screens for each platform and then share some code. But, as all the login screens are going to look the same and work the same, why not do everything in shared XAML?

So, the first thing we can do is to either create a shared project, a .NET Standard library or even a PCL. We then just need to install the pre-release Xamarin.Forms NuGet. Finally, we can go ahead an add a new XAML page. Just right-click and do “Add” > “New Item…” > “Content Page (XAML)” and then you have a new page.

In this page below, I am using data binding, converters, resource dictionaries and good old XAML markup:

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:app="clr-namespace:EmbeddedFormsDemo.Converters"
             x:Class="EmbeddedFormsDemo.Views.LoginPage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <app:NegateConverter x:Key="Negate" />
            <app:NullInvisibilityConverter x:Key="NullInvisibility" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <ScrollView>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <StackLayout Spacing="12" Grid.Row="1">
                <StackLayout.Padding>
                    <OnPlatform x:TypeArguments="Thickness" 
                                Android="24" iOS="24" WinPhone="0" />
                </StackLayout.Padding>
                <Label Text="Enter any username/password:"
                       HorizontalTextAlignment="Center"
                       FontSize="12" />
                <Entry Keyboard="Email" 
                       Placeholder="username or email"
                       Text="{Binding UserName}" 
                       HorizontalTextAlignment="Center"
                       IsEnabled="{Binding IsBusy, Converter={StaticResource Negate}}" />
                <Entry IsPassword="True" 
                       Placeholder="password" 
                       Text="{Binding Password}" 
                       HorizontalTextAlignment="Center"
                       IsEnabled="{Binding IsBusy, Converter={StaticResource Negate}}" />
                <Button Text="Log In" 
                        Command="{Binding LoginCommand}"
                        IsEnabled="{Binding IsBusy, Converter={StaticResource Negate}}" />
                <Label Text="{Binding ErrorMessage}" 
                       HorizontalTextAlignment="Center"
                       FontSize="12"
                       TextColor="Red" 
                       IsVisible="{Binding ErrorMessage, Converter={StaticResource NullInvisibility}}" />
                <ActivityIndicator IsRunning="{Binding IsBusy}" 
                                   IsVisible="{Binding IsBusy}" />
            </StackLayout>
        </Grid>
    </ScrollView>
</ContentPage>

Then, in our code-behind, we can write out code to work with the UI. Here we have made use of several features such as binding, commands, messaging and async/await:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage
{
    public const string LoginMessage = "login";

    private readonly JsonPlaceholderApi api;
    private string errorMessage;

    public LoginPage()
    {
        InitializeComponent();

        // initialize our fake services
        api = new JsonPlaceholderApi();

        // set up the data binding
        LoginCommand = new Command(OnLogin);
        BindingContext = this;
    }

    private async void OnLogin()
    {
        IsBusy = true;

        // reset errors
        ErrorMessage = "";
        // try logging in with our fake services
        var user = await api.LoginAsync(UserName, Password);
        if (user == null) {
            // there was an error
            ErrorMessage = "There was a problem logging in.";
        } else {
            // let the app know we are finished
            MessagingCenter.Send(user, LoginMessage);
        }

        IsBusy = false;
    }

    public string ErrorMessage
    {
        get { return errorMessage; }
        set { errorMessage = value; OnPropertyChanged(); }
    }

    // we don't want to save this as the user types
    public string UserName { get; set; }

    // we don't want to save this at all
    public string Password { get; set; }

    // the login button uses this
    public ICommand LoginCommand { get; }
}

That is basically all we need to do in order to create our UI. The JsonPlaceholderApi type just makes use of http://jsonplaceholder.typicode.com to get some random data, the User type is just a simple POCO object and the converters are basic IValueConverter implementations.

Displaying Shared Pages in Native Apps

Once we have created our shared Xamarin.Forms page, we can just instantiate out Xamarin.Forms page and then ask for the native version.

On Android, the CreateFragment extension method will return a native Android Fragment, which we can then use as we would any other fragment. On iOS, we use the CreateViewController extension method and we will get out a native UIViewController that, again, we can use as we would any other view controller. And finally, on Windows, we use the CreateFrameworkElement extension method to get out a native FrameworkElement that we can also uses as any other element.

There are two steps to obtaining this native container, first we make sure Xamarin.forms is initialized:

// Android
Xamarin.Forms.Forms.Init(this, null);

// iOS
Xamarin.Forms.Forms.Init();

// Windows
// the `e` from `Application.OnLaunched(LaunchActivatedEventArgs e)`
Xamarin.Forms.Forms.Init(e);

Once that is done, we can then get the native page:

// create the Xamarin.Forms page for all platforms
var formsPage = new MyFormsPage();

// Android - get the native Fragment
var nativeFragment = formsPage.CreateFragment(this);

// iOS - get the native UIViewController
var nativeController = formsPage.CreateViewController();

// Windows - get the native FrameworkElement
var nativeElement = formsPage.CreateFrameworkElement();

Now that we have the native view, we can just go ahead and use it as if it was created using the traditional mechanisms.

Xamarin.Android and Xamarin.Forms

When using Xamarin.Forms with an Android app, we are going to need to handle the native Fragment that represents the page. To this end, our Android app is using a native .axml layout with a FrameLayout that will hold all our fragments:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <!-- the other bits of UI -->
    <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/frameLayout" />
    <!-- some more UI -->
</RelativeLayout>

Then, in our main activity code, we load this UI as normal and everything works as it usually does. When we want to show our new XAML page at some point, all we need to do is to just make sure Xamarin.Forms is initialized and then instantiate the page before navigating to it:

using Xamarin.Forms.Platform.Android;

public void DisplayLogin()
{
    if (!Xamarin.Forms.Forms.IsInitialized)
    {
        // initialize Xamarin.Forms before we use it
        Xamarin.Forms.Forms.Init(this, null);

        // we want to listen to the messaging center
        Xamarin.Forms.MessagingCenter.Subscribe(this, LoginPage.LoginMessage, (User user) =>
        {
            // update the app
            CurrentUser = user;

            // go back to the main page
            FragmentManager.PopBackStack();
        });
    }

    // create the login page (Xamarin.Forms ContentPage)
    var loginPage = new LoginPage();

    // get hold of the native Android fragment that represents the Xamarin.Forms page
    var loginFragment = loginPage.CreateFragment(this);

    // show the login screen (native Xamarin.Android)
    FragmentManager
        .BeginTransaction()
        .AddToBackStack(null)
        .Replace(Resource.Id.frameLayout, loginFragment)
        .Commit();
}

Xamarin.iOS and Xamarin.Forms

If we want to use Xamarin.Forms in our iOS app, we will be showing a new UIViewController. We first need to make sure that Xamarin.Forms is initialized and then we can just go ahead and create the desired page. We then get the native view controller that can be presented using all the existing means:

using Xamarin.Forms;

partial void OnLoginClicked(UIButton sender)
{
    if (!Xamarin.Forms.Forms.IsInitialized)
    {
        // initialize Xamarin.Forms before we use it
        Xamarin.Forms.Forms.Init();

        // we want to listen to the messaging center
        Xamarin.Forms.MessagingCenter.Subscribe(this, LoginPage.LoginMessage, (User user) =>
        {
            // update the app
            User = user;

            // go back to the main page
            NavigationController.PopViewController(true);
        });
    }

    // create the login page (Xamarin.Forms ContentPage)
    var loginPage = new LoginPage();

    // show the login screen
    var viewController = loginPage.CreateViewController();
    NavigationController.PushViewController(viewController, true);
}

Windows UWP and Xamarin.Forms

When we want to show a Xamarin.Forms page within our native UWP app, we will work with a FrameworkElement. Like with all the other platforms, we have to make sure that Xamarin.Forms is initialized and then just create the page. Once we have obtained the native element, we can just place it anywhere we need it to be. In this example, I am placing my view in a Flyout as the it is being opened:

using Xamarin.Forms;

private void OnLoginFlyoutOpening(object sender, object e)
{
    var flyout = sender as Flyout;

    if (!Xamarin.Forms.Forms.IsInitialized)
    {
        // initialize Xamarin.Forms before we use it
        Xamarin.Forms.Forms.Init(App.LastLaunchEventArgs);

        // we want to listen to the messaging center
        Xamarin.Forms.MessagingCenter.Subscribe(this, LoginPage.LoginMessage, (User user) =>
        {
            // update the app
            User = user;
            // show some message for some random reason
            WelcomeText = $"Welcome back {user.Name}!";

            // hide the login screen
            flyout.Hide();
        });
    }

    // create the login page (Xamarin.Forms ContentPage)
    var loginPage = new LoginPage();

    // set the native dialog to contain the shared login
    var loginElement = loginPage.CreateFrameworkElement();
    flyout.Content = new Frame
    {
        Content = loginElement,
        Width = 300,
        Height = 200
    };
}

Summary

In this fairly long post, we looked at how to quickly embed a Xamarin.Forms page into an existing native app. The process is easy and painless, and will only get better.

You can download the full code from my GitHub repository and try it out for yourself. And maybe have a look at your app and see if some of those screens that are exactly the same could use Xamarin.Forms.

You can also check out some links:

Some other people also have blogs:

And, then there is code:

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;

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

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

Play Licensing in Xamarin.Android

Google Play offers a licensing service that lets us enforce licensing policies for applications that us publish on Google Play. With Google Play Licensing, our application can query Google Play at runtime to obtain the licensing status for the current user, then allow or disallow further use as appropriate.

The Google Play Licensing service is primarily intended for paid applications that wish to verify that the current user did in fact pay for the application on Google Play. However, any app (including free apps) may use the licensing service to initiate the download of an APK expansion file.

Getting Things Ready

In order to add licensing to our app, all we will need is the licensing verification library. We can get this from NuGet.org or the Component Store (coming soon), or, we can build the source using the GitHub repository.

After adding the library, we need to get hold of our API key for this app:

  1. Browse to the Google Play Developer Console
  2. Select “All Applications” from the sidebar
  3. Select the app we want to implement licensing for
    • If we are going to create a new app, select “Add new application”
    • Enter a name for the app
    • Select “Prepare store listing”
    • Enter the required details for publishing
  4. Select “Services & APIs” from the left menu
  5. Scroll to the “Licensing & In-app billing” section
  6. Under the “Your license key for this application” heading, copy the base64-encoded RSA public key
  7. Paste it into a string constant in the app code:
    const string ApiKey = "XXX";

All Applications in Play
Public Key

Adding the License Handlers

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

    [assembly: UsesPermission("com.android.vending.CHECK_LICENSE")] 

Once we have permission, We can then implement the ILicenseCheckerCallback interface. This can be implemented on the activity, but does not have to:

    public class MainActivity : Activity, ILicenseCheckerCallback
    {
      public void Allow(PolicyServerResponse response)
      {
        // Play has determined that the app is owned,
        // either purchased or free
      }
      public void DontAllow(PolicyServerResponse response)
      {
        // Play has determined that the app should not be available to the user,
        // either because they haven't paid for it or it is not a valid app

        // However, there may have been a problem when Play tried to connect,
        // so if this is the case, allow the user to try again
        if (response == PolicyServerResponse.Retry)
        {
          // try the check again
        }
      }
      public void ApplicationError(CallbackErrorCode errorCode)
      {
        // There was an error accessing the license
      }
    }

Starting the Check

Once we have implemented the interface, all we need to do now is start the check. There are two basic methods provided in order do this, one with caching and one without.

Using StrictPolicy

To make things easier to start off with, I will first demonstrate the one without caching, the StrictPolicy:

    // create the policy we want to use
    var policy = new StrictPolicy();
    // instantiate a checker, passing a Context, an IPolicy and the Public Key
    var checker = new LicenseChecker(this, policy, "Base64 Public Key");
    // start the actual check, passing the callback
    checker.CheckAccess(this);

As soon as the check has completed, either with an error or successfully, one of the methods on the callback will be called, either Allow, DontAllow or ApplicationError.

Allow will receive a Licensed response
DontAllow will receive a NotLicensed response
ApplicationError will have the reason for the error, such as NotMarketManaged, InvalidPublicKey or some other reason.

Using ServerManagedPolicy

Although checking with Play each time the app launches is not a problem, doing so requires additional time and resources before the app can start. Usually, we can use the one with caching, the ServerManagedPolicy policy. This is very much the same as the StrictPolicy, but with an additional step to provide an IObfuscator to store the response:

    // create a device-unique identifier to prevent other devices from decrypting the responses
    string deviceId = Settings.Secure.GetString(ContentResolver, Settings.Secure.AndroidId);
    // create a app-unique identifer to prevent other apps from decrypting the responses
    var appId = this.PackageName;
    // create a random salt to be used by the AES encryption process
    byte[] salt = new byte[] { 46, 65, 30, 128, 103, 57, 74, 64, 51, 88, 95, 45, 77, 117, 36, 113, 11, 32, 64, 89 };

    // create the obfuscator that will read and write the saved responses, 
    // passing the salt, the package name and the device identifier
    var obfuscator = new AesObfuscator(salt, appId, deviceId);
    // create the policy, passing a Context and the obfuscator
    var policy = new ServerManagedPolicy(this, obfuscator);
    // create the checker
    var checker = new LicenseChecker(this, policy, Base64PublicKey);
    // start the actual check, passing the callback
    checker.CheckAccess(this); 

As soon as the checker has returned and we know that we can start the application, we should destroy the cecker in order to free up resources and close connections:

    // free resources and close connections
    checker.OnDestroy();

Testing the Licensing

The last thing that is needed is testing. To do this, we have to be sure that we have uploaded and published the app to Play. Publishing to any of the channels, including Alpha and Beta, will work.
In order for the Alpha or Beta channels to be used on devices other than the publisher’s device, those people have to be added to the Alph or Beta testers group.
If we want to test different responses that our app may receive from Play, we can select the desired response from the settings:

  1. Select “Settings” from the sidebar
  2. Select “Account details” from the left menu
  3. Scroll dow to the “License Testing” section
  4. Select the desired response from the drop down titled “License Test Response”
    • For other testers, make sure we enter their Google account email address in the text area above titled “Gmail accounts with testing access”

Custom License Responses

Important Things to Remember

Testing licensing is easy to do, provided we have all the required bits in place. Here are some common things that we may have to check:

The Play Store

  1. The app version on the device must be the same as the app that is on the store
  2. Provide enough time for the app to appear on the store, this can be determined by a little exclamation sign next to the app title when viewing the app details
  3. Make sure that the app is indeed published, and not in draft

For Other Testers

  1. Ensure that the testers have been added to the Alpha or Beta testers group
  2. If we are testing custom responses, make sure that their emails are added to the “Gmail accounts with testing access” text area in “Settings”

For The App

  1. Make sure we have the Android permission
    com.android.vending.CHECK_LICENSE
  2. Ensure that the app has the same version code/number and package name as that which is on the store

Xamarin Insights for Older Androids

Recently, Xamarin announced a real-time crash reporting and analytics solution for mobile apps, Xamarin Insights.

This is an awesome tool with many great features. They support all the major platforms, iOS Android Windows Phone, Windows RT and traditional desktop applications. Support for Xamarin.Mac is coming soon.

Some of the major features:

  • Report details about the device statistics such as operating system and screen resolution
  • Gather and report any uncaught native or managed exceptions
  • Report any caught exception, along with any additional data
  • Track both past and active sessions
  • Track any event that occurs in your application, including the time it takes to execute
  • Cross-platform across almost all devices, including support for PCL libraries

Old Androids

Recently they added support for Android versions below API level 14 (Android Version 4.0 – Ice Cream Sandwich). To use Xamarin Insights in an Android app below API level 14, such as API Level 8 (Android Version 2.3 – Gingerbread), there are a few things that need to happen:

  1. Set your ‘Compile using Android version’ or ‘Target framework’ value to be API level 14 or higher, such as API level 19
  2. Set the ‘Minimum Android to target’ or ‘Minimum Android version’ to be the value you are wanting to support, such as API level 8.

This will result in your app building against the higher API level, but can run on earlier devices.

However, even after all this, there is still a limitation, namely the inability to record sessions. This may not be a deal breaker for you, but for some, this is. The reason for this is that Xamarin Insights is using the IActivityLifecycleCallbacks interface. This is a relatively new addition to the Android API and is very useful in that it allows you to hook into the Activity lifecycle without having to use the Activity itself. As this interface is not available for the older versions, they simple can’t record the Activity sessions.

The Code

I am here to give you that solution that you always wanted: Manually starting and stopping sessions from within the activity. To do this I have created a simple class InsightsCompat:

    public static class InsightsCompat
    {
        public static void Initialize(string apiKey)
        {
            Insights.Initialize(apiKey, Application.Context);
        }

        public static void StartSession()
        {
            EmitBackgroundChange(false);
        }

        public static void StopSession()
        {
            EmitBackgroundChange(true);
        }

        private static void EmitBackgroundChange(bool backgroundState)
        {
            try
            {
                var status = backgroundState ? "Background" : "Resumed";
                var table = new Dictionary<string, string> {{"Status", status}};
                Insights.Track("X-App-State", table);
            }
            catch (Exception ex)
            {
                Insights.Report(ex);
            }
        }
    }

The Usage

This simple class can do all the work that is needed, plus there is an additional method, Initialize, that allows you to start up Xamarin Insights without having to find the context:

    // from anywhere in your code
    InsightsCompat.Initialize("your API key");

To start and stop sessions, you can override the OnResume and OnPause methods:

    protected override void OnPause()
    {
        InsightsCompat.StopSession();
        base.OnPause();
    }

    protected override void OnResume()
    {
        base.OnResume();        
        InsightsCompat.StartSession();
    }

We only have to override these two methods as android will always call these methods, no matter where the Activity came from or where it is going.

There’s More

Even though Xamarin Insights has many features, it is still in preview and there can still be many more features. If you have any feature requests or ideas, be sure to drop a message on the Xamarin Insights User Voice.

There is a small docs page for Xamarin Insights here. So head over to the dashboard and get started creating and supporting awesome cross-platform apps now.

Binding Flurry Analytics with Xamarin.Android

This week, I needed to use Flurry Analytics in my Xamarin.iOS and my Xamarin.Android apps, but there was no .NET SDK for these platforms. Flurry did provide a SDK for each platform, but it was the native libraries, which cannot be used directly in .NET. Given this, I decided to bind those native libraries using Xamarin.iOS and Xamarin.Android.

I have split this project up into four parts:

  1. Introduction and Pre-requisites
  2. Xamarin.iOS binding
  3. Xamarin.Android binding
  4. Flurry.Analytics in the wild

After binding the iOS SDK for Flurry Analytics, we are going to move onto the Android release. This task needs only one thing from the downloaded SDK:

  • [Android-sdk-path]/Android 4.1.0/FlurryAnalytics/FlurryAnalytics-4.1.0.jar

Of course, the version numbers may change for later releases. The java archive file (.jar) is going to be used to generate the .NET interfaces and enums, and then be embedded in the resulting assembly.

Just before we do the real binding, we should just create our C# solution for the Xamarin.Android binding. Just create a new project/solution and select the Android “Bindings Library” template. For my project name I used Flurry.Analytics.Android, but you could use anything.

The default project has a few files and directories in it, we will have a look at each one in depth as we go through the binding steps:

  • /Additions/ (this allows you to add arbitrary C# to the generated classes
    before they are compiled)
  • /Properties/AssemblyInfo.cs (the usual assembly information attributes)
  • /Jars/ (this directory is for Android .jars)
  • /Transforms/EnumFields.xml (this allows you to map Java int constants to C# enums)
  • /Transforms/EnumMethods.xml (this allows changes to method parameters and return types from Java int constants to C# enums)
  • /Transforms/Metadata.xml (this allows changes to be made to the final API)

Creating the Initial Binding

This step will involve just adding the jar to the project, and letting the compiler do it’s thing, but we will almost always have to go in and tweak a few things in the Metadata.xml.

So, first things first, add the jar file to the project and compile. The build will probably fail with error messages containing single character methods and types. This is because the actual jar file has been obfuscated. However this can easily be fixed.

The way the generation works is that there is a two step process, there is a tool that generates a bunch of xml files from the jar file. These xml files are then used to generate C# code. The Metadata.xml sits in between the two steps and can be used to transform the generated xml before the C# generation.

Tweaking the Generated Binding (Manifest.xml)

As we can see that the build fails on obfuscated types, we can remove these. The removal is safe as we are only preventing the .NET binding from being created, not actually removing the underlying Java members. And, as these items have been obfuscated, we can safely assume that we aren’t supposed to be accessing them anyway.

But, instead of removing each member or type that appears, we can use a great tool that will decompile the jar file and show us exactly what types are internal and what types we should be binding. I use JD-GUI, which is a free Java decompiler. They also have a nice online version, JD-Online. What we can do is to just upload the jar file here and see what’s inside:

  • com.flurry.android.impl.analytics.*
  • com.flurry.android.*
  • com.flurry.sdk.*

As we can see, the impl and sdk branches contain internal and obfuscated types, so we can remove those:

<remove-node path="/api/package[starts-with(@name, 'com.flurry.sdk')]" />
<remove-node path="/api/package[starts-with(@name, 'com.flurry.android.impl')]" />

After this, the build should now succeed and we will have an assembly that we can use. However, there are still some types that we can remove to clean the API a bit: InstallReceiver and Constants. InstallReciever is not used by the consumer, so this is safe to remove, but Constants is still used. If we remove this, then the consumer will not have access to the values on the type. We can see that Constants just contains the values representing male, female and unknown.

To remove the InstallReciever, we can add this line to Metadata.xml:

<remove-node path="/api/package[@name='com.flurry.android']/class[@name='InstallReceiver']" />

For the Constants type, we will do something different.

Managing the Enumerations (Additions & EnumFields.xml)

As we clean up the API, we want to remove the Constants type and replace it with an enum. One way to do this is to use the EnumFields.xml:

<mapping clr-enum-type="Flurry.Analytics.Gender" jni-interface="com/flurry/android/Constants">
    <field clr-name="Male" jni-name="MALE" value="1" />
    <field clr-name="Female" jni-name="FEMALE" value="0" />
    <field clr-name="Unknown" jni-name="UNKNOWN" value="-1" />
</mapping>

This will generate a nice enum for us, but this does leave an unused interface IConstants. As this is a very small library, we can do this mapping slightly differently. First we remove the entire Constants type in the Metadata.xml:

<remove-node path="/api/package[@name='com.flurry.android']/interface[@name='Constants']" />

Then, we can create the enum in the /Additions/ directory. To do this, add a new file (for example called FlurryAgent.cs) under this directory and add the enum:

public enum Gender
{
    Male = 1,
    Female = 0,
    Unknown = -1
}

Now there is one last thing to do before the API definition is complete. There is a SetGender method on the type FlurryAgent, which takes the type sbyte. It is not intuitive to use the Gender enum here, so we can fix this in a two step process. First we will create an overload in the FlurryAgent.cs file that accepts a Gender enum member as an argument:

public partial class FlurryAgent
{
    public static void SetGender(Gender gender)
    {
        FlurryAgent.SetGender ((sbyte)gender);
    }
}

And, what we can do is also hide the original member as the new overload is good enough:

<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='setGender']" name="visibility">internal</attr>

And with this, our binding is complete, although we can do a few nice changes to the namespace and parameter names.

Changing Parameter Names

Now that we have the binding complete, we can see that it is using the namespace Com.Flurry.Android, which is no .NET-like at all. We can change this to something better:

<attr path="/api/package[@name='com.flurry.android']" name="managedName">Flurry.Analytics</attr>

This maps the com.flurry.android package name to the neat Flurry.Analytics namespace. One last thing is to fix the parameter names. Sometimes you can use the JavaDocs, but in this case, I couldn’t get it to work. Doing it manually is not hard, but it is boring and time consuming, but here are a few.

This is the usual mapping:

<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='onStartSession']/parameter[@name='p0']" name="name">context</attr>
<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='onStartSession']/parameter[@name='p1']" name="name">apiKey</attr>
<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='onEndSession']/parameter[@name='p0']" name="name">context</attr>

If there are complicated parameter types (note the &lt;):

<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='logEvent']/parameter[@name='p1' and @type='java.util.Map<java.lang.String, java.lang.String>']" name="name">parameters</attr>

If there are overloads with different parameter types:

<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='onError']/parameter[@name='p2' and @type='java.lang.Throwable']" name="name">exception</attr>
<attr path="/api/package[@name='com.flurry.android']/class[@name='FlurryAgent']/method[@name='onError']/parameter[@name='p2' and @type='java.lang.String']" name="name">errorClass</attr>

After doing this for all the members, the binding is now complete.

Finishing Up

So far we have defined our API, added any additional logic or types, added the native library and added parameter names. This is all that is needed, so our library should build fine now and we should be able to use it in an Xamarin.Android app:

// the methods
FlurryAgent.StartSession(this, "PQSZJRK4B5BW8Q7YQQXF");

// the properties that we changed back into methods
string version = FlurryAgent.ReleaseVersion;

// the extra method that we added
FlurryAgent.SetGender (Gender.Male);

ADB DEVICES >> No Devices Found

When building apps for Android using obscure devices such as the one I was using, sometimes the ADB (Android Debug Bridge) cannot find the device. I spent a long time trying to find out why my device was not appearing in adb, as Windows picked it up in the Device Manager and in Windows Explorer.

Usually, just installing the “Google USB Driver” by using the Android SDK Manager, results in all you problems going away. But, with the more obscure devices, this sometimes does not fix the issue.

The first step is to ensure that the device is installed. This can be checked by using the Windows Device Manager. If the device is not installed, it will be under “Other Devices”, then you just need to install it manually. If you downloaded the drivers by using the Android SDK Manager, then you can find them in a subfolder of the SDK ([sdk]\extras\google\usb_driver\). There should be a file called android_winusb.inf. There is also another way to obtain these drivers without using the Android SDK Manager, and that is directly off their website (latest_usb_driver_windows.zip). You can then extract the files to a convenient location so that you can install the drivers using the Device Manager.

  1. To install the drivers, you can right click the “Unknown Device” under “Other Devices” (It may be a partial/vague bit of a device name – for example, mine is just “Full”), and click “Update Device Software…”. This will start the wizard.
  2. On the first page, you can click “Browse my computer for driver software” (we want to select our downloaded files manually).
  3. We then click the “Let me pick from a list of device drivers on my computer” button as we want to do the install manually as Windows will not detect the driver as they are generic.
  4. The first item in the list of hardware types will be “Show All Devices”, select that and press “Next”.
  5. On the next page, there will be a “Have Disk…” button. Press that and then we can browse to where we have either extracted or installed the drivers to (the file we must select is android_winusb.inf). Press “OK” and then you should be back to the page that contains the “Have Disk…” button.
  6. Above the button will be a list with 3 items, select the “Android ADB Interface” and press “Next”.
  7. Windows will show a warning dialog that says that the device driver is not recommended. We can safely press “Yes” as this is just because this is a generic driver.
  8. Windows will install the driver and when it is finished, we can close the window.

Our device (“Android ADB Interface”) should now be under the “Android Device” item. The device is just installed, and this may be all we need. You can run the ADB DEVICES command to see if the device is detected.

If the device is not detected, then we may have to manually specify the device as a valid Android device for ADB. In order to do this we need to find out our device Hardware ID.

  1. We can obtain the Hardware ID via the Device Manager. We can just right-click out newly installed “Android ADB Interface” item and press “Properties”.
  2. On the “Details” tab, select “Hardware IDs” from the dropdown. There may be one or more items here, but you can use the one that starts with “USB\VID_####” (the #### is the 4 character device Hardware ID). I have an item labeled “USB\VID_2207&PID_0010&REV_0222&MI_01”, thus my Hardware ID is “2207”.
  3. Now, the short way to add the device to ADB is to just add the device Hardware ID to the adb_usb.ini file (%USERPROFILE%.android\adb_usb.ini).
  4. If this file does not exist, you can safely create it.
  5. Open the file in Notepad and add a new line to the end of the file in the form “0x####” (again the #### is the Hardware ID). In the case of my device, I added a line “0x2207” to the bottom of the file.

You should be able to now restart ADB and the device should be listed. You can do a restart by running 2 commands ADB KILL-SERVER and then ADB START-SERVER.

As the Android SDK Manager may overwrite the files here, you changes may be lost later. The correct way to ensure the install the device for ADB is to create a new add-on. This is simply creating a new file in a new folder under the “add-ons” folder in the SDK ([sdk]\add-ons\).

  1. The first thing to do is create a new folder for you add-on. You can pick any folder name as long as it won’t conflict with any other add-ons. I picked “small-tablet” as I don’t think that is a add-on name that is used elsewhere.
  2. Inside that new folder, create a manifest.ini file.
    • name – the add-on name
    • api – the API level on the device – mine was 4.0, thus 14
    • usb-vendor – the hex Hardware ID – mine was 2207, thus it will be 0x2207
  3. The item should now appear in the Android SDK Manager under “Extras”.

The contents of the manifest.ini file should be something like this, with the most important items:

name=small-tablet
vendor=Who Knows
description=That cheap 7″ tablet
api=14
revision=1
usb-vendor=0x2207

And there we go, we now have a nameless device in our Android SDK Manager.

Binding Flurry Analytics with Xamarin

Over the last few days I have been creating a Xamarin.iOS and Xamarin.Android binding for Flurry Analytics SDKs. Flurry Analytics is a neat little library that allows for tracking of your app usage and various user stats.
And, because I really enjoyed my time doing this, I thought that I will share just a bit of the fun times and the not-so-fun times.

I have split this project up into four parts:

  1. Introduction and Pre-requisites
  2. Xamarin.iOS binding
  3. Xamarin.Android binding
  4. Flurry.Analytics in the wild

Pre-requisites

Before we start any coding, we need to get all our tools and files needed for the actual binding tasks.

I was using both Windows 8, with Visual Studio, and Mac OS X with Xamarin Studio. You can bind the Android library on either platform, but for iOS, it is easier to use the Mac. In this case, I will use the Mac for both iOS and Android.

Some of my very excellent sources for this process were the actual Xamarin documentation:

But, along with this info, there are just a few things that you may need. Firstly, it is good to update your Xamarin Studio to the latest stable release as this makes sure that all potential problems are minimized from the start.

Then, the next cool tool to get hold of is, Objective Sharpie, for binding iOS libraries. This tool is quite nifty for quickly generating the .NET interfaces from the Objective-C header files. It uses the header files not the actual compiled native library. The Xamarin docs on Objective Sharpie has a brief walkthrough on how to use the tool, so I will assume you know how to use it.

After we have all our tools ready to go, we need those SDKs from Flurry.

What I did was to create a free account by Flurry, and then created an Android and iOS Application using their dashboard. You have to have an application before they will let you download their SDKs. This step is pretty straight forward, so I won’t go into it here right now. Once you have created and downloaded the SDKs, you can extract them to a nice location for reference.

Now to get started with the real work…

But, as this is quite a long process, I will be splitting this article into this intro, the iOS binding and the Android binding. So, enjoy!

Trying to Blog… and an update

It has been a very long time since I started (or attempted to start) blogging. I hope to really get down to doing this again. What might help is the fact that my company is re-working their website and is asking the developers to start posting an article every couple of months.

Anyway, I have been very busy with my studies, work and other small projects on my GitHub account (github.com/mattleibow). I have several repos, but my cooler ones are the Mono.Data.Sqlite.Orm and the Android.Play.ExpansionLibrary.
The Mono.Data.Sqlite.Orm repo is a small and light-weight O/RM for the Sqlite library on the various platforms.

The initial idea was from Frank A. Krueger and his sqlite-net, but I re-wrote almost the entire library using the Mono.Data.Sqlite assembly instead of his custom types. I also had to port the Mono.Data.Sqlite assembly from the Mono repository to use the C#-SQLite library instead of the sqlite.dll native library.

I also want to create some more docs for this library, so I just set up the GitHub Pages for this repo: http://mattleibow.github.com/Mono.Data.Sqlite.Orm. I will see if I can use this.

The Android.Play.ExpansionLibrary repo is the C# equivalent of the Google provided Java LVL and Expansion libraries. This was, and is to an extent, still an almost a direct translation from Java to C#, but I think it has a few improvements. Such as, a nicer storage system.

I also got my first Android App onto Google Play:
https://play.google.com/store/apps/details?id=com.jamwarehouse.apps.puppy.trial!
This was very exciting and I am very glad that I got this opportunity.

Now I am going to try and edit that GitHub Pages for my repo… But before that, I am going to add some images so that when I select the other layouts, I will get a picture πŸ™‚