最近在做番茄鐘的功能种呐。首先簡(jiǎn)單介紹一下番茄鐘吧形入,就是25分鐘工作番茄工作法乞榨。先說(shuō)一下** 番茄工作法 **:
番茄工作法是簡(jiǎn)單易行的時(shí)間管理方法熔酷,是由弗朗西斯科·西里洛于1992年創(chuàng)立的一種相對(duì)于GTD更微觀的時(shí)間管理方法孤紧。
使用番茄工作法,選擇一個(gè)待完成的任務(wù)拒秘,將番茄時(shí)間設(shè)為25分鐘号显,專注工作,中途不允許做任何與該任務(wù)無(wú)關(guān)的事躺酒,直到番茄時(shí)鐘響起押蚤,然后在紙上畫一個(gè)X短暫休息一下(5分鐘就行),每4個(gè)番茄時(shí)段多休息一會(huì)兒羹应。
番茄工作法極大地提高了工作的效率揽碘,還會(huì)有意想不到的成就感。
那么功能就相當(dāng)于一個(gè)25分鐘的鬧鐘,可以播放背景音樂雳刺,到點(diǎn)給用戶提醒劫灶。
功能聽起來(lái)很簡(jiǎn)單是不是?其實(shí)挺多坑的掖桦。
開發(fā)過程中遇到了2個(gè)問題本昏。
因?yàn)榉宴娛?5分鐘,那么當(dāng)用戶開啟番茄鐘后很可能在中途就將APP切換到了后臺(tái)枪汪,那么幾分鐘程序就會(huì)被系統(tǒng)kill掉涌穆。
當(dāng)用戶開啟番茄鐘的背景音樂時(shí),APP切換到后臺(tái)或者鎖屏狀態(tài)時(shí)雀久,音樂都會(huì)立即停止播放宿稀。
OK,下面我們一步一步來(lái)分析并解決這兩個(gè)問題赖捌。
** 首先要理解iOS系統(tǒng)的后臺(tái)機(jī)制 **
我們都知道祝沸,蘋果對(duì)APP占用硬件資源管的很嚴(yán),更不要說(shuō)應(yīng)用后臺(tái)時(shí)候的資源占用了巡蘸。正常情況下,使用應(yīng)用時(shí)擂送,APP從硬盤加載到內(nèi)存悦荒,開始工作;當(dāng)用戶按下home鍵嘹吨,APP便被掛起搬味,依然駐留在內(nèi)存中,這種狀態(tài)下蟀拷,不調(diào)用蘋果已開放的幾種后臺(tái)方法碰纬,程序便不會(huì)運(yùn)行;如果在這個(gè)時(shí)候问芬,使程序繼續(xù)運(yùn)行悦析,則為后臺(tái)狀態(tài);如果當(dāng)前內(nèi)存將要不夠用時(shí)此衅,系統(tǒng)會(huì)自動(dòng)把之前掛起狀態(tài)下的APP請(qǐng)出內(nèi)存强戴。所以我們看到,有些時(shí)候打開APP時(shí)挡鞍,還是上次退出時(shí)的那個(gè)頁(yè)面那些數(shù)據(jù)骑歹,有時(shí)則是重新從閃屏進(jìn)入。
iOS系統(tǒng)后臺(tái)機(jī)制大概可以分為5種狀態(tài)
Not Running:APP沒有啟動(dòng)墨微,也沒有后臺(tái)運(yùn)行道媚。
Active:用戶正在使用APP,比如說(shuō)我們聊微信看網(wǎng)頁(yè)的時(shí)候,APP就處于Active狀態(tài)最域。
Inactive:這是一個(gè)過渡的狀態(tài)谴分,APP雖然打開了,但是用戶沒有跟APP有任何互動(dòng)操作羡宙。
Background:APP在后臺(tái)運(yùn)行狸剃,微信會(huì)在沒有打開的時(shí)候接收消息。
Suspended:APP雖然在后臺(tái)運(yùn)行狗热,但是處于休眠狀態(tài)钞馁,只占用一點(diǎn)內(nèi)存。
** 那么我需要的是Background模式匿刮。即APP在后臺(tái)運(yùn)行同時(shí)保持程序active的狀態(tài) **
首先去xCode里面設(shè)置僧凰。到info.plist中添加以下信息:
image
然后到Capabilities里面打開后臺(tái)模式,并根據(jù)項(xiàng)目的要求勾選對(duì)應(yīng)的功能熟丸。我這里只需要保持后臺(tái)運(yùn)行并且播放背景音樂及通知功能训措。所以就勾選了第一個(gè)和最后一個(gè)
image
以上這兩步是告訴系統(tǒng)我這個(gè)APP支持后臺(tái)模式,對(duì)應(yīng)的環(huán)境為音頻環(huán)境光羞。
可是到這一步绩鸣,APP還是不能長(zhǎng)時(shí)間運(yùn)行到后臺(tái)。
為什么纱兑?我們思考一下呀闻。我們讓程序支持了后臺(tái)運(yùn)行的模式。那么我們是不是還需要系統(tǒng)知道我們的程序要在后臺(tái)運(yùn)行多久呢潜慎?我們需要告訴系統(tǒng)我們期望APP在后臺(tái)存活的時(shí)間捡多。
首先聲明一個(gè)屬性
@property(nonatomic,assign)UIBackgroundTaskIdentifier bgTask;
在進(jìn)入后臺(tái)的時(shí)候通過AppDelegate里面的方法:
-(void)applicationDidEnterBackground:(UIApplication*)application{[selfcomeToBackgroundMode];}-(void)comeToBackgroundMode{//初始化一個(gè)后臺(tái)任務(wù)BackgroundTask,這個(gè)后臺(tái)任務(wù)的作用就是告訴系統(tǒng)當(dāng)前app在后臺(tái)有任務(wù)處理铐炫,需要時(shí)間UIApplication*app=[UIApplication sharedApplication];self.bgTask=[app beginBackgroundTaskWithExpirationHandler:^{[app endBackgroundTask:self.bgTask];self.bgTask=UIBackgroundTaskInvalid;}];//開啟定時(shí)器 不斷向系統(tǒng)請(qǐng)求后臺(tái)任務(wù)執(zhí)行的時(shí)間self.timer=[NSTimer scheduledTimerWithTimeInterval:25.0target:selfselector:@selector(applyForMoreTime)userInfo:nil repeats:YES];[self.timer fire];}-(void)applyForMoreTime{//如果系統(tǒng)給的剩余時(shí)間小于60秒 就終止當(dāng)前的后臺(tái)任務(wù)垒手,再重新初始化一個(gè)后臺(tái)任務(wù),重新讓系統(tǒng)分配時(shí)間倒信,這樣一直循環(huán)下去科贬,保持APP在后臺(tái)一直處于active狀態(tài)。if([UIApplication sharedApplication].backgroundTimeRemaining<60){[[UIApplication sharedApplication]endBackgroundTask:self.bgTask];self.bgTask=[[UIApplication sharedApplication]beginBackgroundTaskWithExpirationHandler:^{[[UIApplication sharedApplication]endBackgroundTask:self.bgTask];self.bgTask=UIBackgroundTaskInvalid;}];}}
現(xiàn)在就可以讓我們的APP一直運(yùn)行在后臺(tái)啦鳖悠!總結(jié)下來(lái)的思路就是:通過一個(gè)后臺(tái)任務(wù)(這個(gè)任務(wù)我們也不用管唆迁,它存在的意義就是和系統(tǒng)去請(qǐng)求后臺(tái)運(yùn)行的一定的時(shí)間),這個(gè)時(shí)間我們不知道也不用去管竞穷,我們可以通過該時(shí)間還剩下多少判斷是否繼續(xù)請(qǐng)求時(shí)間唐责,如此循環(huán),我們就可以不斷的請(qǐng)求時(shí)間來(lái)保持我們的app一直運(yùn)行在后臺(tái)瘾带。
接下來(lái)解決音樂在后臺(tái)模式(切換到后臺(tái)或者鎖屏狀態(tài))下停止播放的問題鼠哥。
其實(shí)很簡(jiǎn)單。
//設(shè)置后臺(tái)模式和鎖屏模式下依然能夠播放[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];[[AVAudioSession sharedInstance]setActive:YES error:nil];//初始化播放器和兩個(gè)音頻(一個(gè)有聲 一個(gè)無(wú)聲)NSURL*urlSound=[[NSURL alloc]initWithString:[[NSBundle mainBundle]pathForResource:@"pomodoSound"ofType:@"m4a"]];playerSound=[[AVAudioPlayer alloc]initWithContentsOfURL:urlSound error:&playerError];NSURL*urlNoSound=[[NSURL alloc]initWithString:[[NSBundle mainBundle]pathForResource:@"backSound"ofType:@"mp3"]];playerNoSound=[[AVAudioPlayer alloc]initWithContentsOfURL:urlNoSound error:&playerError];playerSound.numberOfLoops=-1;playerNoSound.numberOfLoops=-1;player=playerSound;[player play];
下面解釋一下AVAudioSession的一些設(shè)置參數(shù)
NSString *const AVAudioSessionCategoryAmbient;
靜音模式或者鎖屏下不再播放音樂,和其他app聲音混合朴恳。
NSString *const AVAudioSessionCategorySoloAmbient;
默認(rèn)模式抄罕,靜音模式或者鎖屏下不再播放音樂,不和其他app聲音混合于颖。
NSString *const AVAudioSessionCategoryPlayback;
表示對(duì)于用戶切換靜音模式或者鎖屏 都不理睬呆贿,繼續(xù)播放音樂。并且不播放來(lái)自其他app的音樂
NSString *const AVAudioSessionCategoryRecord;
不播放音樂森渐,鎖屏狀態(tài)繼續(xù)錄音
NSString *const AVAudioSessionCategoryPlayAndRecord;
播放音樂做入,并錄音
Demo地址:https://github.com/BoYangZuo/KeepAppActive
作者:flightlessBirdT
鏈接:http://www.reibang.com/p/d62c6d3ae8ff
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)同衣,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處竟块。