Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cross-platform Mobile Applications with C# and .NET

Cross-platform Mobile Applications with C# and .NET

NEBytes User Group 2012 - 15th August 2012

Chris Hardy

August 15, 2012
Tweet

More Decks by Chris Hardy

Other Decks in Technology

Transcript

  1. Chris Hardy • C# Contractor • Work with Xamarin •

    Write some books • First spoke about MonoTouch in January 2010 • http://twitter.com/chrisntr
  2. What is Mono? • Open source implementation of the .NET

    platform, based on ECMA 334/335 • 2001: Created to bring Windows applications to Linux • 2003: Acquired by Novell with Ximian • Matured at Novell in research mode; now a world-class runtime.
  3. May 2011: Attachmate • May 2nd: Attachmate buys Novell -

    Mono team laid off • Xamarin founded 2 weeks later • Angry Mono customers pressure Novell to cooperate with Xamarin • Xamarin secures a perpetual license to all Mono IP: copyrights, patents and trademarks
  4. Xamarin • Team of around 47 people • Over 150,000

    downloads • Over 7,500 paid users • $12m Series A investment
  5. What is MonoTouch? • C# on iOS devices (iPhone, iPod

    Touch, iPads) What MonoTouch is not... • Silverlight for iOS devices • Compact Framework for iOS devices • iOS development without a Mac • A meta-platform
  6. Commercial Product • Free for Simulator-only • $399 for Professional

    License (Requires Apple Dev License) • $999 for Enterprise License (Requires Apple Dev License Pro/Ent) • $2499 for Enterprise Priority License (Requires Apple Dev License Pro/Ent)
  7. MonoTouch APIs .NET APIs Native APIs 3rd Party mscorlib System

    System.Core (LINQ) System.Data Mono.Data.Sqlite System.ServiceModel System.Json System.Web.Services (WCF) System.Xml System.Xml.Linq AddressBook/ AddressBookUI AudioToolbox/ AVFoundation CoreAnimation CoreGraphics CoreLocation EventKit/EventKitUI ExternalAccessory GameKit MapKit NewsstandKit StoreKit Twitter UIKit And so on.... OpenTK OpenGL OpenAL SQLite MonoGame RestSharp Json.NET ServiceStack Steema TeeChart Flurry Analytics RedLaser And so on...
  8. Strong Types • Objective-C Arrays are weakly typed: NSArray return

    values. • MonoTouch has strong types: UIView[] Subviews { get; } vs NSArray *subviews; • Code Completion - explore the API...
  9. MonoTouch Events • Supports Objective-C pattern (including blocks): webView.Delegate =

    new MyWebViewDelegate(); • C# style events as well: webView.PageLoaded += delegate { HideSpinningWheel(); }
  10. Garbage Collection x2 • Automatic: • Mono’s GC will collect

    objects on demand • Deterministic: • Use when you need control. • Every object in MonoTouch implements IDisposable using (var image = UIImage.FromFile(“foo.png”)){ surface.DrawImage(image, 20, 20); }
  11. Objective-C Library • Download the .a static library and header

    file • Run parse/btouch command to create a self contained .dll • Add reference to the project • Include any resources that are required
  12. Rebuild your libraries • Can’t just use any DLL •

    Re-compile for each lib • Each framework has its own class library .NET Libraries
  13. What is Mono for Android? • C# on Android devices

    What Mono for Android is not... • Silverlight for Android devices • Compact Framework for Android devices • Supported for Linux • A meta-platform
  14. • Available on Windows and Mac • First-class VS 2010

    Support • MonoDevelop on Windows and Mac • JIT (Just in Time compilation) • Potential to support all .NET languages • Shared Runtime for Development • APK for release includes Mono + Linked Assemblies Mono for Android
  15. Mono for Android APIs .NET APIs Native APIs 3rd Party

    mscorlib System System.Core (LINQ) System.Data Mono.Data.Sqlite System.ServiceModel System.Json System.Web.Services (WCF) System.Xml System.Xml.Linq Android.Accounts Android.App.* Android.Bluetooth Android.Content.* Android.Database Android.Graphics Android.Hardware Android.Locations Android.Net.* Android.Nfc Android.Text Android.Util Android.Views.* Android.Widget Java.Lang.* Java.Util.* And so on.... OpenTK OpenGL OpenAL SQLite MonoGame RestSharp Json.NET ServiceStack Steema TeeChart And so on...
  16. Commercial Product • Free for Simulator-only • $399 for Professional

    License • $999 for Enterprise License • $2499 for Enterprise Priority License
  17. x86 Emulator Support • Much faster deployment • Debugging is

    almost instant • Only supported on Intel • Provided by Google
  18. Features • MonoDevelop iPhone/Android Add-In • Visual Studio support for

    Android • monotouch.dll / monoandroid.dll • Full static AOT compiler / Allow JIT for Android • Support for all your existing code • Reflection • Generics • LINQ • Anonymous Methods • Lambda’s etc...
  19. What about App Size? • 50 MB (compressed) limit on

    3G/Edge downloads • .Net BCL and other libraries are huge • Mono Linker to the rescue!
  20. Win/WP7 WPF Silverlight OSX MonoMac C# Plus ECMA languages .NET

    iOS MonoTouch Android Mono for Android Mono Business Logic and Middleware (engine, core and 3rd party) Native UI APIs Runtime OS Code sharing and native experience
  21. MWC 2012 • 1,635 Lines of shared code - 771

    for ORM • iPhone + iPad (2,476 LOC / 2 Apps) - 57% Re-use • Android (1,095 LOC) - 60% Re-use • Windows Phone 7 (896 LOC) - 65% Re-use
  22. Techniques for Cross Platform Code 1. Portable Library Tools 2.

    Linking Files 3. Project Linker 4. Xamarin.Mobile
  23. Portable Library Tools • Pros • One class library to

    rule them all • Common subset across all platforms • Cons • No Pre-processor Directives • No platform specific-code • Limited API set - no System.Xml.Linq or System.Net.WebClient
  24. Project Linker • Pros • Auto-link files between projects •

    Cons • Does not work with MonoDevelop • Must have all projects in the same solution
  25. StringBuilder builder = new StringBuilder(); String lineSep = System.getProperty("line.separator"); ContentResolver

    content = getContentResolver(); Cursor ncursor = null; try { ncursor = content.query (ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data.MIMETYPE, ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.DISPLAY_NAME }, ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME + "=?", new String[] { ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, "Eric" }, null); while (ncursor.moveToNext()) { builder.append (ncursor.getString(ncursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)) + lineSep); String lookupKey = ncursor.getString (ncursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); Cursor dcursor = null; try { dcursor = content.query (ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.Data.DATA1 }, ContactsContract.Contacts.LOOKUP_KEY + "=?", new String[] { lookupKey }, null); while (dcursor.moveToNext()) { String type = dcursor.getString (ncursor.getColumnIndex(ContactsContract.Data.MIMETYPE)); if (type.equals (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) builder.append ("Phone: " + dcursor.getString(dcursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) + lineSep); else if (type.equals (ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) builder.append ("Email: " + dcursor.getString(dcursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA1)) + lineSep); } builder.append(lineSep); } finally { if (dcursor != null) dcursor.close(); } } } finally { if (ncursor != null) ncursor.close(); } t.setText(builder.toString());
  26. var builder = new StringBuilder(); var abook = new AddressBook(this);

    foreach (Contact c in abook.Where (c => c.FirstName == "Eric" && c.Phones.Any())) { builder.AppendLine (c.DisplayName); foreach (Phone p in c.Phones) builder.AppendLine (String.Format ("{0}: {1}", p.Label, p.Number)); builder.AppendLine(); } Console.WriteLine (builder.ToString());
  27. StringBuilder builder = new StringBuilder(); String lineSep = System.getProperty("line.separator"); ContentResolver

    content = getContentResolver(); Cursor ncursor = null; try { ncursor = content.query (ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data.MIMETYPE, ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.DISPLAY_NAME }, ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME + "=?", new String[] { ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, "Eric" }, null); while (ncursor.moveToNext()) { builder.append (ncursor.getString(ncursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)) + lineSep); String lookupKey = ncursor.getString (ncursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); Cursor dcursor = null; try { dcursor = content.query (ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.Data.DATA1 }, ContactsContract.Contacts.LOOKUP_KEY + "=?", new String[] { lookupKey }, null); while (dcursor.moveToNext()) { String type = dcursor.getString (ncursor.getColumnIndex(ContactsContract.Data.MIMETYPE)); if (type.equals (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) builder.append ("Phone: " + dcursor.getString(dcursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) + lineSep); else if (type.equals (ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) builder.append ("Email: " + dcursor.getString(dcursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA1)) + lineSep); } builder.append(lineSep); } finally { if (dcursor != null) dcursor.close(); } } } finally { if (ncursor != null) ncursor.close(); } t.setText(builder.toString()); Manually in Java
  28. var builder = new StringBuilder(); var abook = new AddressBook(this);

    foreach (Contact c in abook.Where (c => c.FirstName == "Eric" && c.Phones.Any())) { builder.AppendLine (c.DisplayName); foreach (Phone p in c.Phones) builder.AppendLine (String.Format ("{0}: {1}", p.Label, p.Number)); builder.AppendLine(); } Console.WriteLine (builder.ToString()); Xamarin.Mobile for Android
  29. var builder = new StringBuilder(); var abook = new AddressBook();

    foreach (Contact c in abook.Where (c => c.FirstName == "Eric" && c.Phones.Any())) { builder.AppendLine (c.DisplayName); foreach (Phone p in c.Phones) builder.AppendLine (String.Format ("{0}: {1}", p.Label, p.Number)); builder.AppendLine(); } Console.WriteLine (builder.ToString()); Xamarin.Mobile for iOS
  30. var builder = new StringBuilder(); var abook = new AddressBook();

    foreach (Contact c in abook.Where (c => c.FirstName == "Eric" && c.Phones.Any())) { builder.AppendLine (c.DisplayName); foreach (Phone p in c.Phones) builder.AppendLine (String.Format ("{0}: {1}", p.Label, p.Number)); builder.AppendLine(); } Console.WriteLine (builder.ToString()); Xamarin.Mobile for Windows Phone 7.1
  31. MonoCross • MVC framework where Model and Controller are shared

    • Open Source (MIT License) • Views are native to the individual platform • www.monocross.net
  32. MVVMCross • MonoCross for MVVM pattern • Open Source (MS-PL)

    • Separation of Concerns • Designability/Testability • Cross-platform code re-use • github.com/slodge/MvvmCross