电话监听 CXCallObserver 和CTCallCenter

iOS10开始用CXCallObserver做电话监听. 代码很简单, 就是状态稍复杂, 下面是使用总结. iOS10之前用CTCallCenter下面也有介绍.

CallKit框架在中国禁用了, 2020.10.31上线被拒, 小伙伴们注意了, 我们是只用了电话监听功能. 更换CoreTelephony框架又提了一版, 过审了.

Guideline 5.0 - Legal
Recently, the Chinese Ministry of Industry and Information Technology (MIIT) requested that CallKit functionality be deactivated in all apps available on the China App Store.
During our review, we found that your app currently includes CallKit functionality and has China listed as an available territory in App Store Connect.

Next Steps
This app cannot be approved with CallKit functionality active in China. Please make the appropriate changes and resubmit this app for review.
If you have already ensured that CallKit functionality is not active in China, you may reply to this message in Resolution Center to confirm.
Voice over Internet Protocol (VoIP) call functionality continues to be allowed but can no longer take advantage of CallKit’s intuitive look and feel. CallKit can continue to be used in apps outside of China.

  • 使用CallKit
// 导入头文件
#import <CallKit/CXCallObserver.h>
#import <CallKit/CXCall.h>

@interface YCXRemoteCommandCenter () <CXCallObserverDelegate>
@property (nonatomic,strong) CXCallObserver *callObserber;
@end

@implementation YCXRemoteCommandCenter

- (instancetype)init {
    if (self = [super init]) {
        [self callHandler];
    }
    return self;
}
// 创建对象callObserber 并设置代理
- (void)callHandler {
    if (@available(iOS 10.0, *)) {
        self.callObserber = [[CXCallObserver alloc] init];
        [self.callObserber setDelegate:self queue:dispatch_get_main_queue()];
    } else {
        // Fallback on earlier versions
    }
}

// 代理方法
- (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call  API_AVAILABLE(ios(10.0)){
    
    if (!call.outgoing && !call.onHold && !call.hasConnected && !call.hasEnded) {
        NSLog(@"来电");
    } else if (!call.outgoing && !call.onHold && !call.hasConnected && call.hasEnded) {
        NSLog(@"来电-挂掉(未接通)");
    } else if (!call.outgoing && !call.onHold && call.hasConnected && !call.hasEnded) {
        NSLog(@"来电-接通");
    } else if (!call.outgoing && !call.onHold && call.hasConnected && call.hasEnded) {
        NSLog(@"来电-接通-挂掉");
    } else if (call.outgoing && !call.onHold && !call.hasConnected && !call.hasEnded) {
        NSLog(@"拨打");
    } else if (call.outgoing && !call.onHold && !call.hasConnected && call.hasEnded) {
        NSLog(@"拨打-挂掉(未接通)");
    } else if (call.outgoing && !call.onHold && call.hasConnected && !call.hasEnded) {
        NSLog(@"拨打-接通");
    } else if (call.outgoing && !call.onHold && call.hasConnected && call.hasEnded) {
        NSLog(@"拨打-接通-挂掉");
    }
    NSLog(@"outgoing(拨打):%d  onHold(待接通):%d   hasConnected(接通):%d   hasEnded(挂断):%d",call.outgoing,call.onHold,call.hasConnected,call.hasEnded);
}
@end
  • 使用CoreTelephony
// 导入头文件
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h>
@interface YCXRemoteCommandCenter ()
@property (nonatomic,strong) CTCallCenter *callCenter;
@end

@implementation YCXRemoteCommandCenter
- (instancetype)init {
    if (self = [super init]) {
        [self callHandler];
    }
    return self;
}

- (void)callHandler {
    self.callCenter = [[CTCallCenter alloc] init];
    YCX_WSELF;
    self.callCenter.callEventHandler = ^(CTCall *call) {
        YCX_SSELF;
         // 主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([call.callState isEqualToString:CTCallStateDialing]) {
                NSLog(@"拨打");
            } else if ([call.callState isEqualToString:CTCallStateConnected]) {
                NSLog(@"接通");
            } else if ([call.callState isEqualToString:CTCallStateIncoming]) {
                NSLog(@"来电");
            } else if ([call.callState isEqualToString:CTCallStateDisconnected]) {
                NSLog(@"挂掉");
            } else {
                NSLog(@"其他");
            }
        });
    };
}
@end

推荐阅读更多精彩内容