一:了解multitasking
background apps(可以在后台运行的任务):
1:play audio
2:get location
3:voip stream
4:request time to finish
5: create notifications
二:多任务生命周期
1:程序加载成功
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
2:程序将要失去活跃状态
- (void)applicationWillResignActive:(UIApplication *)application
3:程序已经进入后台运行
- (void)applicationDidEnterBackground:(UIApplication *)application
4:程序将要进入前台运行
- (void)applicationWillEnterForeground:(UIApplication *)application
5:程序进入活跃状态
- (void)applicationDidBecomeActive:(UIApplication *)application
6:程序退出
- (void)applicationWillTerminate:(UIApplication *)application
从启动到转入后台,从后台转入前台,退出,生命周期函数调用顺序
1->5->2->3->4->5->6
三:转入后台后请求一段时间完成操作
UIBackgroundTaskIdentifier backgroundTask; - (void)applicationDidEnterBackground:(UIApplication *)application { // tell the OS you're about to begin a background task that may need time to finish backgroundTask = [application beginBackgroundTaskWithExpirationHandler: ^{ // 如果超时这个block将被调用 dispatch_async(dispatch_get_main_queue(), ^{ if (backgroundTask != UIBackgroundTaskInvalid) { // do whatever needs to be done [application endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; } }); }]; // Start the long-running task dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do the work! [NSThread sleepForTimeInterval:5]; NSLog(@"Time remaining: %f",[application backgroundTimeRemaining]); [NSThread sleepForTimeInterval:5]; NSLog(@"Time remaining: %f",[application backgroundTimeRemaining]); [NSThread sleepForTimeInterval:5]; NSLog(@"Time remaining: %f",[application backgroundTimeRemaining]); // done! // call endBackgroundTask - should be executed back on // main thread dispatch_async(dispatch_get_main_queue(), ^{ if (backgroundTask != UIBackgroundTaskInvalid) { // if you don't call endBackgroundTask, the OS will exit your app. [application endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; } }); }); NSLog(@"Reached the end of ApplicationDidEnterBackground - I'm done!"); }
四:本地消息
1:创建一个本地消息
-(IBAction) scheduleNotification { UILocalNotification *local = [[UILocalNotification alloc] init]; // create date/time information local.fireDate = [NSDate dateWithTimeIntervalSinceNow:15]; local.timeZone = [NSTimeZone defaultTimeZone]; // set notification details local.alertBody = @"Missing you already!"; local.alertAction = @"View"; // set the badge on the app icon local.applicationIconBadgeNumber = 1; // Gather any custom data you need to save with the notification NSDictionary *customInfo = [NSDictionary dictionaryWithObject:@"ABCD1234" forKey:@"yourKey"]; local.userInfo = customInfo; // Schedule it! [[UIApplication sharedApplication] scheduleLocalNotification:local]; [local release]; }
2:delegate 处理方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // Add the view controller's view to the window and display. [window addSubview:viewController.view]; [window makeKeyAndVisible]; //程序启动是检查是否有UILocalNotification,如果有跳出提示框 // reset badge application.applicationIconBadgeNumber = 0; // If the app was closed, and we launched from the notification UILocalNotification *local = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; if (local) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"You came back! (App was closed)" message:@"Nice to see you again!" delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil]; [alert show]; [alert release]; } return YES; }
//如果程序完全退出,此方法不会被调用,而是先调用didFinishLaunchingWithOptions把程序启动起来。如果该程序在后台运行收到消息时直接调用该方法 - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)local { // reset badge number application.applicationIconBadgeNumber = 0; if (local) { // get custom info from dictionary NSString *customInfo = [local.userInfo objectForKey:@"yourKey"]; // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"You came back! (App was running)" message:customInfo delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil]; [alert show]; [alert release]; } }
五:后台播放音乐
1:读取文件
- (void)viewDidLoad { [super viewDidLoad]; self.playPauseButton.titleLabel.text == @"play"; // grab the path to the caf file NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: @"Rainstorm" ofType: @"mp3"]; NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath]; // create a new AVAudioPlayer initialized with the URL to the file AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil]; [fileURL release]; // set our ivar equal to the new player self.player = newPlayer; [newPlayer release]; // preloads buffers, gets ready to play [player prepareToPlay]; // set delegate so we can get called back when the sound has finished playing [player setDelegate: self]; //重要的两行 // set category of audio [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; // announce that we want to hook up to remote UI events [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; }
2:重写canBecomeFirstResponder 方法,使改view 可以成为第一响应者
-(BOOL) canBecomeFirstResponder { return YES; }
3:显示view时,设置为第一响应者
-(void) viewDidAppear:(BOOL)animated { [self becomeFirstResponder]; }
4:实现remoteControlReceivedWithEvent方法使程序接收 iphone 自动音乐控制事件
-(void) remoteControlReceivedWithEvent:(UIEvent *)event { switch (event.subtype) { case UIEventSubtypeRemoteControlTogglePlayPause: [self playPause]; default: break; } }
5:info.plist 设置,可以设置多种形式
<key>UIBackgroundModes</key> <array> <string>audio</string> </array>
六:NSUserDefaults 问题
如果程序在后台挂起,在转入到前台后不会调用viewDidLoad 方法,所以要在viewDidLoad 方法里面注册UIApplicationWillEnterForegroundNotification ,调用loadSettings
-(void) loadSettings: (NSNotification *) notification { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize]; }
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [self loadSettings:nil]; NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self selector:@selector(loadSettings:) name:UIApplicationWillEnterForegroundNotification object:nil]; [super viewDidLoad]; }
七:去除后台运行inof.list
application dose not run in background 设置为 true