Introduction to Android/iOS development using Visual Studio and Xamarin

February 18th, 2014 | Posted by Tom in Article | Visual Studio | Xamarin | Read: 7,711

I like to think that I’m open minded enough to look at a lot of things. Recently, I’ve started to look at Xamarin not to start developing apps on Android but just to be able to know the product and I have to say that it’s very interesting. I’ll try to make more posts on it but, for now, let’s take a look that the big picture of it!

 

What is Xamarin ?

 

 Xamarin is a set of tools developers can use to delivers high performance compiled code with full access to all the native APIs so you can create native apps with device-specific experiences. Anything you can do in Objective-C or Java, you can do in C# with Xamarin.

The other good point is that even if you can use Xamarin Studio to develop your app, you can also use Visual Studio and all the other tools you already use for any C# development. This include Team Foundation Server (for the source control) but also plugins like Resharper, GhostDoc, etc.

Finally, to let you share code easily across iOS, Android and Windows Phone, you can also use the Portable Class Library (PCL) to create a core component that will be available on all the platforms (only the GUI part will be specific). The following article give your more details on how to work with the PCL and Xamarin Studio or Visual Studio (if you are already using the PCL on Visual Studio, you’ll see that there are no big differences!).

 

How does it work ?

Xamarin offers 2 mains products: Xamarin.iOS (MonoTouch.dll) and Xamarin.Android (Mono.Android.dll). Both of them are developed on top of Mono, the open source version of the .NET Framework. For those who have been on the .NET community for a long time, you may remembered that Mono project has been initiate by Miguel De Icaza, the co-founder and current CTO of… Xamarin :)

On iOS, a dedicated compiler (AOT: Ahead Of Time) compiles applications written on C# directly to native ARM code.

For Android, the process is similar to the .NET compilation and execution: the source code is compiled to an Intermediate Language (IL) and, when the code is executed on the device, a second compilation (performed Just-In-Time, JIT) compile the IL to native code. This makes sense because Android applications are used to be developed in Java, which has an internal architecture similar to the .NET architecture.

In both case, you don’t have to worry about the memory management, resources allocation, etc.: all is managed, for you, by the runtime delivered by Xamarin.

Once compiled, the Android applications are packaged in a file with the .apk extension. Like XAP files, these files are only ZIP files that contains:

  • The Android manifest file, on binary format (more on that later)
  • The application code (compiled into the file classes.dex)
  • The differents assets included in the package
  • The differents resources (layouts, drawable)
  • The native libraries containing the Mono runtime.

This last point is important. Indeed, an Android application must be deployed with the native libraries for the desired architecture (armeabi, armeabi-v7a, x86). Be careful that your application won’t be able to run on a particular plateform until the dedicated runtime libraries are deployed on it:

image image

Finally, the Android application also contains the Android Callable Wrappers (ACW), which allows you to call managed code from the Android runtime. The full definition of the Android Callable Wrappers can be found online but, basically, this is similar to the Runtime Callable Wrappers (RCW): a proxy object that allows Java (or COM) to allow .NET code, without having to handle the difference of type between the two worlds. On the other side, the Managed Callable Wrappers (MCW) are bridges allowing .NET code to invoke Android code (so this is the opposite of Android Callable Wrappers). Managed callable wrappers are responsible for converting between managed and Android types and invoking the underlying Android platform methods.

 

What tools are available ?

Xamarin has its own IDE, Xamarin Studio, that looks like a lot to Visual Studio (well, to be honest, it’s more like the first version of SharpDevelop but at least, it’s working):

image

But Xamarin Studio can only be used to develop Android applications, not iOS apps:

image

Fortunately, for the .NET developers we are, it’s also possible to use Visual Studio to develop iOS and Andoid applications!

image

Xamarin also come with a lot of emulators that are available through Xamarin Studio and Visual Studio:

image image

There is also a very nice device manager that allow you to manage the different emulators installed:

image image

image

You may notice that I talk/write a lot about Android. This is not that I dont want to try iOS but to be able to test iOS, you need a Mac (with Xamarin.iOS installed on it) to play the role of a proxy between your PC and the target device. Unfortunately, as I don’t have a such device, I’m not able to try and test that part (if a Apple evangelist read my blog and want to offer me a Mac, feel free to him to do so ;-)

