Wednesday, 16 January 2013

Xamarin for Java Developers

Last night I was given the opportunity to present Xamarin's Mono for Android to the East Bay Google Developer Group. It was a lot of fun, with plenty of the audience asking a lot of great questions and generally being curious about how C# can be used to build Android apps. Here are the slides from the talk - please drop me a line with any feedback or questions!

One topical question was "what does using Xamarin and C# offer existing Android Java developers?". I have a couple of thoughts which are listed below (in no particular order):

Learn a new language!
The days of specializing in a single language throughout your career (or even throughout the year!) are over. Once upon a time it was COBOL all the way down, and you could argue that it's still enough to just know C/C++. But it's no longer the norm ~ developers want to grow and learn, and use the best tool for the job (whether it's Perl, PHP, Java, Ruby, C#, F#, Javascript, TypeScript, Go, or whatever).

It can be daunting though, to start from scratch and learn a new IDE, framework and syntax - which is why I think C# is a great progression for Java devs. The two languages are obviously related - there is a lot of common syntax and equivalent keywords that make it easy to get proficient quickly. They're both strongly typed, so the IDE and compiler can really help you learn. Then once you know the C# basics, a whole world of new APIs open up to you: LINQ, the .NET framework's serialization and web service features, Parallel Task Library and async support, reactive extensions, and more.

It also introduces you to another IDE (Visual Studio is a great tool, as is Xamarin's free MonoDevelop IDE), which in turn can encourage you to further explore other languages and platforms (suddenly it's a small leap to work on Windows Phone, or try F#). Using the free trial you can easily get productive in C# and Android development without any up-front cost: you can run your apps on the Android emulator, and choose to work on either Windows or Mac with MonoDevelop.

Cross-platform development!
There are a lot of Java developers who are already proficient with the Android SDK and have published successful apps to Google Play, or Amazon, or Samsung app stores; and there's another group of corporate/enterprise developers building apps for internal/extranet use that were designed for Android. When these developers ask "why Xamarin?", I never say "throw away everything you've done and re-write in C#!" -- that'd be crazy ;-)

But what happens when you want to take these apps cross-platform, either to make more money on the iOS and Mac App Stores or to better support a corporate BYOD policy which means your internal apps need to run on iOS and Windows? You can choose to learn Objective-C to write for iOS and C# for Windows... or take the opportunity provided by Xamarin to use C# for all the non-Java platforms and reduce the amount of code you have to support and re-write by half!

Following on from the first point, I think learning C# is a much smaller leap for a Java developer than Objective-C; and once you've done so you can work on either iOS apps using Xamarin's MonoTouch or Windows Phone, Windows 8 and Windows RT tablet apps! You might like C# so much that you do go back and re-write your Java, or at least start building a hybrid that shares some Java and C# code...

Xamarin does Android well too :)
If Java developers do fall in love with C# then they also find that Xamarin does Android just as well as anyone (probably better!). Our MonoDevelop IDE (and our integration with Visual Studio) means you get an awesome coding experience (autocomplete/intellisense/code completion, debugging, refactoring, source control integration, etc) as well as a drag-and-drop UI designer. You be the judge of whether it's a better experience than Eclipse :)

Fin
In summary, why not? As a Java developer you have a lot to gain and nothing to lose by giving C# a try. A whole world of new platforms, tools and frameworks become available with a very low barrier to entry. Try it - you just might like it ;-)

Friday, 4 January 2013

Localizing iOS6 Storyboards with MonoTouch

Localization and internationalization of XIB and Storyboard files has historically been a very manual process. Typically these file types would be duplicated in each 'language directory' (*.lproj) and then the text and layout tweaked independently by each translator. Changes to the actual Storyboard or XIBs would need to be manually propagated across all the 'language copies'.

In iOS6 Apple introduced a new concept - Base Localization - which you can read about in their documentation on Internationalizing Your App. Your project can contain a 'special' Base.lproj directory where the Storyboard files are located, and then a corresponding *.strings file (whose filename matches the Storyboard's) in each language directory with the translations.

There is a small sample showing how this works with MonoTouch - TaskyL10nStoryboard on github. There is no IDE support currently, but you can easily create the Base.lproj directory manually in MonoDevelop and everything works as expected. Here's a screenshot of the project structure:

then inside the Storyboard itself you need to identify the controls you wish to localize. Click on a control to discover its Object ID, and shown in this screenshot:

Using the Object IDs from the Storyboard file, we can translate the display values for various properties (including text, placeholders and others) in the MainStoryboard.strings file in each language directory, like this:
"SXg-TT-IwM.placeholder" = "nombre de la tarea";
"Pqa-aa-ury.placeholder"= "otra información de tarea";
"zwR-D9-hM1.text" = "Detalles de la tarea";
"bAM-2j-Rzw.text" = "Notas";
"NF3-h8-xmR.text" = "Completo";
"MWt-Ya-pMf.normalTitle" = "Guardar";
"IGr-pR-05L.normalTitle" = "Eliminar";
Using the Object ID and property as the localization key is quite different to Apple's previous guidance on localization, where the key is typically the base-language's actual displayable value.

Here's the localized Storyboard, in Japanese:


What about layout?
Strings can often be very different lengths in different languages. When you used a different Storyboard or XIB for each language then the control sizes could be manually adjusted to fit. When using Base Localization you should use Apple's new constraint-based layout to handle these size differences.

What about iOS5 and earlier?
This method only works on iOS6. To localize text on earlier versions of iOS you will have to duplicate your Storyboards and XIBs for each language, or create outlets for all the controls and set their localized text values in code using NSBundle.MainBundle.LocalizedString().
There is another localized sample - TaskyL10n - which shows how to localize text elements directly and uses MonoTouch.Dialog.

Sunday, 23 September 2012

iOS 6 UIRefreshControl with MonoTouch

Another cute little new feature of iOS 6 is the built-in pull-to-refresh control - UIRefreshControl. It is really simple to wire up with Xamarin on a regular UITableViewController or with MonoTouch.Dialog.

In case you're unfamiliar with it, this is how the new control looks:

To implement:

  • Assign the RefreshControl property of a UITableViewController to a new instance of the control, eg. RefreshControl = new UIRefreshControl();
  • Create a handler for the control's ValueChanged event, eg RefreshControl.ValueChanged += HandleValueChanged;. In this handler your code will do whatever is required to refresh the data when the user pulls down enough to trigger the event.
  • In HandleValueChanged code, once you have refreshed the table, call the EndRefreshing method of the control to stop it spinning. Your refresh code was probably not running on the main thread, in which case you'll probably want to use InvokeOnMainThread like this: InvokeOnMainThread (() => {RefreshControl.EndRefreshing (); });

There are additional features you may use:

  • BeginRefreshing - call this method from your code if you start a refresh operation from code (eg. on a timer or in response to some other event). This sets the UI of the control to indicate there is already a refresh in progress.
  • Refreshing - whether there is already a refresh in progress.
  • AttributedTitle - optional text that appears under the refresh control.
  • TintColor - customize the appearance of the control to match your application's theme.

Refer to Apple's UIRefreshControl doc for additional info.

UPDATE: What about iOS 5?

This above example will not work on earlier versions of iOS - the UIRefreshControl class does not exist, nor does the RefreshControl property on UITableViewController. To get around this problem, the following code does a system check and falls back to an old-fashioned navbarbutton in earlier versions of iOS:

if (UIDevice.CurrentDevice.CheckSystemVersion (6,0)) {
    // UIRefreshControl iOS6
    RefreshControl = new UIRefreshControl();
    RefreshControl.ValueChanged += (sender, e) => { Refresh(); };
} else {
    // old style refresh button
    NavigationItem.SetRightBarButtonItem (new UIBarButtonItem (UIBarButtonSystemItem.Refresh), false);
    NavigationItem.RightBarButtonItem.Clicked += (sender, e) => { Refresh(); };
}

The Refresh method should contain the code that actually gets new data and updates the UITableView. That method should contain a similar if (CheckSystemVersion(6,0)) clause that wraps the call to the RefreshControl.EndRefreshing method on the main thread. Users on older operating systems will see this:

Thursday, 20 September 2012

iOS 6 released, supported by Xamarin

It would be hard to miss the news that Apple is launching their new iPhone 5 this week, and has also released the final version of iOS 6. What's also great is that Xamarin supports iOS 6 too, on release day! There's already plenty of documentation, using C# with StoreKit, PassKit, EventKit, UIKit changes and more.

Of course there are heaps of little additions as well as those big ones, including a raft of new Core Image Filters to play with. For those working on the next Instagram (isn't everyone ;-), here's a preview of a couple of them:


(Posterize, Bloom, Invert, Perspective and Vortex)

For more information, review the Introduction to CoreImage in iOS 5 and the additional sample code for iOS 6. You might also like Apple's CoreImage Filter Reference.

Thursday, 13 September 2012

Microsoft's Azure Mobile Services... and WP7... and Mac

So far, Azure Mobile Services have been added to MonoTouch and Mono for Android (as well as Microsoft's getting started sample for Windows 8).
To complete the 'set', I ported the MonoTouch code to MacOSX using the free, open-source MonoMac AND used @kenegozi's 'unofficial' client to munge Azure Mobile Services into our existing Tasky sample on WP7.

These aren't production-quality implementations, mind you, just a couple of quick hacks to illustrate the beauty and simplicity of having C# and the .NET framework available across all these platforms. Oh, and also show the beauty of Azure Mobile Services :-)
You can grab the code for all of these from TaskCloud/Azure on github. You'll need to sign up for the Azure trial and follow the instructions to set up the Todo list tutorial.
Screenshots
Here's how the WP7 and MonoMac versions look:

Saturday, 1 September 2012

Microsoft's Azure Mobile Services... and Mono-for-Android

Yesterday's post introduced a quick implementation of Microsoft's Azure Mobile Services using MonoTouch to build an iOS app.
The WebClient and Json handling was easily refactored into a single class - AzureWebService - which was then added to the existing Android version of the Tasky sample... and now we have the same Azure Mobile Service being access by three platform clients: Windows 8, iOS and Android all with C# (and the iOS and Android apps sharing the service client code).

Additional features have also been added to AzureWebService to allow deletion of tasks. The Android app source is on github and it looks like this (delete has been added to the iOS app too):

Here is a discussion of how the API was reverse-engineered with Fiddler. The REST endpoints that TaskyAzure accesses are:

GET /tables/TodoItem

GET /tables/TodoItem/?$filter=(id%20eq%20{0})

PATCH /tables/TodoItem/{id}
{"id":1,"text":"updated task text","complete":false}

POST /tables/TodoItem
{"text":"new task text","complete":false}

DELETE /tables/TodoItem/{id}

Finally, only a few small updates were required in the Windows 8 example prevent the completed tasks from disappearing and instead make use of the checkbox in a more natural way:

Now all three apps are reading and writing to the same Azure data store! Can't wait for the official cross-platform APIs :-)

Friday, 31 August 2012

Microsoft's Azure Mobile Services... and MonoTouch

Microsoft only recently announced a cool new addition to the Azure product offering: Mobile Services. They have done a great job at providing a getting started tutorial that gives you a working Windows 8 app in about 5 minutes (seriously, it's fast and easy).

Azure Mobile Services consist of an underlying REST API, so it didn't take long for someone (Chris Risner :-) to put a simple iOS client together. That was all the inspiration required to get it working with MonoTouch.

Actually there is already a MonoTouch todo-list example called Tasky and it has previously been adapted to use Apple's iCloud storage.

The finished code for TaskyAzure borrows heavily from the existing Tasky samples (eg. it uses MonoTouch.Dialog), and really only borrows the REST API urls and Json from Chris' post. I might be biased, but the C# code looks a lot simpler to me :-)
Visit github for the TaskyAzure code. The app looks like this:

And just to prove that the Windows 8 app and the MonoTouch app are both writing to the same Azure database, here is a screenshot of the Azure Management Portal showing the data storage:
Azure Mobile Services looks pretty interesting - look forward to seeing the official cross-platform APIs :-)

UPDATE: to try the code follow the Microsoft's instructions, including creating a free trial account. Once your Azure Mobile Service has been created, configure the app by updating the constants in the AzureWebService.cs class:

static string subdomain = "xxxxxx"; // your azure subdomain
static string MobileServiceAppId = "xxxxxx"; // your application key