Have you ever wondered if there is a solid, meaningful way of creating native mobile apps other than mastering native SDKs? Or is there a way to write an iOS app using JavaScript or C# instead of Objective-C or Swift? In this post I’ll try to compare four biggest players in the mobile cross-platform development industry: Xamarin, Apache Cordova with Ionic, Appcelerator Titanium and RubyMotion. My aim is to present you how to make a simple app using each of these technologies. Also, I’ll try to cover most of frequently asked questions by my collegemates, co-workers and developers on the Internet – pricing, availability, extra tools, nativeness, difficulty level.

This blog post is divided into two parts: first one covers Xamarin and Apache Cordova, second – RubyMotion and Appcelerator Titanium.

Extended source code for every project available at my Github repo.


 

Xamarin

It’s good to know: 

C#, .NET

Compatible with: 

iOS, Android, WindowsPhone, Mac, Windows

Pricing: 

Free for OSS development and small teams, Visual Studio Proffesional/Enterprise licenses needed for larger teams

Is it truly native? 

Yes. Xamarin provides direct interfaces between native APIs and C#. You can either create a truly native iOS (or Android, WinPhone, …) application using native SDK (in C# instead of Objective-C/Swift) or use Xamarin.Forms and develop applications for every platform at once using Shared Project or PCL (Platform Class Libraries). Xamarin.Forms includes approx. 40 of controls, pages and layouts, which are later mapped into native controls at runtime. No jokes, this really feels (and indeed is) native.

Tools

Xamarin provides a wide range of developer tools:

– Xamarin Insights – application analytics, crash logs, user logs etc (partially free)

– Xamarin Text Cloud along with Xamarin Test Recorder – test automation tools; over 1000 devices in cloud for automated UI testing (extra paid)

– Xamarin Android Player – Andriod emulator, much faster than the stock Android Emulator (free). For every Android application I will use Xamarin Android Player, as it’s in my opinion the fastest and the most stable Android emulator up to date.

– Xamarin Profiler – collects information about apps, helps with finding memory leaks, performance bottlenecks etc.

 

IDE

Xamarin Studio, Visual Studio

Step by step guide

  1. Create an account at www.xamarin.com and download Xamarin Studio. I’ll use Xamarin Studio as it’s available both for PCs and Mac. If you’re using Visual Studio, download a VS plugin from here.

Xamarin offers a free, 30-day trial account with all Business Edition features. To activate your account, login to Xamarin from Xamarin Studio, populate all necessary fields and hit Start Trial.

  1. Click File -> New -> Solution, then choose Cross-platform -> Xamarin.Forms App. Enter your app name, select Android and iOS, select Use Portable Class Library

If you’re interested in differences between a PCL project and Shared Library project, visit this page.

Click Next, select your project directory and click Finish

  1. As you can see in the project explorer, Xamarin generated three projects within your main solution: Main project, iOS project and Android project (if you use Visual studio you can also check Windows Phone option which will make WinPhone project generated as well). We’ll focus on Main project, where we’ll add all source code that needs to be shared across all platforms.
  2. Go to the Main project and add a new File (right click on the project -> Add -> New File -> Forms -> Forms ContentPage Xaml), name it GamePage.

Note: Xamarin.Forms uses MVVM pattern.

 

  1. Basically, there are three ways of managing views in Xamarin.Forms: XAML files, in-code, and those two combined. We’ll use XAML files, as it (in my opinion) suits best the MVVM pattern.

I’ve prepared a basic view for RockPaperScissors Game. Pase it into GamePage.xaml:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="RockPaperScissors.GamePage">
	<ContentPage.Content>
		<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
			<Button HorizontalOptions="FillAndExpand" HeightRequest="50" Text="ROCK" BackgroundColor="Gray" TextColor="White" Clicked="OnUserChoiceButtonClicked"/>
			<Button HorizontalOptions="FillAndExpand" HeightRequest="50" Text="PAPER" BackgroundColor="Gray" TextColor="White" Clicked="OnUserChoiceButtonClicked"/>
			<Button HorizontalOptions="FillAndExpand" HeightRequest="50" Text="SCISSORS" BackgroundColor="Gray" TextColor="White" Clicked="OnUserChoiceButtonClicked"/>
			<Label x:Name="ComputerChoiceLabel" Text="Computer:"/>
			<Label x:Name="UserChoiceLabel" Text="You:"/>
			<Label x:Name="ResultLabel" Text="Result:"/>
		</StackLayout>
	</ContentPage.Content>
