Swift : 在VoIP应用中接入iOS10中的CallKit框架--即接听电话使用系统原生界面

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lin1109221208/article/details/53785513

        由于目前开发的应用是一款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<String>
        
        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
        }
    }

3、开发中遇到的问题:

(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




      

      

猜你喜欢

转载自blog.csdn.net/lin1109221208/article/details/53785513