前言

近期项目进行迭代更新,偶然看到项目中对电话拨打、接听以及挂断的SDK已经被遗弃了,所以尝试着换成了新的SDK,注意到网上相关内容较少,因此记录一下自己的实操。

警告

该API在国内已经禁用,目前老的电话监听API还可以在iOS 14上使用,建议换回来

场景

APP内长久使用,如看视频、主播直播等,该场景下电话进入可能导致断网的情况,需要及时处理,在用户回来之后,可以恢复场景。

实战

准备工作

头文件引入:

#import <CallKit/CXCallObserver.h>
#import <CallKit/CXCall.h>

创建一个全局的监听对象,方便在离开页面或者发生跳转回来之后进行对象的移除与重新创建

/// 电话监听
@property (nonatomic, strong) CXCallObserver *callObserver;

需要添加协议

CXCallObserverDelegate

初始化

由于我这边的使用场景为直播间,因此存在直播间跳转到用户详情的情况,所以为了不写重复代码,我将初始化放进了viewWillApear方法中

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    // 电话监听
    if (!self.callObserver) {
        self.callObserver = [[CXCallObserver alloc] init];
        [self.callObserver setDelegate:self queue:dispatch_get_main_queue()];
    }
}

如果不需要跳转的独立页面,直接写进viewDidLoad中也是可以的

状态监听

#pragma mark - 电话的监听
- (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call {
    NSLog(@"call observer uuid: %@", call.UUID);
    NSLog(@"outgoing(拨打) :%d  onHold(待接通) :%d   hasConnected(接通) :%d   hasEnded(挂断) :%d",call.outgoing,call.onHold,call.hasConnected,call.hasEnded);
    /*
     https://developer.apple.com/documentation/callkit/cxcall
     
     挂断    outgoing(拨打) :0  onHold(待接通) :0   hasConnected(接通) :0   hasEnded(挂断) :1
     拨打    outgoing(拨打) :1  onHold(待接通) :0   hasConnected(接通) :0   hasEnded(挂断) :0  (拨打)
     outgoing(拨打) :1  onHold(待接通) :0   hasConnected(接通) :0   hasEnded(挂断) :1  (拨打 - 挂断)
     outgoing(拨打) :1  onHold(待接通) :0   hasConnected(接通) :1   hasEnded(挂断) :0  (拨打 - 接通)
     outgoing(拨打) :1  onHold(待接通) :0   hasConnected(接通) :1   hasEnded(挂断) :1  (拨打 - 接通 - 挂断)
     接通    outgoing(拨打) :0  onHold(待接通) :0   hasConnected(接通) :1   hasEnded(挂断) :0  (接通)
     outgoing(拨打) :0  onHold(待接通) :0   hasConnected(接通) :1   hasEnded(挂断) :1  (接通 - 挂断)
     */
    
    if ((call.outgoing && call.hasConnected) ||
        call.hasConnected) {
        // 说明主动拨打 或者 接通了电话
       
        dispatch_async(dispatch_get_main_queue(), ^{
           
        });
    }
    
    if ((call.hasConnected && call.hasEnded) ||
        (call.outgoing && call.hasEnded)) {
        // 说明是接通过电话并已挂断 或者 拨打并已挂断
        dispatch_async(dispatch_get_main_queue(), ^{
           
        });
        return;
    }

}

需要说明的是,该方法不能通过单一状态来判断当前状态,建议进行多值的判断

取消监听

当离开页面或者不在需要的时候,只需要执行以下代码,将监听置空就不会在进入监听了

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    if (self.callObserver) {
        [self.callObserver setDelegate:nil queue:dispatch_get_main_queue()];
        self.callObserver = nil;
    }
}

结语

虽然是个简单的功能,不过有时候找不到资料的时候还是很容易走进坑里,希望这篇文章能帮助更多的同行节约时间。