</ContentPage>

We’ll manage all the logic inside a code-behind file – GamePage.xaml.cs. As you can see, every button has ‚Clicked’ attribute. Using it, we can define which function is being called after clicking the button. In our case it’s „OnUserChoiceButtonClicked”. Let’s jump to the xaml.cs file. Add these lines there:

using System;
using System.Collections.Generic;

using Xamarin.Forms;

namespace RockPaperScissors
{
	public partial class GamePage : ContentPage
	{
		private readonly Random getrandom = new Random();
		private readonly object syncLock = new object();

		public GamePage ()
		{
			InitializeComponent ();
		}

		private void OnUserChoiceButtonClicked(object sender, EventArgs args)
		{
			HandleUserChoice(((Button)sender).Text);
		}

		private void HandleUserChoice(string userChoice) {
			//0 - rock, 1 - paper, 2 - scissors
			var computerChoice = GetRandomInt(0, 2);

			switch (userChoice) {
			case "ROCK":
				if (computerChoice == 0) {
					HandleUserChoice("ROCK");
				} else if (computerChoice == 1) {
					ShowResultsToUser(false);
					ComputerChoiceLabel.Text = "Computer: PAPER";
				} else {
					ShowResultsToUser(true);
					ComputerChoiceLabel.Text= "Computer: SCISSORS";
				}
				break;
			case "PAPER":
				if (computerChoice == 1) {
					HandleUserChoice("paper");
				} else if (computerChoice == 0) {
					ShowResultsToUser(true);
					ComputerChoiceLabel.Text = "Computer: ROCK";
				} else {
					ShowResultsToUser(false);
					ComputerChoiceLabel.Text = "Computer: SCISSORS";
				}

				break;
			case "SCISSORS":
				if (computerChoice == 2) {
					HandleUserChoice("scissors");
				} else if (computerChoice == 1) {
					ShowResultsToUser(true);
					ComputerChoiceLabel.Text = "Computer: PAPER";
				} else {
					ShowResultsToUser(false);
					ComputerChoiceLabel.Text = "Computer: ROCK";
				}
				break;
			}

			UserChoiceLabel.Text = "You: " + userChoice;
		}

		private int GetRandomInt(int min, int max)
		{
			lock(syncLock) {
				return getrandom .Next(min, max);
			}
		}

		private void ShowResultsToUser(bool didUserWin) {
			ResultLabel.Text = didUserWin ? "YOU WON!" : "YOU LOST!";
		}
	}
}

That’s it – it’s that easy! Just 5 steps to make it up and running. :) The code above represents just three buttons and three labels. I’ve added some design polishing to this project and ended up with something like this:

xamarin-androidxamarin-ios

 

 

 

 

 

 

 

 

Switch between tabs to see the native fell of Xamarin (and by the way see how a tabbed page works).

But is Xamarin a good solution for bigger mobile developers teams? Well, it’s indeed a powerfull tool. All C# libraries, including NuGet packages work perfectly, not to mention Java libraries for Android, that can be easly ported to C# with Java Binding Libraries. Likewise, if there is a control that is not customizable enough by default, Xamarin gives you Export Renderers mechanism, which allow you to take full controll of any UI element by overriding rendering behaviours using truly native SDK.

To be honest, Objective-C is not a fun language to learn for all developers – from my experience, learning all Cocoa and iOS mechanisms in C# with Xamarin.iOS can help a lot with learning iOS in general.

It’s worth to mention Xamarin fully supports almost all native mechanisms like camera, contacts, calendars etc. It’s also easy to implement push notifications.


 

APACHE CORDOVA & IONIC

It’s good to know:

HTML, JavaScript, AngularJS, CSS

Compatible with:

Android, iOS, Windows Phone, Firefox OS, Blackberry, Ubunty

Pricing:

Free (open source)

Is it truly native?

