2011年9月24日星期六

Timing Out An Application Due To Inactivity

Timing Out An Application Due To Inactivity:

In the recent months, I have had a few separate applications that required a “timeout”. What I mean by this is, the application should log the user out if they haven’t touched the screen in X number of minutes. There are quite a few uses for this, but the best use is when you have an application that contains sensitive data in a shared environment.


For example, say your company uses iPads to collect feedback from your customers. You would definitely want a timeout on the application in case a non-employee picked up a stray iPad.


The code that I came up with to do this is pretty simple, and I wanted to share it with you as well as walk you through an example of using it.


Overview


Here’s how it works. I have created a subclass of UIApplication called ELCUIApplication. The purpose of extending UIApplication was to overwrite the sendEvent: method. This method gets called every time there’s a touch. The touch could be on a button, text field, or just anywhere inside the window.


Inside of my sendEvent: method, I first call the super method (to ensure that we pass the tap through to do what it’s supposed to do), and then reset an NSTimer. This timer is set to go off after 5 minutes (configurable).


Once the timer does go off (the app times out), I fire off an NSNotification and everyone who subscribes to it will get notified. Pretty simple.


In order to reset the timer (perhaps after the user re-logs-in), you call the resetIdleTimer method of ELCUIApplication.


The main question you might ask is, why not just add a UIGestureRecognizer on the main window. This was my first thought, and after trying it for quite some time, I couldn’t get all of the taps to forward. This resulted in loss of functionality/interaction.


The project is available on github along with a sample project. Make sure you go there and at least download ELCUIApplication.h and ELCUIApplication.m before continuing.


Using Our Custom UIApplication Subclass


Drag ELCUIApplication.h and ELCUIApplication.m into your project. Make sure you check to copy them into your source folder. Now, open up main.m (I’ll bet you have never opened this file on purpose before). Update it to look like this:



#import <UIKit/UIKit.h>

int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, @"ELCUIApplication", nil);
[pool release];
return retVal;
}


The only change we made is, we set the 3rd argument of UIApplicationMain to be an NSString with our classname (ELCUIApplication). This tells the app to start using our UIApplication rather than the super class.


One other thing to note is, in ELCUIApplicaiton.h there is a define called kApplicationTimeoutInMinutes. Change this value to modify the number of minutes until your application times out. By default, it’s set to 5.


That’s all that must be done to have your application start publishing notifications upon timeout. The next thing to do is respond to these notifications by doing something meaningful.


Responding To Timeout Notifications


A good place to respond to the timeout notifications is in your application’s delegate. This might change depending on how you are doing your logout logic, but I generally have some sort of login controller that needs to be presented modally upon timeout. Here is a snippet from the app delegate of the sample project.



- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidTimeout:)
name:kApplicationDidTimeoutNotification object:nil];

return YES;
}

- (void) applicationDidTimeout:(NSNotification *) notif {
LoginViewController *controller = [[[LoginViewController alloc] initWithNibName:@"LoginViewController"
bundle:[NSBundle mainBundle]] autorelease];
[self.viewController presentModalViewController:controller animated:YES];
}


Notice that we add an observer for a notification named kApplicationDidTimeoutNotification. So, whenever the kApplicationDidTimeoutNotification notification fires, our app delegate will call the applicationDidTimeout: method. This method is responsible for displaying the login view controller.


Now, we have “logged the user out”. Once the user logs back in, we must reset the idle timer to ensure that they will be logged out again if they leave the device unattended.


Resetting The Timer


I have created a simple (simulated) login method inside of my login view controller that looks like this:



- (IBAction)login:(id)sender {
[(ELCUIApplication *)[UIApplication sharedApplication] resetIdleTimer];
[self.parentViewController dismissModalViewControllerAnimated:YES];
}


The first line of this method tells the application to reset the timer and the second reveals the interface (the user has logged back in). Obviously, this doesn’t truly simulate a user loggin in/out, but it has been simplified to demonstrate how easy our ELCUIApplication timeout functionality is.


Conclusion


As always, if you have any questions or comments feel free to leave them hear or write them to me on Twitter. Again the source for this tutorial is available on github.


Happy iCoding!


没有评论:

发表评论