Ios 呼叫套件拒绝入站呼叫(目标-C)

Ios 呼叫套件拒绝入站呼叫(目标-C),ios,objective-c,voip,callkit,Ios,Objective C,Voip,Callkit,我正在使用CallKit开发一个VOIP应用程序(我们称之为SampleApp),我正在努力解决一个问题 我可以使用CallKit以似乎正常工作的方式回答入站SampleApp调用。但是,当我拒绝一个调用时,调用仍然被实例化,这是不正确的行为 根据我的理解,我需要根据呼叫是否被接受和拒绝得到一个布尔值,然后用它来决定电话控制器是否接听来电 PhoneViewController.m - (void) presentIncomingCallAlertForCall:(SampleAppClient

我正在使用CallKit开发一个VOIP应用程序(我们称之为SampleApp),我正在努力解决一个问题

我可以使用CallKit以似乎正常工作的方式回答入站SampleApp调用。但是,当我拒绝一个调用时,调用仍然被实例化,这是不正确的行为

根据我的理解,我需要根据呼叫是否被接受和拒绝得到一个布尔值,然后用它来决定电话控制器是否接听来电

PhoneViewController.m

- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call
{
    callIdentifier = [[NSUUID alloc] init];
    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) 
    {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];

        [self answerIncomingCall];
    }
    // Use Notification mechanism if iPad
    else 
    {
        // etc.
    }
}
-(void) reportIncomingCall: (NSUUID *) uuid
                handle: (NSString *) handle
              hasVideo: (BOOL) hasVideo
     completionHandler:
     (nullable void (^) (NSArray * _Nullable results, NSError * _Nonnull error))completionHandler
{
    CXCallUpdate *update = [[CXCallUpdate alloc] init];
    update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber 
                                                   value:handle];
    update.hasVideo = hasVideo;

    [provider reportNewIncomingCallWithUUID:uuid 
                                     update:update 
                                 completion: ^(NSError *error)
    {
        // not sure what to put here? 
    }]; 
}

- (void) provider: (CXProvider *)provider 
     performAnswerCallAction : (CXAnswerCallAction *)action 
{
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateConnected: now];
}
- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call {

    callIdentifier = [[NSUUID alloc] init];

    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];
    }
    // Use Notification mechanism if iPad
    else {
        ...
    }
}
ProviderDelegate.m

- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call
{
    callIdentifier = [[NSUUID alloc] init];
    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) 
    {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];

        [self answerIncomingCall];
    }
    // Use Notification mechanism if iPad
    else 
    {
        // etc.
    }
}
-(void) reportIncomingCall: (NSUUID *) uuid
                handle: (NSString *) handle
              hasVideo: (BOOL) hasVideo
     completionHandler:
     (nullable void (^) (NSArray * _Nullable results, NSError * _Nonnull error))completionHandler
{
    CXCallUpdate *update = [[CXCallUpdate alloc] init];
    update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber 
                                                   value:handle];
    update.hasVideo = hasVideo;

    [provider reportNewIncomingCallWithUUID:uuid 
                                     update:update 
                                 completion: ^(NSError *error)
    {
        // not sure what to put here? 
    }]; 
}

- (void) provider: (CXProvider *)provider 
     performAnswerCallAction : (CXAnswerCallAction *)action 
{
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateConnected: now];
}
- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call {

    callIdentifier = [[NSUUID alloc] init];

    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];
    }
    // Use Notification mechanism if iPad
    else {
        ...
    }
}
这是我的第一个问题,我已经阅读了堆栈溢出指南,但是如果我做错了什么,请告诉我

但是,当我拒绝一个调用时,该调用无论如何都会被实例化,这 这是不正确的行为

不清楚您在这里的代码中试图做什么。您总是呼叫
[自我应答呼叫]
(我们没有看到要执行的代码,但我假设它会向您的应用程序逻辑和后端报告用户已应答呼叫)就在
[\pDelegate reportIncomingCall:…]
之后,因此您似乎假设用户已决定应答,甚至在用户做任何事情之前

相反,你应该告诉你的应用程序逻辑和你的后端,用户已经接听了电话,只有在你的
-provider:performAnswerCallAction:
方法中,并且在你的
-provider:performEndCallAction:
中,告诉你的应用程序逻辑和后端,用户已经拒绝了呼叫(如果是来电)

但是,当我拒绝一个调用时,该调用无论如何都会被实例化,这 这是不正确的行为

不清楚您在这里的代码中试图做什么。您总是呼叫
[自我应答呼叫]
(我们没有看到要执行的代码,但我假设它会向您的应用程序逻辑和后端报告用户已应答呼叫)就在
[\pDelegate reportIncomingCall:…]
之后,因此您似乎假设用户已决定应答,甚至在用户做任何事情之前


相反,你应该告诉你的应用程序逻辑和你的后端,用户已经接听了电话,只有在你的
-provider:performAnswerCallAction:
方法中,并且在你的
-provider:performEndCallAction:
中,告诉你的应用程序逻辑和后端,用户已经拒绝了呼叫(如果是来电).

以下是基于@user102008建议的解决方案,该建议实现了我想要实现的目标

我将应答传入呼叫的责任转移到提供者代理而不是phone view controller,后者调用应答呼叫或结束呼叫方法,具体取决于其提供者方法中的呼叫是被接受还是被拒绝

PhoneViewController.m

- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call
{
    callIdentifier = [[NSUUID alloc] init];
    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) 
    {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];

        [self answerIncomingCall];
    }
    // Use Notification mechanism if iPad
    else 
    {
        // etc.
    }
}
-(void) reportIncomingCall: (NSUUID *) uuid
                handle: (NSString *) handle
              hasVideo: (BOOL) hasVideo
     completionHandler:
     (nullable void (^) (NSArray * _Nullable results, NSError * _Nonnull error))completionHandler
{
    CXCallUpdate *update = [[CXCallUpdate alloc] init];
    update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber 
                                                   value:handle];
    update.hasVideo = hasVideo;

    [provider reportNewIncomingCallWithUUID:uuid 
                                     update:update 
                                 completion: ^(NSError *error)
    {
        // not sure what to put here? 
    }]; 
}

- (void) provider: (CXProvider *)provider 
     performAnswerCallAction : (CXAnswerCallAction *)action 
{
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateConnected: now];
}
- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call {

    callIdentifier = [[NSUUID alloc] init];

    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];
    }
    // Use Notification mechanism if iPad
    else {
        ...
    }
}
ProviderDelegate.h

-(void) reportIncomingCall: (NSUUID *) uuid
                    handle: (NSString *) handle
                  hasVideo: (BOOL) hasVideo
         completionHandler: (nullable void (^) (NSArray * _Nullable results, NSError * _Nonnull error))
            completionHandler {

    CXCallUpdate *update = [[CXCallUpdate alloc] init];
    update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:handle];
    update.hasVideo = hasVideo;

    [provider reportNewIncomingCallWithUUID:uuid 
                                     update:update 
                                 completion: ^(NSError *error) {
        if (error) {
            [self reportCallEnded:uuid reason:(NSInteger *)CXCallEndedReasonFailed];
        }
    }];
}


- (void) provider: (CXProvider *)provider performAnswerCallAction: (CXAnswerCallAction *)action {
    [_phoneVC answerIncomingCall];
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateConnected: now];
}

- (void) provider: (CXProvider *)provider performEndCallAction: (CXEndCallAction *)action {
    [_phoneVC rejectIncomingCall];
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateEnded: now];
}

下面是基于@user102008的建议的解决方案,它实现了我想要实现的目标

我将应答传入呼叫的责任转移到提供者代理而不是phone view controller,后者调用应答呼叫或结束呼叫方法,具体取决于其提供者方法中的呼叫是被接受还是被拒绝

PhoneViewController.m

- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call
{
    callIdentifier = [[NSUUID alloc] init];
    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) 
    {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];

        [self answerIncomingCall];
    }
    // Use Notification mechanism if iPad
    else 
    {
        // etc.
    }
}
-(void) reportIncomingCall: (NSUUID *) uuid
                handle: (NSString *) handle
              hasVideo: (BOOL) hasVideo
     completionHandler:
     (nullable void (^) (NSArray * _Nullable results, NSError * _Nonnull error))completionHandler
{
    CXCallUpdate *update = [[CXCallUpdate alloc] init];
    update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber 
                                                   value:handle];
    update.hasVideo = hasVideo;

    [provider reportNewIncomingCallWithUUID:uuid 
                                     update:update 
                                 completion: ^(NSError *error)
    {
        // not sure what to put here? 
    }]; 
}

- (void) provider: (CXProvider *)provider 
     performAnswerCallAction : (CXAnswerCallAction *)action 
{
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateConnected: now];
}
- (void) presentIncomingCallAlertForCall:(SampleAppClientCall*)call {

    callIdentifier = [[NSUUID alloc] init];

    // Use CallKit if iPhone
    if(UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
        [_pDelegate reportIncomingCall:callIdentifier 
                                handle:call.remoteAddress 
                              hasVideo:hasVideo 
                     completionHandler: nil];
    }
    // Use Notification mechanism if iPad
    else {
        ...
    }
}
ProviderDelegate.h

-(void) reportIncomingCall: (NSUUID *) uuid
                    handle: (NSString *) handle
                  hasVideo: (BOOL) hasVideo
         completionHandler: (nullable void (^) (NSArray * _Nullable results, NSError * _Nonnull error))
            completionHandler {

    CXCallUpdate *update = [[CXCallUpdate alloc] init];
    update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:handle];
    update.hasVideo = hasVideo;

    [provider reportNewIncomingCallWithUUID:uuid 
                                     update:update 
                                 completion: ^(NSError *error) {
        if (error) {
            [self reportCallEnded:uuid reason:(NSInteger *)CXCallEndedReasonFailed];
        }
    }];
}


- (void) provider: (CXProvider *)provider performAnswerCallAction: (CXAnswerCallAction *)action {
    [_phoneVC answerIncomingCall];
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateConnected: now];
}

- (void) provider: (CXProvider *)provider performEndCallAction: (CXEndCallAction *)action {
    [_phoneVC rejectIncomingCall];
    NSDate *now = [[NSDate alloc] init];
    [action fulfillWithDateEnded: now];
}

provider:performAnswerCallAction:
中,您是否尝试调用
[action fail]
而不是
fulfillWithDateConnected:
?@davewston感谢您的评论。我尝试了你的建议,但似乎没有效果。在
提供程序:PerformancesWerCallAction:
中,你是否尝试调用
[操作失败]
,而不是
使用DateConnected:
实现?@Davewston感谢您的评论。我试过你的建议,但似乎没有效果。你的评论使我意识到我在倒退。My PhoneViewController(PVC)应接收呼叫,并将其报告给ProviderDelegate,并且该代理应在其自己的PerformancesWerCallAction和PerformanceCallAction中调用PVC的AnswerInMingCall方法。您的评论使我意识到我正在倒退。My PhoneViewController(PVC)应接收呼叫,并将其报告给ProviderDelegate,并且该代理应在其自己的PerformanceWerCallAction和PerformanceCallAction中调用PVC的AnswerInMingCall方法。