The first time you’ll start an Android emulator, you’ll see this message:

image

Trust me, this is true! Indeed, the first time the emulator starts, the IDE need to deploy on it the Mono Shared Runtime and the Platform Framework corresponding to the API level that will be targeted by your application. So, in my case, the initial start was up to 7 minutes ! Of course, once the emulator is started, the deployments are more faster.

 

A first look of the development part

Each page, of an Android application, is represented by an Activity object. This is the equivalent of the Page objects on Windows (Phone) apps. To define the activity that need to be launched on the first start, you need to put the MainLauncher property to true:

[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")]
public class Activity1 : Activity
{
}

From the point of view of a XAML developer, the development is quite similar. Indeed, on the XAML side, we have the XAML part that defines the UI and the code-behind that corresponds to the app logic. Well, here, this is the same: the activity corresponds to the code-behind part and the XAML part will be associated to the AXML (no, it’s not a typo) files that we will see more in details later.

On the activity, the method OnCreate need to be override to add our own logic. This method is called when the activity is starting so this is where we’ll define our user interface, etc.:

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
}

To define the user interface, we can do it using 2 ways:

  1. By using C# code
  2. By using XML code.

The first way consists in building the GUI by code:

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

    var btn = new Button(this);
    btn.Text = "Hello World!";
    btn.Click += (sender, args) => { };

    SetContentView(btn);
}

image

Even if that works, this is not the most useful way (in particular to create complex UI). So we’ll prefer the XML way.

Each project contains a “Resources” folder that is composed by a set of sub-folders:

  1. Drawable: contains all the resources (images for example) that need to be used in the app
  2. Layout: contains all the layouts that will be designed by the developer
  3. Values: contains all the strings resources available

To add a new view, simply right clic on the Layout folder and select Add –> New item –> Android Layout:

image

The screen that appears offers a visual designer where you can drag and drop controls from the toolbox to create your custom UI:

image

If you click on the “Source” button (located at the bottom of the view), you’ll be able to see the XML representation of the GUI. So, like for the XAML part, the visual designer is just here to serialize the XML content and render it on a surface view:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:minWidth="25px"
    android:minHeight="25px">
    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button1" />
</LinearLayout>

You may notice the particular syntax used to specify the value of the id property: @+id/button1. This syntax tells the parser to generate a resource with the id indicated so, on the file Resource.Designer.cs (which is refreshed after all builds and which contains all the resources values as strongly type properties) a property is automatically added:

public partial class Id
{
    // aapt resource value: 0x7f050001
    public const int MyButton = 2131034113;

    // aapt resource value: 0x7f050000
    public const int button1 = 2131034112;

    static Id()
    {
        global::Android.Runtime.ResourceIdManager.UpdateIdValues();
    }

    private Id()
    {
    }
}

For the strings values (of the buttons, labels, etc.), you have 2 choices: you can hardcode the value and set it to the dedicated property (for example, the Text property of the button) or you can use a similar principle as the id property. Indeed, here is a valid code to set the text property:

<Button
        android:text="@string/TestButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button1" />

So again, we tell the Android parser to generate a dedicated property to the resources file:

public partial class String
{
    // aapt resource value: 0x7f040001
    public const int ApplicationName = 2130968577;

    // aapt resource value: 0x7f040000
    public const int Hello = 2130968576;

    // aapt resource value: 0x7f040002
    public const int TestButton = 2130968578;

    static String()
    {
        global::Android.Runtime.ResourceIdManager.UpdateIdValues();
    }

    private String()
    {
    }
}

But this time, this is a bit different. The String class contains the property corresponding to the string resources we want to use but we have to define the values of these resources. To do so, we need to open and edit the file Strings.xml which is in the subfolder Values of the folder Resources:

 image

The content of this file is a simple list of key/value:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="Hello">Hello World, Click Me!</string>
    <string name="ApplicationName">AndroidApplication1</string>
    <string name="TestButton">My Super Button!</string>
</resources>

Using this system, it’s easy to create a localized version of your application. In the Resources folder, just add a folder “Values-XX” where XX corresponds to the two-letter language code (if you want to support multiples locales of the same language, add the two-letter region code prefixed by the –r letter, for example: Values-fr-rFR for the French France locale; Values-fr-rCA for the French Canadian locale, etc.):

 image

