由于目前开发的应用是一款VoIP应用,需要接入iOS10新框架CallKit,由于这个框架在官网也只有各种方法,没有具体的说明,不过提供了一个swift版本的Demo作为参考,
官网Demo链接地址:官网Demo链接
使用CallKit接听来电的步骤为:
1、配置CallKit框架的模型类、管理类和代理方法类,这个可以参考官网Demo里面的,需要的文件见下图红线标注的部分
2、在AppDelegate中引入PushKit框架,并注册pushRegistry对象,遵守PKPushRegistryDelegate代理,并实现其
didReceiveIncomingPushWithPayload代理方法,部分代码如下:
let pushRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
//注册VOIP通知
//设置来电的pushKit和ProviderDelegate
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = NSSet(object: PKPushTypeVoIP) as? Set
if #available(iOS 10.0, *) {
print("CallKit 管理者")
providerDelegate = CallKit_ProviderDelegate(callManager: callManager1)
在此还需要定义两个对象:CallKit管理类和CallKit代理方法类对象
@available(iOS 10.0, *)
var callManager1 = CallKit_CallManager()
@available(iOS 10.0, *)
var providerDelegate: CallKit_ProviderDelegate?
在收到来电推送后,在
didReceiveIncomingPushWithPayload方法中将来电的参数传给CallKit中的方法报给系统向用户展示
func pushRegistry(registry: PKPushRegistry, didReceiveIncomingPushWithPayload payload: PKPushPayload, forType type: String) {
print("didReceiveIncomingPushWithPayload")
//判断类型是否是voip
guard type == PKPushTypeVoIP else {
return
}
//取到之前设置的pload
let alert = payload.dictionaryPayload
print("alert \(alert) ")
let alertDict = payload.dictionaryPayload["aps"]!["alert"]!
var name :String = alertDict!["loc-args"]!!.firstObject as! String
let callType :String = alertDict!["loc-key"]! as! String
print("alertDict \(alertDict) ")
if #available(iOS 10.0, *) {
// //界面处理
if let callidString = alert["callid"] as? String,
var handle = alert["aps"]!["alert"]!!["loc-args"]!!.firstObject as? String
// let hasVideo = alert["apns"]!["sound"] as? Bool,
{
let uuid = NSUUID()
// UIDevice.currentDevice().identifierForVendor
if (handle.rangeOfString("@") != nil) {
handle = handle.substringToIndex((handle.rangeOfString("@")?.startIndex)!)
}
print("-------------callidString :\(callidString)")
print("-----------displayIncomingCall")
displayIncomingCall(uuid, handle: handle, hasVideo: false, completion: { (error) in
})
}
} else {
if (name.rangeOfString("@") != nil) {
name = name.substringToIndex((name.rangeOfString("@")?.startIndex)!)
}
//创建UILocalNotification来进行本地消息通知
let localNotification = UILocalNotification()
//推送内容
localNotification.alertBody = "ReceiveIncomingPush:"+name
//声音
localNotification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification)
}
}
//向用户展示来电
func displayIncomingCall(uuid: NSUUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)? = nil) {
if #available(iOS 10.0, *) {
providerDelegate?.reportIncomingCall(uuid, handle: handle, hasVideo: hasVideo, cmpletion: completion)
} else {
// Fallback on earlier versions
}
}
(1)当应用在后台且手机未锁屏时,如何在接通系统界面的同时自动接通应用中的来电界面
解决方法:在CallKit的代理类中的performAnswerCallAction代理方法中向应用的来电界面发送一个通知,应用的来电界面收到通知后,在通知方法中设置按钮的自动点击事件:
self.acceptBtn.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
(2)当app用户作为被叫时,如何让系统界面被动挂断电话?
解决方法:每个来电都有唯一的callUUID,然后找到这个来电对象,使用CXEndCallAction创建动作,让界面执行改动做
//找到与uuid相对应的call对象
guard let call = callManager?.callWithUUID(self.callUUID) else {
return
}
let callend : CXEndCallAction = CXEndCallAction(callUUID: call.uuid!)
let transaction : CXTransaction = CXTransaction.init()
transaction.addAction(callend)
callManager?.callController.requestTransaction(transaction, completion: { (error) in
print("-----error : \(error)")
})
参考文档链接:http://www.jianshu.com/p/d3d82f62ffaa
http://www.jianshu.com/p/3bf73a293535
http://www.jianshu.com/p/305bd923c1ae