原文
"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