級別: ★★☆☆☆
標籤:「iOS 驗證碼後臺倒計時」「NSTimer後臺運行」「iOS 定時器後臺運行」
做者: Xs·H
審校: QiShare團隊php
短信驗證碼登陸在app中十分常見,相對於帳號+密碼的登陸方式,短信驗證碼登陸既免去了用戶記憶密碼的繁瑣,也在很大程度上下降了密碼泄露的風險。可是,對app運營方來講,每發一條短信就會支付相對應的短信費,因此,爲了防止惡意頻繁訪問,在設計發送短信驗證碼接口時會加上限制邏輯。好比,針對同一手機號,接口會控制在120秒內不可重複發送短信驗證碼。爲了優化用戶體驗,app每每會作出對應的邏輯控制:在點擊「獲取驗證碼」按鈕後將按鈕設置成不可點擊狀態,並開始120秒的倒計時,倒計時結束後恢復按鈕爲可點擊狀態。git
按照上述需求,實現一個倒計時按鈕並不難,使用NSTimer就能夠。但因爲在app進入後臺時NSTimer會被暫停,直到app進入前臺,NSTimer纔會繼續工做(若是NSTimer還沒被釋放的話),這就會致使按鈕上的倒計時會缺失app在後臺的那段時間。因此,開發者要想辦法補上這段時間。github
如何補上這段時間,就是本文探討的內容。在此以前,先經過下圖看一下短信驗證碼倒計時場景。算法
要補上app進入後臺的時間,有兩個思路:bash
經過監聽UIApplicationDidEnterBackgroundNotification
和UIApplicationWillEnterForegroundNotification
能夠獲取到app進入後臺和回到前臺的時間戳,將這兩個時間戳取差,就是app在後臺的時間,而後用這個時間對計時器的時間進行補償就能實現需求。代碼以下:微信
#pragma mark - Notifications
- (void)applicationDidEnterBackground:(id)sender {
NSLog(@"%s", __func__);
_didEnterBackgroundTimestamp = [[NSDate date] timeIntervalSince1970];
}
- (void)applicationWillEnterForeground:(id)sender {
NSLog(@"%s", __func__);
NSTimeInterval willEnterForegroundTimestamp = [[NSDate date] timeIntervalSince1970];
NSInteger onBackgroundSeconds = floor((_didEnterBackgroundTimestamp == 0)? 0: (willEnterForegroundTimestamp - _didEnterBackgroundTimestamp));
_currentInteger -= onBackgroundSeconds;
}
複製代碼
didEnterBackgroundTimestamp
是全局變量,用來記錄app進入後臺時的時間戳;onBackgroundSeconds
表示app在後臺的時間(秒數)。用三目運算排除app直接啓動時的狀況;- 用floor()函數對Double類型的時間差進行向下取整,是爲了保證倒計時不會提早結束。
首先,Apple容許開發者向系統申請後臺運行權限,好比使用「位置服務」的「高德地圖」、「滴滴出行」等app和使用「音頻服務」的「QQ音樂」、「網易雲音樂」等app。但若是申請了權限,就得保證app提供相應的服務,否則在上線App Store時會被拒絕。因此,對於簡單的倒計時場景,不考慮使用這種方式。 好在,iOS向開發者提供了臨時借用後臺運行權限的API,以向app提供最多180秒的後臺運行權限。說到「借用」,就得有個「借條」(憑證),還得有借有還。 經過監聽UIApplicationDidEnterBackgroundNotification
,在app進入後臺時,調用API向系統借用180秒的後臺運行權限,並保留借用憑證。在借用時間即將到期時或者作完須要作的事情後調用API將後臺權限還給系統,並將借用憑證標識爲失效狀態。具體代碼以下。app
- (void)stopCountdown {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
[self endBackgroundTask];
[self setEnabled:YES];
[_timer invalidate];
_timer = nil;
}
#pragma mark - Private functions
- (void)startBackgroundTask {
__weak typeof(self) weakSelf = self;
_backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[weakSelf endBackgroundTask];
}];
}
- (void)endBackgroundTask {
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId];
_backgroundTaskId = UIBackgroundTaskInvalid;
}
#pragma mark - Notifications
- (void)applicationDidEnterBackground:(id)sender {
NSLog(@"%s", __func__);
[self startBackgroundTask];
}
複製代碼
backgroundTaskId
是全局變量,表示向系統借用後臺權限所產生的憑證;beginBackgroundTaskWithExpirationHandler
是借用的後臺權限將到期時會觸發的block,在裏面要作「還權限」的操做;- 在定時器倒計時結束後,會調用
stopCountdown
方法,在裏面提早執行「還權限」的操做。
以上是做者實現短信驗證碼倒計時按鈕經常使用到的兩種方式。爲了方便複用,做者將倒計時功能封裝進了按鈕中,工程代碼可從QiCountdownButton中獲取。函數
小編微信:可加並拉入《QiShare技術交流羣》。優化
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)ui
推薦文章:
iOS 環境變量配置
iOS 中處理定時任務的經常使用方法
算法小專欄:貪心算法
iOS 快速實現分頁界面的搭建
iOS 中的界面旋轉
奇舞週刊