Supporting iOS 6.1 and iOS 7 (Xamarin.iOS)

As a developer it’s always way more fun to play with the new “toys” a new framework or OS provides. The issue we usually run into is at what point are we able to start using the new functionality in applications we develop. With Apple and iOS, the adoption rate of new versions is so high and so quick that you only really need to worry about supporting the 2 latest versions. With that said, if you’re starting something brand new you’ll probably just want to build against the newest version, but if you’ve got an existing application that you want to function in both versions you’ll need to do some work.

1st: If you don’t have Xcode 5, copy the iPhoneOS6.1.sdk and the iPhoneSimulator6.1.sdk folders from your existing Xcode 4.6.3 installation somewhere else so you can still dev for iOS 6. The simulator SDK can also be downloaded after the upgrade, but this is faster since you already have it on your machine. The SDKs are located under /Applications/Xcode.app/Contents/Developer/Platforms. In Finder choose Go => Go to Folder to get to the desired directories. Copy both of these folders somewhere else for use later.

  • iPhoneOS6.1.sdk is located here /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
  • iPhoneSimulator6.1.sdk is located here /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/

NOTE: If you’ve already upgraded to Xcode 5 you’ll need to download the Xcode 4.6.3 installer from the Apple Developer site located here. Once downloaded, open the .dmg file and right-click on the Xcode icon, choose “Show Package Contents” and then follow the same directory structure to get to the SDK folders.

2nd: In order to support iOS 7 make sure you are upgraded to OS X 10.8.5 and Xcode 5.

3rd: With Xcode 5 installed copy the iPhoneOS6.1.sdk and iPhoneSimulator6.1.sdk folders back to the directories you copied them out of. You should notice 7.0 versions of each SDK now in those directories as well.

4th: In Xamarin Studio under the iOS Build view in your project options, you’ll now notice that you have the ability to specifiy 6.1 as the SDK version as well as 7.0. Under the iOS Application view is the more important Deployment Target property. Set this to 6.1 in order for the application to still be deployable. Otherwise only iOS 7 devices will be able to get it from the app store. Making this change will allow it to be deployable for both versions, but you still have one more thing.

5th & Last: Apple made some drastic changes with how certain properties work, how the NavigationController’s title bar and the iOS status bar look and work, and a bunch of other things. You’ll need to add version specific code to handle/fix these changes. I created a VersionHelper static class to do the comparison logic for me. There are definitely other ways to accomplish this but here it is:

public static class VersionHelper
{
	private static Version _systemVersion;
	public static bool CurrentVersionIsGreaterThanOrEqualTo( Version versionToCompareAgainst )
	{
		if ( _systemVersion == null )
		{
			_systemVersion = new Version( UIDevice.CurrentDevice.SystemVersion );
		}

		return _systemVersion >= versionToCompareAgainst;
	}
}

With that you should be good to go.

Creating an iOS Settings Bundle (Xamarin.iOS)

With the investigation I’ve been doing in building an iOS application using Xamarin, I’ve now gotten to the point where I wanted to put some settings into the iOS Setting app for my application. I found this nice thread that gave the 3 easy steps to set up a settings bundle.

It literally is as simple as written, but there were a couple gotchas that I ran into that I wanted to forward along.

  1. The Settings.bundle folder needs to be in the project root, NOT under the Resources folder (where some examples showed it). I’m not sure if this is a new change or not, but I spent some time banging my head against the wall over this one.
  2. If you do not register default values for your settings they’ll return the default for the data type. (ie. null for String, false for bool, etc….). The DefaultValue you specify in the Root.plist file for a setting is the default value the control will show, NOT the value of the setting. Below is an example of registering default values for settings.
  3. NSUserDefaults userDefaults = NSUserDefaults.StandardUserDefaults;
    NSMutableDictionary appDefaults = new NSMutableDictionary(); 
    appDefaults.SetValueForKey( NSObject.FromObject( true ), new NSString( "BooleanSettingKey" ) );
    userDefaults.RegisterDefaults( appDefaults );
    userDefaults.Synchronize();
    

Accessing the value for a setting is a simple as the following:

bool settingValue = NSUserDefaults.StandardUserDefaults.BoolForKey( "BooleanSettingKey");

One last thing that I found in an example solution here was how to listen in your app for when settings have been changed and wanted to pass it along:

NSObject observer = NSNotificationCenter.DefaultCenter.AddObserver( (NSString)"NSUserDefaultsDidChangeNotification", DefaultsChanged ); 
private void DefaultsChanged( NSNotification obj )
{ 	
// Handle the settings changed 
}

The biggest bummer I found in the iOS Settings Bundle is that everything is statically defined. So if you happen to have a collection of items that you want updated from a server, you’ll have to do this on your own inside your application.

Working with UITableView (Xamarin.iOS)

After setting up my solution, my next step was to figure out how to display a list in iOS with the ability to select an item. In WPF, my first thought would be to utilize the ListBox control, bind its ItemsSource to the underlying data, and define an ItemTemplate for how I want each item to look. Not so simple in iOS. There’s a nice list control called the UITableView that provides support for a number of neat things (indexed list, splitting the items into sections/grouping them, selection, etc…). However, to accomplish the most important part, hooking it up to data, you have to define a data source object that you assign to the .Source property of the UITableView. There are a number of ways to accomplish this, but I went with creating a source that inherits from UITableViewSource. Xamarin has a nice guide that I used for guidance (Working with Tables and Cells).

Coming from WPF and MVVM I wanted to make this source reusable rather than following all the examples that were hardcoded to a specific object type. So I decided to create an ObjectTableSource, and since I’m still in the early stages of development I decided to make use of the built-in styles for the cell appearance rather than making a custom cell. With this in mind I needed to make sure that the objects provided to my table source had specific properties for me to utilize so I created an interface called ISupportTableSourceand used that as the .

public interface ISupportTableSource
{
	string Text { get; }
	string DetailText { get; }
	string ImageUri { get; }
}
public class ObjectTableSource : UITableViewSource

When inheriting from UITableViewSource you must override RowsInSection and GetCell. RowsInSection is exactly what it sounds like, you return how many items are in that section. My current version only supports 1 section so it returns the total number of items. GetCell returns the prepared UITableViewCell. The UITableView supports virtualization of its cell controls so in order to get the cell you need to call the DequeueReusableCellmethod on the table view. In versions earlier than iOS 6 this will return null if the cell hasn’t been created yet. In iOS 6 and later you can choose to register a cell type with the UITableView and that will make it so a cell is always returned. However, going this path means that you can’t specify which of the 4 build in styles to use (since it is specified in the constructor only), so I refrained from registering the cell type and handle null. When preparing the cell I also loaded any images on a background thread so the UI is still responsive, but I’ll cover that in another post.

public override int RowsInSection( UITableView tableview, int section )
{
	return _items.Count;
}

public override UITableViewCell GetCell( UITableView tableView, NSIndexPath indexPath )
{
	// if there are no cells to reuse, create a new one
	UITableViewCell cell = tableView.DequeueReusableCell( CellId )
			       ?? new UITableViewCell( _desiredCellStyle, CellId );

	ISupportTableSource item = _items[indexPath.Row];
	if ( !String.IsNullOrEmpty( item.Text ) )
	{
		cell.TextLabel.Text = item.Text;
	}
	if ( !String.IsNullOrEmpty( item.DetailText ) )
	{
		cell.DetailTextLabel.Text = item.DetailText;
	}
	if ( !String.IsNullOrEmpty( item.ImageUri ) )
	{
		cell.ImageView.ShowLoadingAnimation();
		LoadImageAsync( cell, item.ImageUri );
	}
	return cell;
}

The remaining thing for making this usable was to provide a way to notify when an item has been selected. There isn’t any event on the UITableViewSource like I expected, instead I needed to override the RowSelectedmethod and fire my own event providing the object found at the selected row.

public override void RowSelected( UITableView tableView, NSIndexPath indexPath )
{
	ISupportTableSource selectedItem = _items[indexPath.Row];

	// normal iOS behaviour is to remove the blue highlight
	tableView.DeselectRow( indexPath, true );

	OnItemSelected( selectedItem );
}

Beginning Xamarin and Xamarin.iOS

I’ve recently started delving into using Xamarin and Xamarin.iOS to get an understanding of its capabilities and see what I could do with it. After my first little app, I have to say it is really impressive what the people at Xamarin have done!

I’m coming at this from years of experience in C# and WPF/Silverlight/XAML and I wanted to describe my initial findings. For this post I plan to cover the general setup.

Installation

My goal was to have an iPad application that does something similar to a Master-Detail set of views where I could display a collection of images. Because of this I wanted to get a grasp on both Xamarin Studio and the Visual Studio integration so I installed Xamarin for Windows (on my primary dev machine) and Xamarin for OS X (on a Mac Mini we have at our office) from here. NOTE: On Windows 8 run the Xamarin installer as Administrator otherwise it will error out near the end. The installation took a while because it downloaded everything that I needed to develop for iOS (and for Android since I wanted to look into that in the future too.), but once everything was installed I was able to start developing instantly.

The installation guides for Xamarin.iOS, located here, provided excellent instruction for hooking up Visual Studio 2012 to remote debug on the Mac Mini (Section: 6.2. Connecting to the Mac Build Host), and the Xamarin services that were installed made it so that I found and connected to the Mac immediately. On another note, Synergy is an amazing tool to use to share your keyboard and mouse between the 2 devices. You need to make sure both machines are on the same network though in order for it to work (quickly at least).

Solution Setup

With Xamarin installed, I decided to get my feet wet by following Xamarin’s Hello, iPhone guide. (They’ve done a very nice job with their guides covering a nice range of topics.) For someone who has never developed in Xcode (and is pretty much a Mac beginner) this provided a nice tutorial of the tool.

With a general idea of how to get started, I created my solution in VS 2012 and on the Mac I used “Finder” to connect to my machine and open up the solution in Xamarin Studio. I’ve found that if I want to use Xcode’s Interface Builder to design my UI I need to add the iPad View Controller via Xamarin Studio, since adding it in Visual Studio didn’t create the .xib file.

My next step was to set up a core library, since I desire to try Xamarin’s Android functionality in the future, to enable code reuse. Xamarin is currently developing support for referencing Portable Class Libraries (PCLs), but until they’ve got that functioning we have to go more manual routes. I created the PCL to hold my core files (model objects primarily), but went the route of linking to all those files in the iOS project. Once I work on the Android counterpart I’ll be able to update with whether I think it’s the right way to go.

EDIT: With the release of Xamarin.iOS 7.0.1, they’ve apparently fixed the PCL build issue I was running into. So I was able to remove the links to all the files and reference the PCL library instead!

Debugging

It is extremely nice to be able to dev and debug in VS 2012 while connected to the iOS simulator on the Mac. When running into exceptions being thrown, I found that, if it wasn’t immediately apparent as to what the exception was caused by, debugging from Xamarin Studio on the Mac provides better exception information.

I’ll go into more detail on discoveries I ran into in other posts, but overall the development process using Xamarin and Xamarin.iOS has been very interesting and enjoyable. I would definitely recommend it.