版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2022.11.06 星期日 |
前言
Background Modes
我們?cè)诔绦蛑锌倳?huì)用到,包括語(yǔ)音携龟、定位更新均函、后臺(tái)任務(wù)以及遠(yuǎn)程通知等,這個(gè)模塊我們就一起來(lái)學(xué)習(xí)下俄烁。
開(kāi)始
Background Modes
是我們常用的模式,比如語(yǔ)音级野、定位更新页屠、后臺(tái)任務(wù)以及遠(yuǎn)程通知等。Xcode里的后臺(tái)模式如下所示:
在本教程中勺阐,您將創(chuàng)建一個(gè)使用音頻播放、位置更新矛双、關(guān)鍵任務(wù)和后臺(tái)拉取的應(yīng)用程序渊抽,以了解最常見(jiàn)的后臺(tái)模式。本文來(lái)自翻譯议忽。
2010
年懒闷,隨著iOS 4的發(fā)布,蘋果開(kāi)始允許應(yīng)用程序在后臺(tái)工作,并從那時(shí)起不斷發(fā)展和改進(jìn)后臺(tái)模式愤估。iOS
限制使用后臺(tái)操作來(lái)改善用戶體驗(yàn)和延長(zhǎng)電池壽命帮辟。你的應(yīng)用可以在后臺(tái)運(yùn)行特定的情況,包括:播放音頻玩焰,更新位置和從服務(wù)器獲取最新的內(nèi)容由驹。
如果你的任務(wù)不屬于允許的類別,后臺(tái)模式可能不適合你昔园。如果你試圖使用超出其作用范圍的后臺(tái)模式來(lái)操縱系統(tǒng)蔓榄,你可能會(huì)面臨App Store
的拒絕。
在本后臺(tái)模式教程中默刚,你將了解你的應(yīng)用程序可以在后臺(tái)做的四件事:
- Play audio - 播放音頻:允許應(yīng)用程序在后臺(tái)繼續(xù)播放音頻甥郑。
- Receive location updates - 接收位置更新:允許應(yīng)用程序在后臺(tái)接收位置更改。
- Complete finite-length critical tasks - 完成有限長(zhǎng)度的關(guān)鍵任務(wù):允許應(yīng)用程序在移動(dòng)到后臺(tái)后繼續(xù)完成關(guān)鍵任務(wù)荤西。
- Background Fetch - 后臺(tái)獲取:在iOS調(diào)度的時(shí)間表上執(zhí)行后臺(tái)更新澜搅。
在深入研究之前,我們先來(lái)快速瀏覽一下iOS的基本后臺(tái)模式:
- Audio, AirPlay, and Picture in Picture - 音頻邪锌,AirPlay勉躺,和圖片中的圖片:當(dāng)應(yīng)用程序在后臺(tái)時(shí)播放音頻和視頻。
- Location Updates - 位置更新:在后臺(tái)時(shí)繼續(xù)接收位置更新秃流。
- Voice over IP - IP語(yǔ)音:通過(guò)因特網(wǎng)發(fā)送和接收語(yǔ)音赂蕴。
-
External accessory communication - 外部配件通信:通過(guò)
lightning
接口與外部配件通信。 -
Using Bluetooth LE accessories - 使用藍(lán)牙LE配件:在后臺(tái)與藍(lán)牙
LE
配件通信舶胀。 -
Acting as a Bluetooth LE accessory - 充當(dāng)藍(lán)牙LE配件:允許應(yīng)用程序?yàn)榕浼峁┧{(lán)牙
LE
信息概说。 - Background fetch - 后臺(tái)拉取:執(zhí)行數(shù)據(jù)刷新。
- Remote notitifications - 遠(yuǎn)程通知:發(fā)送和接收遠(yuǎn)程通知嚣伐。
- Background processing - 后臺(tái)處理:執(zhí)行較長(zhǎng)的關(guān)鍵進(jìn)程糖赔。
您將向示例應(yīng)用程序添加上述模式中的四種——音頻、定位轩端、后臺(tái)處理和后臺(tái)獲取(audio, location, background processing and background fetches)
放典。如果你只對(duì)其中的一些模式感興趣,可以隨意跳過(guò)基茵,只玩你感興趣的模式奋构。
注意:要獲得完整的效果,您應(yīng)該在真實(shí)的設(shè)備上進(jìn)行操作拱层。在模擬器中弥臼,當(dāng)你忘記一個(gè)步驟時(shí),應(yīng)用程序可能會(huì)在后臺(tái)運(yùn)行根灯。然后當(dāng)你切換到真正的設(shè)備時(shí)径缅,它可能根本無(wú)法工作掺栅。
在您可以在物理設(shè)備上運(yùn)行項(xiàng)目之前,您必須設(shè)置您的development team
纳猪,如下所示:
構(gòu)建并運(yùn)行示例項(xiàng)目來(lái)感受一下Sleepless
氧卧,這是一個(gè)從不休息的應(yīng)用程序,因?yàn)樗诤笈_(tái)做事情氏堤。有四個(gè)tab
—— 每個(gè)覆蓋一個(gè)模式:
您要添加的第一個(gè)capability
是background audio
沙绝。
Playing Audio
在物理設(shè)備上構(gòu)建并運(yùn)行Sleepless
。導(dǎo)航到audio tab
丽猬,播放音樂(lè)宿饱,然后通過(guò)返回主屏幕把應(yīng)用程序放在后臺(tái)。音樂(lè)將停止播放脚祟。
打開(kāi) AudioModel.swift
該應(yīng)用程序利用AVQueuePlayer
對(duì)歌曲進(jìn)行排隊(duì)并按順序播放谬以。模型觀察播放器的currentItem
值以提供視圖的更新。
1. Giving Credit Where Credit Is Due
最初的項(xiàng)目包括來(lái)自incompetech.com的音頻文件由桌,這是一個(gè)流行的免版稅音樂(lè)網(wǎng)站为黎。你可以免費(fèi)使用帶有版權(quán)的音樂(lè)。這三首歌都是Kevin MacLeod
寫的:
“Feelin Good” Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/“Iron Bacon” Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/“What You Want” Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/
謝謝你美妙的音樂(lè)行您,Kevin
!
注意:在蘋果的UIKit文檔中查看Execution States for Apps铭乾,了解更多關(guān)于
active state
和其他的信息。
2. Testing Audio in the Background
為什么當(dāng)應(yīng)用程序進(jìn)入后臺(tái)時(shí)音樂(lè)停止了娃循?好吧炕檩,缺了一個(gè)關(guān)鍵的部分!
大多數(shù)后臺(tái)模式都不能工作,除非你啟用特定的功能捌斧,表明應(yīng)用程序想要在后臺(tái)運(yùn)行代碼笛质。特例是關(guān)鍵任務(wù)完成,任何應(yīng)用程序都可以執(zhí)行捞蚂。
當(dāng)激活時(shí)妇押,音頻后臺(tái)模式告訴iOS繼續(xù)播放音頻,即使應(yīng)用程序在后臺(tái)姓迅。沒(méi)錯(cuò)敲霍,音頻后臺(tái)模式實(shí)際上是自動(dòng)的。你只需要激活它丁存。
返回Xcode肩杈,執(zhí)行以下操作:
接下來(lái),雙擊Background Modes
以添加此功能解寝。展開(kāi)Background Modes
功能扩然,然后勾選Audio, AirPlay, and Picture in Picture
以啟用background audio
。
在物理設(shè)備上構(gòu)建并運(yùn)行應(yīng)用程序编丘。像以前一樣啟動(dòng)音樂(lè)与学,然后離開(kāi)應(yīng)用程序。這一次音頻將繼續(xù)嘉抓。就這么簡(jiǎn)單!
接下來(lái)索守,你將使用Location updates
后臺(tái)模式繼續(xù)接收位置更新,即使應(yīng)用程序是在后臺(tái)抑片。
Receiving Location Updates
首先卵佛,構(gòu)建并運(yùn)行應(yīng)用程序。選擇Location tab
并點(diǎn)擊Start
敞斋。什么也沒(méi)有發(fā)生截汪,因?yàn)槟沐e(cuò)過(guò)了一些重要的步驟。你現(xiàn)在要改變了植捎。
1. Enabling Location Updates
打開(kāi)LocationModel.swift
衙解。這是為LocationView
提供位置數(shù)據(jù)的代碼。您將對(duì)init()
做一個(gè)簡(jiǎn)單的更改焰枢。替換以下兩行:
mgr.requestWhenInUseAuthorization()
mgr.allowsBackgroundLocationUpdates = false
為
mgr.requestAlwaysAuthorization()
mgr.allowsBackgroundLocationUpdates = true
第一行請(qǐng)求位置更新蚓峦,即使應(yīng)用程序沒(méi)有在使用。第二個(gè)請(qǐng)求甚至在后臺(tái)進(jìn)行更新济锄。
回到Signing & Capabilities
界面暑椰,勾選Location updates
框,讓iOS知道你的應(yīng)用程序想在后臺(tái)接收位置更新荐绝。
除了勾選這個(gè)框一汽,iOS還要求你在Info.plist
中設(shè)置一個(gè)鍵向用戶解釋為什么你需要后臺(tái)更新。如果不包含這一點(diǎn)低滩,位置請(qǐng)求將會(huì)無(wú)聲地失敗召夹。
打開(kāi)Info.plist
。并添加Privacy — Location Always and When In Use Usage Description
和Privacy — Location When In Use Usage Description
的鍵委造。然后輸入The app will show your location on a map
作為兩個(gè)鍵的value
戳鹅。
現(xiàn)在,構(gòu)建并運(yùn)行昏兆,切換到Location tab
枫虏,點(diǎn)擊Start
。
當(dāng)它第一次加載時(shí)爬虱,你會(huì)看到你寫進(jìn)你的位置隱私原因的消息隶债。
點(diǎn)擊Allow while using app
,在外面或大樓周圍散步——盡量不要因?yàn)樽タ诖侄中摹?/p>
位置更新應(yīng)該開(kāi)始出現(xiàn)跑筝。如果沒(méi)有死讹,將應(yīng)用再次發(fā)送到后臺(tái),以觸發(fā)Always
提示進(jìn)行位置跟蹤曲梗。你也可以使用Settings
應(yīng)用程序赞警,在Privacy ? Location Services ? Sleepless
設(shè)置中啟用Sleepless
應(yīng)用程序始終跟蹤妓忍。
如果你將應(yīng)用程序發(fā)送到后臺(tái),你仍然會(huì)看到控制臺(tái)中發(fā)生的位置更新愧旦。
一段時(shí)間后世剖,你應(yīng)該會(huì)看到如下內(nèi)容:
2. Testing Location Mode in the Background
如果你退出應(yīng)用程序,你應(yīng)該看到應(yīng)用程序更新了控制臺(tái)日志中的位置笤虫。再次打開(kāi)它旁瘫,可以看到地圖上所有的大頭針,顯示你在步行過(guò)程中去過(guò)的地方琼蚯。
如果你正在使用模擬器酬凳,你也可以使用它來(lái)模擬移動(dòng)!點(diǎn)擊Features ? Location
菜單:
非常簡(jiǎn)單遭庶,對(duì)吧宁仔?打開(kāi)第三個(gè)選項(xiàng)卡和第三個(gè)后臺(tái)模式!
Completing Critical Tasks Upon Moving to the Background
下一個(gè)后臺(tái)模式的正式名稱是Extending Your App’s Background Execution Time,任務(wù)完成說(shuō)起來(lái)容易一點(diǎn)!
從技術(shù)上講峦睡,這根本不是后臺(tái)模式台诗。你不需要在Capabilities
中聲明你的應(yīng)用程序使用它。它是一個(gè)API赐俗,當(dāng)你的應(yīng)用程序在后臺(tái)時(shí)拉队,允許你在有限的時(shí)間內(nèi)運(yùn)行任意代碼,給你更多的時(shí)間來(lái)完成關(guān)鍵任務(wù)阻逮,如保存數(shù)據(jù)粱快。
1. When to Use Task Completion
Completion
后臺(tái)模式的一個(gè)有效用例是完成一些關(guān)鍵任務(wù),例如保存用戶的輸入或發(fā)布一個(gè)事務(wù)叔扼。有很多可能性事哭。
由于代碼是任意的,你可以使用這個(gè)API
做幾乎任何事情:執(zhí)行冗長(zhǎng)的計(jì)算瓜富,對(duì)圖像應(yīng)用過(guò)濾器鳍咱,渲染一個(gè)復(fù)雜的3D網(wǎng)格 —— 任何!你的想象力是極限与柑,只要你記住你只有一些時(shí)間谤辜,而不是無(wú)限的時(shí)間。稍后价捧,您將設(shè)置一個(gè)在后臺(tái)運(yùn)行的冗長(zhǎng)計(jì)算丑念,因此您可以看到這個(gè)API是如何工作的。
iOS
決定了你的應(yīng)用程序移到后臺(tái)后的時(shí)間结蟋。你被授予的時(shí)間沒(méi)有保證脯倚,但你總是可以檢查UIApplication.shared.backgroundTimeRemaining
。這會(huì)告訴你還剩下多少時(shí)間嵌屎。
一般的推正,基于觀察的共識(shí)是你大約有30秒恍涂。同樣,沒(méi)有保證植榕,API文檔甚至沒(méi)有給出一個(gè)估計(jì)——所以不要依賴這個(gè)數(shù)字乳丰。你可能有5分鐘或5秒鐘的時(shí)間,所以你的應(yīng)用程序需要為中斷做好準(zhǔn)備内贮。當(dāng)你的時(shí)間快到的時(shí)候,iOS會(huì)給你回調(diào)信號(hào)汞斧。
2. Setting Up a Completion Task
這里有一個(gè)每個(gè)計(jì)算機(jī)科學(xué)專業(yè)的學(xué)生都應(yīng)該熟悉的常見(jiàn)任務(wù):計(jì)算 Fibonacci Sequence中的數(shù)字夜郁。這里的扭轉(zhuǎn)是,你將應(yīng)用程序移動(dòng)到后臺(tái)后計(jì)算這些數(shù)字粘勒。
打開(kāi)CompleteTaskModel.swift
竞端,看看已經(jīng)有什么了。按照目前的情況庙睡,該視圖將按順序計(jì)算斐波那契數(shù)列并顯示結(jié)果事富。
如果你現(xiàn)在掛起一個(gè)實(shí)際設(shè)備上的應(yīng)用程序,計(jì)算將停止乘陪,并在應(yīng)用程序再次激活時(shí)恢復(fù)到原來(lái)的位置统台。你的任務(wù)是創(chuàng)建一個(gè)后臺(tái)任務(wù),這樣計(jì)算就可以一直運(yùn)行啡邑,直到iOS說(shuō)“時(shí)間到贱勃!”
你首先需要添加以下內(nèi)容到CompleteTaskModel
:
var backgroundTask: UIBackgroundTaskIdentifier = .invalid
此屬性標(biāo)識(shí)要在后臺(tái)運(yùn)行的任務(wù)請(qǐng)求。
接下來(lái)谤逼,在resetcalculation()
之前向CompleteTaskModel
添加以下方法:
func registerBackgroundTask() {
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
print("iOS has signaled time has expired")
self?.endBackgroundTaskIfActive()
}
}
registerBackgroundTask()
告訴iOS贵扰,當(dāng)應(yīng)用移動(dòng)到后臺(tái)時(shí),你需要更多的時(shí)間來(lái)完成你正在做的事情流部。返回的值是這個(gè)任務(wù)的標(biāo)識(shí)符戚绕,這樣你就可以告訴iOS你什么時(shí)候完成了。在這個(gè)調(diào)用之后枝冀,如果你的應(yīng)用程序移動(dòng)到后臺(tái)舞丛,它仍然會(huì)得到CPU
時(shí)間,直到你調(diào)用endBackgroundTask(_:)
果漾。
好吧瓷马,至少有一些CPU時(shí)間。
3. Ending the Completion Task
如果你在后臺(tái)一段時(shí)間后沒(méi)有調(diào)用endBackgroundTask(_:)
跨晴, iOS將調(diào)用當(dāng)你調(diào)用beginBackgroundTask(expirationHandler:)
時(shí)定義的閉包欧聘。這使您有機(jī)會(huì)停止執(zhí)行代碼。
因此端盆,調(diào)用endBackgroundTask(_:)
來(lái)告訴系統(tǒng)您已經(jīng)完成是一個(gè)好主意怀骤。如果你不調(diào)用它并在這個(gè)塊運(yùn)行后繼續(xù)執(zhí)行代碼费封,iOS將終止你的應(yīng)用程序!
將這個(gè)方法添加到registerBackgroundTask()
下面:
func endBackgroundTaskIfActive() {
let isBackgroundTaskActive = backgroundTask != .invalid
if isBackgroundTaskActive {
print("Background task ended.")
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = .invalid
}
}
這將結(jié)束后臺(tái)任務(wù),如果它是主動(dòng)注冊(cè)的蒋伦,并將其ID重置為invalid
弓摘。
4. Registering and Ending Background Tasks
現(xiàn)在,對(duì)于重要的部分:更新onChangeOfScenePhase(_:)
來(lái)注冊(cè)和結(jié)束后臺(tái)任務(wù)痕届,這取決于應(yīng)用程序是移動(dòng)到后臺(tái)還是活動(dòng)狀態(tài)韧献。
用以下語(yǔ)句替換這兩個(gè)case語(yǔ)句:
case .background:
let isTimerRunning = updateTimer != nil
let isTaskUnregistered = backgroundTask == .invalid
if isTimerRunning && isTaskUnregistered {
registerBackgroundTask()
}
case .active:
endBackgroundTaskIfActive()
當(dāng)切換到后臺(tái)background
狀態(tài)時(shí),這將在任務(wù)正在運(yùn)行但未注冊(cè)時(shí)注冊(cè)它研叫。當(dāng)切換到活動(dòng)active
狀態(tài)時(shí)锤窑,它將結(jié)束后臺(tái)任務(wù)。
在beginPauseTask()
中嚷炉,在updateTimer = nil
之后添加這一行:
endBackgroundTaskIfActive()
現(xiàn)在渊啰,當(dāng)用戶停止計(jì)算時(shí),你調(diào)用endBackgroundTask(_:)
來(lái)告訴iOS你不需要任何額外的CPU時(shí)間申屹。
注意:每次調(diào)用
beginBackgroundTask(expirationHandler:)
時(shí)調(diào)用endBackgroundTask(_:)
是很重要的绘证。如果你調(diào)用beginBackgroundTask(expirationHandler:)
兩次,并且只對(duì)其中一個(gè)任務(wù)調(diào)用endBackgroundTask(_:)
哗讥,你仍然會(huì)得到CPU
時(shí)間嚷那,直到你使用第二個(gè)后臺(tái)任務(wù)的標(biāo)識(shí)符第二次調(diào)用endBackgroundTask(_:)
。
構(gòu)建并運(yùn)行杆煞,然后切換到第三個(gè)選項(xiàng)卡车酣。
點(diǎn)擊Play
并觀看應(yīng)用程序計(jì)算這些甜蜜的斐波那契值。將應(yīng)用發(fā)送到后臺(tái)索绪,但要觀察Xcode控制臺(tái)的輸出湖员。當(dāng)剩下的時(shí)間減少時(shí),你的應(yīng)用程序應(yīng)該繼續(xù)更新數(shù)字瑞驱。
在大多數(shù)情況下娘摔,這個(gè)時(shí)間從30秒開(kāi)始,一直到5秒唤反。如果你在達(dá)到5秒時(shí)等待時(shí)間過(guò)期——或者你看到的任何值——iOS就會(huì)調(diào)用過(guò)期block
凳寺。
你的應(yīng)用程序應(yīng)該很快停止產(chǎn)生輸出。然后彤侍,如果你回到應(yīng)用程序肠缨,計(jì)時(shí)器應(yīng)該會(huì)再次啟動(dòng),斐波那契瘋狂將繼續(xù)盏阶。
在前臺(tái)和后臺(tái)之間切換晒奕,看看如何通過(guò)每次切換獲得額外的時(shí)間塊。
下面是本教程的最后一個(gè)主題:background fetch
Background Fetch
Background fetch
是在iOS 7
中引入的。它可以讓你的應(yīng)用程序顯示最新的同時(shí)最小化對(duì)電池壽命的影響脑慧。從iOS 13
開(kāi)始魄眉,蘋果引入了一個(gè)新的后臺(tái)任務(wù)調(diào)度程序API,提供了顯著的改進(jìn)闷袒。
例如坑律,假設(shè)你正在應(yīng)用程序中實(shí)現(xiàn)一個(gè)新聞feed
。在后臺(tái)獲取之前囊骤,你將在應(yīng)用程序每次啟動(dòng)時(shí)刷新feed
晃择。
遺憾的是,當(dāng)刷新時(shí)也物,用戶會(huì)看到幾秒鐘的舊標(biāo)題宫屠。你知道,有些人會(huì)試圖挖掘一個(gè)故事焦除,結(jié)果卻發(fā)現(xiàn)它消失了,取而代之的是一個(gè)不相關(guān)的故事作彤”炱牵看起來(lái)不太好。
如果當(dāng)用戶打開(kāi)你的應(yīng)用時(shí)竭讳,最新的標(biāo)題就會(huì)神奇地出現(xiàn)在那里创葡,不是更好嗎?這是后臺(tái)獲取給你的能力绢慢。
當(dāng)啟用時(shí)灿渴,系統(tǒng)利用使用模式來(lái)確定何時(shí)觸發(fā)后臺(tái)獲取。例如胰舆,如果用戶在上午9點(diǎn)打開(kāi)你的新聞應(yīng)用骚露,background fetch
可能會(huì)在上午9點(diǎn)之前發(fā)生。系統(tǒng)決定發(fā)出background fetch
的最佳時(shí)間缚窿,由于這個(gè)原因棘幸,它不適合進(jìn)行關(guān)鍵更新。
1. Understanding Background Fetch
Background fetch
由BGTaskScheduler
控制倦零,這是一個(gè)復(fù)雜的系統(tǒng)误续,用于平衡所有影響用戶體驗(yàn)的因素,如性能扫茅、使用模式蹋嵌、電池壽命等蹦魔。
Background fetch
通常涉及從外部來(lái)源(如網(wǎng)絡(luò)服務(wù))獲取信息炫隶。在本后臺(tái)模式教程中,您將獲取當(dāng)前時(shí)間延窜,而不使用網(wǎng)絡(luò)。
為了實(shí)現(xiàn)background fetch
愕鼓,你需要完成這些任務(wù)——但現(xiàn)在不要做:
- 在你的應(yīng)用程序的
Capabilities
的Background Modes
中勾選Background fetch
钙态。 - 為
Info.plist
添加標(biāo)識(shí)符。請(qǐng)為您的刷新任務(wù)菇晃。 - 在你的應(yīng)用程序代理中調(diào)用
BGTaskScheduler.register(forTaskWithIdentifier:using:launchHandler:)
來(lái)處理后臺(tái)獲取册倒。 - 創(chuàng)建一個(gè)
BGAppRefreshTaskRequest
,為何時(shí)執(zhí)行指定一個(gè)earliestBeginDate
磺送。 - 使用
BGTaskScheduler.submit(_:)
提交請(qǐng)求驻子。
與后臺(tái)完成任務(wù)類似,您有一個(gè)很短但不確定的時(shí)間框架來(lái)執(zhí)行background fetch
估灿。共識(shí)的數(shù)字是最大30
秒崇呵,但計(jì)劃更少。如果您需要下載大型資源作為獲取的一部分馅袁,請(qǐng)使用URLSession
的后臺(tái)傳輸服務(wù)域慷。
2. Implementing Background Fetch
是時(shí)候開(kāi)始了。首先汗销,簡(jiǎn)單的部分:在Signing & Capabilities
下選中Background fetch
能力犹褒。
接下來(lái),打開(kāi)Info.plist
弛针。并點(diǎn)擊+
來(lái)添加一個(gè)新的標(biāo)識(shí)符叠骑。
向下滾動(dòng)并選擇Permitted background task scheduler identifiers
。展開(kāi)項(xiàng)目削茁,然后點(diǎn)擊新標(biāo)識(shí)符旁邊的+
以添加條目宙枷。
輸入com.mycompany.myapp.task.refresh
獲取標(biāo)識(shí)符的值。
注意:在您的實(shí)際項(xiàng)目中茧跋,您將反向使用您公司的URL作為標(biāo)識(shí)符的根慰丛,添加您的應(yīng)用程序名稱和描述性元素,如
task.refresh
瘾杭¤档郏可以定義多種類型的刷新任務(wù),每種任務(wù)都有自己的標(biāo)識(shí)符富寿。
接下來(lái)睬隶,你需要一個(gè)AppDelegate
類,因?yàn)閕OS希望在application(_:didFinishLaunchingWithOptions:)
任務(wù)之間注冊(cè)你的獲取task
页徐。
在App
文件夾中苏潜,添加一個(gè)新的Swift
文件AppDelegate.swift
。然后將現(xiàn)有代碼替換為:
import UIKit
import BackgroundTasks
class AppDelegate: UIResponder, UIApplicationDelegate {
static var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .long
return formatter
}()
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
return true
}
}
這段代碼為刷新時(shí)間戳定義了一個(gè)日期格式化器变勇。它還包括一個(gè)application(_:didFinishLaunchingWithOptions:)
空方法恤左,這是您將注冊(cè)后臺(tái)獲取任務(wù)的地方贴唇。
現(xiàn)在向AppDelegate
添加以下函數(shù):
func refresh() {
// to simulate a refresh, just update the last refresh date
// to current date/time
let formattedDate = Self.dateFormatter.string(from: Date())
UserDefaults.standard.set(
formattedDate,
forKey: UserDefaultsKeys.lastRefreshDateKey)
print("refresh occurred")
}
這個(gè)函數(shù)模擬了一次刷新。
在您創(chuàng)建的應(yīng)用程序中飞袋,您可能會(huì)從網(wǎng)絡(luò)獲取數(shù)據(jù)戳气。對(duì)于本教程,您將把一個(gè)格式化的時(shí)間戳保存到UserDefaults
中巧鸭,以顯示刷新執(zhí)行的時(shí)間瓶您。
仍然在AppDelegate.swift
中,向AppDelegate
添加以下函數(shù):
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(
identifier: AppConstants.backgroundTaskIdentifier)
request.earliestBeginDate = Date(timeIntervalSinceNow: 1 * 60)
do {
try BGTaskScheduler.shared.submit(request)
print("background refresh scheduled")
} catch {
print("Couldn't schedule app refresh \(error.localizedDescription)")
}
}
這里你創(chuàng)建了一個(gè)BGAppRefreshTaskRequest
纲仍,然后從當(dāng)前時(shí)間開(kāi)始分配一個(gè)earliestBeginDate
呀袱。然后使用BGTaskScheduler.submit(_:)
提交請(qǐng)求。
現(xiàn)在郑叠,將application(_:didFinishLaunchingWithOptions:)
替換為:
BGTaskScheduler.shared.register(
forTaskWithIdentifier: AppConstants.backgroundTaskIdentifier,
using: nil) { task in
self.refresh() // 1
task.setTaskCompleted(success: true) // 2
self.scheduleAppRefresh() // 3
}
scheduleAppRefresh()
return true
當(dāng)iOS完成啟動(dòng)應(yīng)用程序時(shí)夜赵,這段代碼向任務(wù)調(diào)度器注冊(cè)任務(wù)并調(diào)度第一次刷新。任務(wù)本身乡革,當(dāng)執(zhí)行時(shí)寇僧,將:
現(xiàn)在需要將AppDelegate
連接到AppMain
。打開(kāi)AppMain.swift
沸版。在body
之前加上這一行:
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
這就是iOS
調(diào)用AppDelegate
所需要的一切嘁傀。
在物理設(shè)備上構(gòu)建并運(yùn)行應(yīng)用程序。檢查Xcode
控制臺(tái)的消息推穷,以確認(rèn)后臺(tái)刷新是預(yù)定調(diào)度的心包。
3. Testing Background Fetch
測(cè)試background fetch
的一種方法是坐等系統(tǒng)決定執(zhí)行它类咧。但你可能要坐很長(zhǎng)時(shí)間等待這一切發(fā)生馒铃。
iOS
無(wú)法保證何時(shí)執(zhí)行刷新。該系統(tǒng)使用多種因素來(lái)決定何時(shí)執(zhí)行痕惋,如應(yīng)用程序使用模式区宇、電池充電等。幸運(yùn)的是值戳,Xcode
提供了一種使用調(diào)試器命令觸發(fā)后臺(tái)獲取的方法议谷。
打開(kāi)RefreshView.swift
并在print("moved to background")
處設(shè)置斷點(diǎn)。
然后將應(yīng)用發(fā)送到后臺(tái)堕虹,Xcode應(yīng)該在新的斷點(diǎn)處中斷卧晓。在lldb
提示符下,輸入以下命令(或者赴捞,因?yàn)樗浅?fù)雜逼裆,復(fù)制和粘貼!)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.mycompany.myapp.task.refresh"]
這將指示調(diào)試器立即執(zhí)行后臺(tái)刷新。
恢復(fù)應(yīng)用程序的執(zhí)行赦政∈び睿控制臺(tái)應(yīng)該顯示刷新已發(fā)生,然后調(diào)度計(jì)劃的后臺(tái)刷新。每次刷新都為未來(lái)安排另一次刷新桐愉。您還可能看到來(lái)自后臺(tái)任務(wù)調(diào)度器的調(diào)試消息财破,指示其活動(dòng)。
接下來(lái)从诲,重新打開(kāi)應(yīng)用程序左痢。 Refresh tab
將顯示刷新發(fā)生的時(shí)間和日期。
如果你把這款應(yīng)用留在你的設(shè)備上盏求,在接下來(lái)的幾天里查看抖锥,你會(huì)不時(shí)看到時(shí)間戳的更新。iOS根據(jù)最佳刷新時(shí)間的計(jì)算調(diào)用刷新碎罚。
對(duì)于需要很多分鐘才能完成的長(zhǎng)時(shí)間運(yùn)行的后臺(tái)任務(wù)磅废,了解更多關(guān)于 background processing tasks的信息。后臺(tái)處理任務(wù)Background processing
類似于后臺(tái)獲取(background fetch)
荆烈,但用于更嚴(yán)格的任務(wù)拯勉,如數(shù)據(jù)處理和維護(hù)。
還有兩個(gè)與后臺(tái)模式(background mode)
相關(guān)的很棒的WWDC
演講:
-
Advances in App Background Execution : 討論
background processing
選項(xiàng)的最新改進(jìn)憔购。 -
Background Execution Demystified : 將幫助你對(duì)不同的
background mode
有更深的理解宫峦。
最后,您可以在Configuring Background Execution Modes 中了解所有的后臺(tái)執(zhí)行模式玫鸟。
后記
本篇主要講述了
Background Modes
幾種Mode使用示例导绷,感興趣的給個(gè)贊或者關(guān)注~~~