Yes… No. The whole view runs in OS native web view container – the front-end is build with JavaScript. A Cordova app is basically a web app packed into platform-specific package installer (.ipa for iPhone, .apk for Android and so on). There is a number of native API available for each platform like GPS, Accelerometer, Calendar, Contacts, Camera etc., but the list is limited.

UI/Unit testing

There is no Cordova native testing mechanism. Alternatively, you can use an open source testing framework – Appium.

IDE

Every IDE that handles JavaScript.

Step by step guide

  1. We’ll use Visual Studio Code, as it’s free and available both on Mac OSX and Windows. You can download VSC from (link: https://code.visualstudio.com/)
  2. You’ll need full developer iOS and Android SDK:

Android instructions here, iOS instructions here

  1. Install Node.js 4, latest Cordova and Ionic command-line tools

Node.js link

Cordova & Ionic:

$npm install -g cordova ionic

For iOS development install: 

$sudo npm -g install ios-sim
  1. Let’s create a project. We’ll use one of predefined Ionic projects just to show you how easy is to create a working project.

Go to the project’s directory and type in Terminal (OSX):

ionic start RockPaperScissors tabs

That will download a sample project from Ionic’s Github repository and set it up fro you. I decided to use „tabs” template for this presentation, as it can easily present the nativeness of Apache Cordova, which I’ll describe later.

  1. Add Android and iOS platforms:
$ionic platform add ios (no need on OSX - Ionic will add iOS project by default)

$ionic platform add android
  1. Build and launch an empty app:
$ionic build ios
$ionic emulate ios
  1. You should see your app being deployed to an iOS simulator.

Let’s dive a little into Visual Studio Code. Lauch the VSC, open the VS Code Command Pallete by pressing cmd + P and type the following command:

$ext install cordova-tools

Restart the VSC, go to View -> Debug, click on a gear icon at the top of the screen, select Cordova. A launch.json file has been generated. This file contains all launch configurations. For example, we have an android emulator, that is listed as „10.71.34.101:5555” (to see all android devices type „adb devices” in Terminal) and we want to set it as a default emulator. Find „Run Android on emulator” field in launch.json file, change „target” from „emulator” to „10.71.34.101:5555”.

launch json file android emulator

Similarly, you can change the iOS target by, for example, typing „iPhone-6-Plus” in „target” field within „Run iOS on simulator” field.

Save the file and hit F5. You should see your app being deployed to  device you’ve just specified.

You can now see how great Cordova (and Ionic) is – both platforms, despite using the same source code, remaind a true native feel. Android tabs are on the top of the screen, iOS tabs – on the bottom, just like it supposed to be.

Rock, Papers, Scissors

Before adding any new code, let’s discuss how a Cordova project is built.

            All the HTML, CSS and JS files, that you want to use in your app, are located in the WWW folder.

cordova folders

 

Under RESOURCES folder you can find icons, splash screens, text files and any other files for specific platform.

To control all the app’s settings, find the config.xml file. It should be located in the project’s root directory. The file is rather self-explanatory. You can control the app’s name there, or add an author information.

Creating a mobile app using Apache Cordova is pretty much like creating an HTML page with JavaScript. Ionic gives you a great set of predefined, prepared for mobile development functions. Let’s see what we can change in our prebuilt app.

Ionic uses AngularJS. You’re about to find out that this powerful tool fits perfectly in hybrid cross-platform mobile development.

Open index.html. As you can see, the whole view is described by Angular directives – the navigation bar, for example, is an ion-nav-bar directive. The header says that our app is controller by app.js script sheet – let’s see what’s inside.

Along the code, Ionic also has lots of commentars which makes this tool excellent for newstarters.

Our app contains free tabs – Status, Chats and Account. Each tab is defined in the app.js file. Let’s modify one of them. I have prepared the game’s code, so simply open the tab-dash.html file under the templates folder, and paste code listed below

<ion-view view-title="Account">
  <ion-content>
    <ion-list>

    <ion-toggle  ng-model="settings.enableFriends">
        Enable Friends
    </ion-toggle>

    <button class="bu[ctton">
        <i class="icon ion-loading-c"></i> Loading...
    </button>

    <button class="button icon-left ion-home">Home</button>

    <button class="button icon-left ion-star button-positive">Favorites</button>

    <a class="button icon-right ion-chevron-right button-calm">Learn More</a>

    <a class="button icon-left ion-chevron-left button-clear button-dark">Back</a>

    <button class="button icon ion-gear-a"></button>

    <a class="button button-icon icon ion-settings"></a>

    <a class="button button-outline icon-right ion-navicon button-balanced">Reorder</a>

    <ion-checkbox ng-model="filter.blue">Red</ion-checkbox>
    <ion-checkbox ng-model="filter.yellow">Yellow</ion-checkbox>
    <ion-checkbox ng-model="filter.pink">Pink</ion-checkbox>

    <div class="item range">
        <i class="icon ion-volume-low"></i>
        <input type="range" name="volume">
        <i class="icon ion-volume-high"></i>
    </div>

    </ion-list>
  </ion-content>
</ion-view>

Create a js file at /js directory and name it functions.js (remember to add proper reference in index.html). Paste the game logic there:

function handleUserChoice(userChoice) {
    //0 - rock, 1 - paper, 2 - scissors
    var computerElement = document.getElementById("computer-choice");
    var userElement = document.getElementById("user-choice");
    var computerChoice = getRandomInt(0, 2);
    setChoiceImage(computerChoice, false);

    switch (userChoice) {
        case 0:
            if (computerChoice == 0) {
                handleUserChoice(0);
            } else if (computerChoice == 1) {
                showResultsToUser(false);
                computerElement.innerHTML = "Computer: PAPER";
            } else {
                showResultsToUser(true);
                computerElement.innerHTML = "Computer: SCISSORS";
            }

            userElement.innerHTML = "You: ROCK";
        break;
        case 1:
            if (computerChoice == 1) {
                handleUserChoice(1);
            } else if (computerChoice == 0) {
                showResultsToUser(true);
                computerElement.innerHTML = "Computer: ROCK";
            } else {
                showResultsToUser(false);
                computerElement.innerHTML = "Computer: SCISSORS";
            }

            userElement.innerHTML = "You: PAPER";
        break;
        case 2:
            if (computerChoice == 2) {
                handleUserChoice(2);
            } else if (computerChoice == 1) {
                showResultsToUser(true);
                computerElement.innerHTML = "Computer: PAPER";
            } else {
                showResultsToUser(false);
                computerElement.innerHTML = "Computer: ROCK";
            }

            userElement.innerHTML = "You: SCISSORS";
        break;
    }

    setChoiceImage(userChoice, true);
}

function setChoiceImage(choice, isUserChoice) {
    var source = ""
     switch (choice) {
         case 0:
             source = "img/rock";
            break;
         case 1:
            source = "img/paper";
            break;
         case 2:
            source = "img/scissors";
            break;
     }

    source = source.concat(isUserChoice ? ".png" : "_op.png");
    document.getElementById(isUserChoice ? "user-choice-image" : "computer-choice-image").src = source;
}

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function showResultsToUser(didUserWin) {
    var resultElement = document.getElementById("result");
    resultElement.innerHTML = didUserWin ? "YOU WON!" : "YOU LOST!";
    resultElement.style.color = didUserWin ? "Green" : "Red";
}

Also edit the css style sheet:

.inner-div {
    width: 90%;
    margin: 0 auto;
    text-align: center;
}

.user-image {
    width: 90px;
    height: 90px;
}

.computer-image {
    width: 120px;
    height: 120px;
}

.score-text {
    font-size: 14pt;
    color: black;
}

As you can see, we changed the title and contents of our view. I’ve also changed following files: tab-dash.html, tabs.html, app.js and controllers.js – just renamed all the „dash” words to „game”.

Hit F5 – you should see yet another Rock Paper Scissors game.

The code above is just a minimum code to make the game work properly. I’ve decided to polish the design a little bit and here’s what I’ve ended up with:

cordova-android cordova-iphone

Feel free to explore other views I’ve prepared for this article – other two tabs contain several popular UI elements, like buttons, switches, labels etc. It’s always worth to run it on iOS and Android just to compare how efficient it is compared to truly native components.

 

Part two – coming soon.

Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY