Monotouch – Tips and Tricks (Part 2)
This is the second part of my “Monotouch – Tips and Tricks” series. I will write about the following topics:
- How to create reminders using NSNotifications + use of my UIAlertHelper class.
- How to simulate reminders/alerts using NSNotifications when the application has already been killed. (handling it in the FinishedLaunching method)
A cool feature of the Fusonic EventGuide application is the ability to star your favourite events/gigs. All starred gigs are not only available on your personal running-order, you will also get a notification shortly before the event starts so that you don’t miss your favourite bands. So I needed a solution to show notifications some minutes before the gig starts and to allow the user to jump directly to the event info page (alert action buttons).
Do not try using System.Threading.Timer
My first idea was to use the System.Threading.Timer class where I’d register a new timer with a callback. Unfortunately this will not work, because as soon as your application is sent to background (e.x. through an incoming call or just because the user presses the home button), your application-process is send to sleep by the IOS-Kernel and NONE of your code will ever execute, including your timers. Obviously this would also not work if the app is not running at all.
The Solution: Schedule your Notifications using the Notification APIs.
Fortunately IOS does provide you some APIs which allows you to schedule notifications. Your notifications will be triggered when your application is in foreground, in background and even when it has already been killed.
These APIs are published through the UILocalNotification class and the UIApplication.SharedApplication.ScheduleNotification(…) method.
So first of all we will create a new notification:
void CreateNotification()
{
DateTime fireDate = DateTime.UtcNow.Add(TimeSpan.FromSeconds(30));
UILocalNotification alert = new UILocalNotification();
alert.TimeZone = NSTimeZone.LocalTimeZone;
alert.FireDate = fireDate.ToNSDate();
alert.RepeatInterval = 0;
alert.AlertBody = string.Format("This notification is scheduled for {0}", firedate.toString());
alert.AlertAction = "Click me"; // This will create a button which will launch your application
}
The previous code creates a notification which will trigger in 30 seconds. We can also add an additional userdata dictionary which allows us to attach metadata to the notification which can be retrieved when the notification triggers:
var keys = new object[] { "yourKey" };
var objects = new object[] { "yourKeyValue" };
var userInfo = NSDictionary.FromObjectsAndKeys(objects, keys);
alert.UserInfo = userInfo;
Now we will schedule the notification with this code:
UIApplication.SharedApplication.ScheduleLocalNotification(alert);
Finally we need some notification handling code in the UIApplicationDelegate class. Open your AppDelegate class (usually Main.cs) and implement the following override:
public override void ReceivedLocalNotification (UIApplication application, UILocalNotification notification)
{
Console.WriteLine(notification);
}
If you run this code and keep your application in foreground, you will see a console output in approximately 30 seconds. If you put your application in background, you will see a popup notification. That`s just because IOs will not show the UI-Alert dialog if your app is already in foreground – you have to handle this scenario yourself.
In practice there are 3 different scenarios you need to handle:
1) Your application is in foreground
IOs will not show any notification dialog for you but it will call the ReceivedLocalNotification override though. If you want to show an UIAlert dialog in this scenario, you have to do this yourself by writing this code:
public override void ReceivedLocalNotification (UIApplication application, UILocalNotification notification)
{
// Check if the application is in foreground.
if(application.ApplicationState == UIApplicationState.Active)
{
UIAlertHelper.ShowAlert("The title"
"the notification body",
"label of the close button", new ButtonAction("MyAction", () => MyActionCallback));
}
}
private void MyActionCallback()
{
Console.WriteLine("the user has clicked the button 'MyAction");
}
This code uses my UIAlertHelper class which you can find here https://gist.github.com/1075682. It’s just one of these simple helper classes which provides you an easy to use API for showing alerts with buttons. The class will handle the reference tracking and alert queue for you, so you don’t have to worry about keeping a reference to the actual dialog or handling an alert queue. In a nutshell: It’s making using UIAlerts much easier.
2) Your application is in background
If your application is in background, IOs will show a notification dialog with your text and two buttons: One dismiss/cancel button and one action-button. If the user touches the cancel-button, the dialog will disappear and the ReceivedLocalNotification method will not be called. If the user touches the action-button (“Click me”), IOs will invoke the ReceivedLocalNotification method for you.
This time the application.ApplicationState property value is Background. Because the user has already touched the action button in the dialog, we can directly redirect him to the action method by calling MyActionCallback():
public override void ReceivedLocalNotification (UIApplication application, UILocalNotification notification)
{
// Check if the application is in foreground.
if(application.ApplicationState == UIApplicationState.Active)
{
UIAlertHelper.ShowAlert("The title"
"the notification body",
"label of the close button", new ButtonAction("MyAction", () => MyActionCallback));
}
// Your application is in background and the user has pressed the action button
else
{
MyActionCallback();
}
}
private void MyActionCallback()
{
Console.WriteLine("the user has clicked the button 'MyAction");
}
3) Your application is not in memory / has already been killed
If your application is not running at all, IOs will show a notification dialog with your text and two buttons: One dismiss/cancel button and one action-button. If the user touches the cancel-button, the dialog will disappear and your application will not be started. If the user touches the action-button (“Click me”), IOs will start your application with options which you can handle this way:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
UILocalNotification startupNotification = null;
// Check if the application has been started with options
if(options != null)
{
// Try get the startup notification:
startupNotification = options.ValueForKey(UIApplication.LaunchOptionsLocalNotificationKey) as UILocalNotification;
}
window.AddSubview(navigationController.View);
window.MakeKeyAndVisible ();
BeginInvokeOnMainThread(() => {
InitApplication(startupNotification);
});
return true;
}
private void InitApplication(UILocalNotification startupNotification)
{
if(startupNotification != null)
{
MyActionCallback();
}
}
private void MyActionCallback()
{
Console.WriteLine("the user has clicked the button "MyAction");
}
Testing of scenario 3 => Your application is not running
Testing scenario 1 and 2 is not a problem, but simulating a proper application shutdown and wakeup with notifications takes some time and you probably want some easy and fast way to test your code.
The most simple approach I know is to create a dummy UILocalNotification object in the FinishedLaunching method and pass this to your InitApplication method. You can enable/disable this by using comments or compiler directives.
Example:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
UILocalNotification startupNotification = null;
if(options != null)
{
startupNotification = options.ValueForKey(UIApplication.LaunchOptionsLocalNotificationKey) as UILocalNotification;
}
// Comment/Uncomment the following line to enable/disable the dummy notification
startupNotification = GetSimulatedNotification();
window.AddSubview(navigationController.View);
window.MakeKeyAndVisible ();
BeginInvokeOnMainThread(() => {
InitApplication(startupNotification);
});
return true;
}
public static UILocalNotification GetSimulatedNotification()
{
DateTime fireDate = DateTime.UtcNow.Add(TimeSpan.FromSeconds(30));
UILocalNotification alert = new UILocalNotification();
alert.TimeZone = NSTimeZone.LocalTimeZone;
alert.FireDate = fireDate.ToNSDate();
var keys = new object[] { "yourKey" };
var objects = new object[] { "yourKeyValue" };
var userInfo = NSDictionary.FromObjectsAndKeys(objects, keys);
alert.UserInfo = userInfo;
return alert;
}
I hope that you enjoyed reading my blog-post and that I could help you with my infos.
In part 3 I will write about some of the following topics:
- Increase user experience by using UI-Toasts for action-feedback.
- Making UIWebViews transparent
- Buttons with image scaling


[...] hope you enjoyed reading this first part of my monotouch blog series. In Part-2 of my blog-series I will write [...]
[...] Monotouch – Tips and Tricks (Part 2) – Monotouch – Tips and Tricks (Part [...]