原文
"Energy Efficiency Guide for iOS Apps: Voice Over IP (VoIP) Best Practices"
本文適用于iOS8及以上系統,iOS7及以下系統推薦查看官方文檔“App Programming Guide for iOS”,在該文檔的“Background Execution”中的“Implementing Long-Running Tasks”下的“Implementing a VoIP App”小節。
VoIP最佳實踐
VoIP應用能夠使用戶通過互聯網撥打和接聽電話,而不是通過蜂窩移動網。VoIP應用嚴重依賴網絡,打VoIP電話導致高的能耗就不足為奇了。當VoIP應用處于不活躍的狀態時,不管怎樣應用都應該徹底地空閑已到達省電的目的。
使用VoIP Push Notification來避免長連接
過去(指iOS8之前),VoIP應用不得不和服務器之間維持一個長連接,來接收(可能的)呼入電話和其他數據。這意味著即使不使用應用時也要通過編寫復雜的代碼來實現在應用和服務器端來回發送消息來保持連接的活躍(alive)。這項技術導致設備頻繁地喚醒,浪費了電量。這也意味著如果用戶退出了VoIP應用,來自服務器端的電話就再也接收不到了。
開發者應該使用PushKit框架替代長連接,PushKit的API允許應用接收來著遠程服務器的推送(當數據可用時)。無論何時一旦收到推送,應用就能被喚醒執行動作。比如,當收到呼入電話時,VoIP應用可以顯示一個提醒,并提供選項來用于接聽或拒絕來電。
使用PushKit來接收VoIP推送有很多的優點:
- 省電,只有當使用PushKit并收到VoIP通知時,設備才工作。
- VoIP推送可以直接觸發程序執行,而不同于一般的推送,只有當用戶響應了通知之后,應用才能執行動作。
- VoIP推送被看作高優先級通知,傳送過程無延時。
- 相比一般推送,VoIP推送可以包含更多的數據。這些數據是一般推送不能提供的。
- 當收到VoIP推送但你的VoIP應用并未運行,應用會自動重新啟動(relaunched)。
- 即使你的應用正處于后臺,當收到VoIP推送時,系統也會給你的應用一定的運行時間(runtime)來處理推送。
提示
iOS8及更高版本才支持PushKit。
準備接收 VoIP推送通知
就像所有支持后臺運行的應用一樣,你的VoIP應用必須將開啟后臺運行模式。如圖所示,點擊Xcode Project下的Capabilities pane,選擇Voice over IP。
你也必須創建一個VoIP證書。每一個VoIP應用都需要一個自己單獨的映射到唯一App ID的VoIP服務證書(VoIP Services certificate)。這個證書允許你的通知服務器連接到VoIP服務器。瀏覽Apple Developer Member Center并創建一個新的VoIP服務證書(VoIP Services Certificate)。如圖所示,下載證書并導入鑰匙串訪問應用。
配置VoIP推送通知
為了收到VoIP通知,你需要配置你的應用,在app delegate中連接PushKit框架。然后創建PKPushRegistry
對象,設置它的代理為self
,并注冊VoIP推送,代碼如下。
** 注冊VoIP推送通知**
OBJECTIVE-C
// Link to the PushKit framework
#import <PushKit/PushKit.h>
// Trigger VoIP registration on launch
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self voipRegistration];
return YES;
}
// Register for VoIP notifications
- (void) voipRegistration {
dispatch_queue_t mainQueue = dispatch_get_main_queue()
// Create a push registry object
PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue];
// Set the registry's delegate to self
voipRegistry.delegate = self;
// Set the push type to VoIP
voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
SWIFT
// Link to the PushKit framework
import PushKit
// Trigger VoIP registration on launch
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.voipRegistration()
return true
}
// Register for VoIP notifications
func voipRegistration {
let mainQueue = dispatch_get_main_queue()
// Create a push registry object
let voipRegistry: PKPushRegistry = PKPushRegistry(mainQueue)
// Set the registry's delegate to self
voipRegistry.delegate = self
// Set the push type to VoIP
voipRegistry.desiredPushTypes = [PKPushTypeVoIP]
}
下一步,實現代理的協議方法來處理更新后的推送證書。如果你的應用同時收到了一般通知和VoIP推送,你的應用將收到兩個不同的推送token。為了能收到兩種通知,必須將兩個token發送給對應的服務器,代碼如下。
** 處理更新后的推送通知證書 **
OBJECTIVE-C
// Handle updated push credentials
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials: (PKPushCredentials *)credentials forType:(NSString *)type {
// Register VoIP push token (a property of PKPushCredentials) with server
}
SWIFT
// Handle updated push credentials
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
// Register VoIP push token (a property of PKPushCredentials) with server
}
最后,設置代理的協議方法來處理推送。如果收到推送時你的應用未運行,你的應用將會自動運行(launched automatically),代碼如下。
** 處理推送 **
OBJECTIVE-C
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
// Process the received push
}
SWIFT
// Handle incoming pushes
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
// Process the received push
}
提示
更多關于VoIP推送通知的信息,請瀏覽PushKit Framework Reference