Add a new XML file on the newly created folder (be sure to set its Build Action property to AndroidResource) and just translate the content:

image  image

OK so now that our user interface is almost finished (eventually using string resources for the different labels), we need to display it! To do that, let’s go back to the code of the activity and just modify the parameter of the SetContentView to use our newly interface:

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

    // Set our view from the "demolayout" layout resource
    SetContentView(Resource.Layout.demolayout);
}

Again, after finishing the user interface, the parser generates a dedicated property so we can manipulate it:

public partial class Layout
{
    // aapt resource value: 0x7f030000
    public const int demolayout = 2130903040;

    // aapt resource value: 0x7f030001
    public const int Main = 2130903041;

    static Layout()
    {
        global::Android.Runtime.ResourceIdManager.UpdateIdValues();
    }

    private Layout()
    {
    }
}

image

Your view is now display on screen but you may wonder how you can interact with it so you can retrieve user inputs (clicks con button, etc.). For that, you’ll need to use the FindViewById method:

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

    // Set our view from the "demolayout" layout resource
    SetContentView(Resource.Layout.demolayout);

    var button = FindViewById<Button>(Resource.Id.button1);
}

This method takes in parameter the id of the control you want to manipulate through code (and you can notice, once again, the use of the Resource.Id nested class, which contains all the ids of the graphical elements). Once you get access to the controls, you can manipulate them easily:

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

    // Set our view from the "demolayout" layout resource
    SetContentView(Resource.Layout.demolayout);

    var button = FindViewById<Button>(Resource.Id.button1);
    button.Click += (sender, args) => SetContentView(Resource.Layout.Main);
}

You may also wonder how to access to some assets resources you can embed on the application. To do so, you have 2 choices. For the image files, you need to put them on the “Drawable” folder. After the build, the file Resource.Designer.cs will be updated (as we seen before). Then, to use your new file, simply use it as before:

<ImageView
        android:src="@drawable/Yoda"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/imageView1" />

Here, for the src property, I access to the Yoda file within the “Drawable” folder:

image image

For the other types of files (text files, sound files, video files, etc.), you need to put them on the Assets folder. Files placed on that folder will have a build definition set to AndroidAsset. To be able to use them, you need to call one of the methods of the Asset API of the AssetManager (Asset.Open, Asset.OpenFd, etc.):

var button = FindViewById<Button>(Resource.Id.button1);
button.Click += (sender, args) =>
{
    var assets = Assets.List(string.Empty);
    if (assets.Any())
    {
        var videoFilename = assets.FirstOrDefault(a => a.EndsWith(".mp4"));
        if (!string.IsNullOrWhiteSpace(videoFilename))
        {
            var fileDescriptor = Assets.OpenFd(videoFilename);

            var player = new MediaPlayer();
            player.SetDataSource(fileDescriptor.FileDescriptor, fileDescriptor.StartOffset, fileDescriptor.Length);
            player.Prepare();
            player.Start();
        }
    }
};

To be able to perform some actions, you might need to set the desired required permissions on the Android Manifest file. To do that, open the properties of your project and select the tab “Android Manifest”:

image

In the previous screenshot, the SEND_SMS permission is selected. So the application is free to write code that will send SMS:

SmsManager.Default.SendTextMessage("0123456789", null, "First SMS from Xamarin", null, null);

Without selected this permission, the code throws an exception (one thing I regret currently about exceptions: we don’t have a lot of information about the exact issue):

image

On the project properties, you can also look at the different options you can change like, for example, the particular platforms for which your application will be available or the API version needed to be able to run your app:

image

Some actions you’ll need perform will not need special permissions, even if you think there are needed. Indeed, let’s re-write the sample to send a SMS (don’t forget to uncheck the dedicated permission):

var phoneNumber = Android.Net.Uri.Parse("smsto:0123456789");
var smsIntent = new Intent(Intent.ActionSendto, phoneNumber);
smsIntent.PutExtra("sms_body", "First SMS from Xamarin");
StartActivity(smsIntent);

If you execute this code, you’ll note that there are no errors/exceptions:

image

But how is it possible, as we don’t select the right permission ?! In fact, this is because this sample use an Intent (Android.Content.Intent):

image

An Intent is a kind of concept that is used to say: “Hey, do the following but don’t do it automatically: use a dedicated application to do that!”. So, basically, it’s not your code that performs the action, it’s another app. An intent generally has two pieces of information associated with it; first, what the intent is (a phone call, a camera ), and second, what data does the intent need (such as a phone number) to perform the intention.

That’s why the following code, which use an Intent, does not need special permissions (although it access special information such battery data):

var filter = new IntentFilter(Intent.ActionBatteryChanged);
var battery = RegisterReceiver(null, filter);
int level = battery.GetIntExtra(BatteryManager.ExtraLevel, -1);
int scale = battery.GetIntExtra(BatteryManager.ExtraScale, -1);

var batteryLevel = Math.Floor(level * 100D / scale);

int status = battery.GetIntExtra(BatteryManager.ExtraStatus, -1);
var isCharging = status == (int)BatteryStatus.Charging || status == (int)BatteryStatus.Full;

// How are we charging?
int chargePlug = battery.GetIntExtra(BatteryManager.ExtraPlugged, -1);
var usbCharge = chargePlug == (int)BatteryPlugged.Usb;
var acCharge = chargePlug == (int)BatteryPlugged.Ac;

 

Access to the user’s contacts

To be able to access to the user’s contacts, it’s pretty easy. We’ll use the ManagedQuery API to query the contact’s properties:

var uri = ContactsContract.Contacts.ContentUri;

string[] projection = { ContactsContract.Contacts.InterfaceConsts.Id, ContactsContract.Contacts.InterfaceConsts.DisplayName, };
var cursor = ManagedQuery(uri, projection, null, null, null);

var items = new List<string>();

if (cursor.MoveToFirst())
{
    do
    {
        items.Add(cursor.GetString(cursor.GetColumnIndex(projection[1])));

    }
    while (cursor.MoveToNext());
}

The API takes in parameters the list of properties you want to retrieve. In the previous code, we load the Id and DisplayName properties and we add the last one on a list of string objects. Of course, when using the ManagedQuery object, it’s possible to filter the results:

var uri = ContactsContract.Contacts.ContentUri;

string[] projection = { ContactsContract.Contacts.InterfaceConsts.Id, ContactsContract.Contacts.InterfaceConsts.DisplayName, };
var cursor = ManagedQuery(uri, projection, null, null, null);

var items = new List<string>();

if (cursor.MoveToFirst())
{
    do
    {
        items.Add(cursor.GetString(cursor.GetColumnIndex(projection[1])));

        var userId = cursor.GetString(cursor.GetColumnIndex(projection[0]));
        var userEmailCursor = this.ManagedQuery(ContactsContract.CommonDataKinds.Email.ContentUri, null, ContactsContract.CommonDataKinds.Email.InterfaceConsts.ContactId + "=" + userId, null, null);
        if (userEmailCursor.Count > 0)
        {
            while (userEmailCursor.MoveToNext())
            {
                var userEmail = userEmailCursor.GetString(userEmailCursor.GetColumnIndex(ContactsContract.CommonDataKinds.Email.InterfaceConsts.Data));
            }
        }

    }
    while (cursor.MoveToNext());
}

Ok so now, we have a list of the contacts stored in memory but we need to find a way to display it on the screen. For that, we’ll replace the base type for the current activity by the ListActivity. This is a particular activity type that expose a ListAdapter object, which allow you to directly displays a list of items on the screen using a particular template:

ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, items);

As its name suggests, the SimpleListItem1 display the items using a simple list:

image

If you want to display the items with some Checkboxes, you have just to use SimpleListItemsSingleChoice:

ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItemSingleChoice, items);

Which displays the following:

image

So, by changing a simple property, you can change the display of your items! If you want to know which item is clicked by the user, you just have to override the OnListItemClick method (available because we are on a ListActivity):

protected override void OnListItemClick(ListView l, View v, int position, long id)
{
    var item = items[position];

    Android.Widget.Toast.MakeText(this, item, ToastLength.Short).Show();
}

 

Of course, there are a lot of other things that you can do in your applications but I hope this first overview gave you all the pointers you need to start !

Happy (Xamarin) coding!

You can follow any responses to this entry through the RSS 2.0 You can leave a response, or trackback.

2 Responses

Add Comment Register



Leave a Reply