反应本机 voip 推送通知应用程序在接受呼叫后不会启动

问题描述 投票:0回答:1

所以我目前正在开发一个在 iOS 上实现 VoIP 呼叫的应用程序,为此我使用了

RNCallKeep
RNVoipPushNotification
。我设法处理所有状态,包括前台和后台的应用程序,但问题是,当应用程序处于
Killed
状态或
background
状态时,并且在我点击后,设备会收到 VoIP 呼叫,应答呼叫将被接受的背景。但应用程序无法启动

AppDelegate填充

`#import "AppDelegate.h"

#import <Firebase.h>
#import "RNNotifications.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNCallKeep.h"
#import <PushKit/PushKit.h>                 
#import "RNVoipPushNotificationManager.h"

#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>

static void InitializeFlipper(UIApplication *application) {
  FlipperClient *client = [FlipperClient sharedClient];
  SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
  [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
  [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
  [client addPlugin:[FlipperKitReactPlugin new]];
  [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
  [client start];
}
#endif

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
 if ([FIRApp defaultApp] == nil) {
      [FIRApp configure];
    }
#ifdef FB_SONARKIT_ENABLED
  InitializeFlipper(application);
#endif

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

  [RNCallKeep setup:@{
    @"appName": @"Med360Doctors",
    @"maximumCallGroups": @3,
    @"maximumCallsPerCallGroup": @1,
    @"supportsVideo": @YES,
  }];

  [RNVoipPushNotificationManager voipRegistration];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"Med360Doctors"
                                            initialProperties:nil];

  if (@available(iOS 13.0, *)) {
      rootView.backgroundColor = [UIColor systemBackgroundColor];
  } else {
      rootView.backgroundColor = [UIColor whiteColor];
  }

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  [RNNotifications startMonitorNotifications];
  return YES;
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  [RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
  [RNNotifications didReceiveBackgroundNotification:userInfo withCompletionHandler:completionHandler];
}


- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];

#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

 - (BOOL)application:(UIApplication *)application
 continueUserActivity:(NSUserActivity *)userActivity
   restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler
 {
   return [RNCallKeep application:application
            continueUserActivity:userActivity
              restorationHandler:restorationHandler];
 }

 - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
  // Register VoIP push token (a property of PKPushCredentials) with server
  [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type];
}

- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type
{
  // --- The system calls this method when a previously provided push token is no longer valid for use. No action is necessary on your part to reregister the push type. Instead, use this method to notify your server not to send push notifications using the matching push token.
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {

  NSString *uuid = payload.dictionaryPayload[@"uuid"];
  NSString *displayName = [NSString stringWithFormat:@"%@ Calling from Med360", payload.dictionaryPayload[@"displayName"]];
  NSString *handle = payload.dictionaryPayload[@"handle"];
  // --- this is optional, only required if you want to call `completion()` on the js side
  [RNVoipPushNotificationManager addCompletionHandler:uuid completionHandler:completion];

  // --- Process the received push
  [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
//  NSDictionary *extra = [payload.dictionaryPayload valueForKeyPath:@"custom.path.to.data"];

  [RNCallKeep reportNewIncomingCall: uuid
                               handle: handle
                           handleType: @"generic"
                             hasVideo: YES
                  localizedCallerName: displayName
                      supportsHolding: YES
                         supportsDTMF: YES
                     supportsGrouping: YES
                   supportsUngrouping: YES
                          fromPushKit: YES
                              payload: nil
                withCompletionHandler: completion];
  
  // --- You don't need to call it if you stored `completion()` and will call it on the js side.
  completion();
}
@end`

RNVOipPushNotification 控制器文件

`import React, { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';
import Incomingvideocall from './components/incomingCallUi/Incomingvideocall';  //callkeep code to manage  accept and reject call 
import VoipPushNotification from "react-native-voip-push-notification";

let timer = null;
const NotificationController = () => {
  const navigation = useNavigation();
  useEffect(() => {
    VoipPushNotification.registerVoipToken();
    VoipPushNotification.addEventListener("notification", (notification) => {
      console.log('samam  2222', notification);
      const { type } = notification;
      if (type === "Video") {
        const incomingCallAnswer = ({ callUUID }) => {
          console.log('inner  1212', callUUID);
         setTimeout(() => {
          navigation.navigate('McoVideoCall', {
            appointment: Object.assign({}, notification),
          });
          Incomingvideocall.endIncomingcallAnswer(callUUID);
          clearTimeout(timer);
          Incomingvideocall.endAllCall();
         }, 1000);
        };
        const endIncomingCall = () => {
          Incomingvideocall.endAllCall();
        };
        Incomingvideocall.configure(incomingCallAnswer, endIncomingCall);
      } else if (type === "DISCONNECTED") {
        Incomingvideocall.endAllCall();
      }
      VoipPushNotification.onVoipNotificationCompleted(notification.uuid);
    });

    VoipPushNotification.addEventListener("didLoadWithEvents", (events) => {
      console.log('events',events);
      const  type  =  events.length != 0 && events[1]?.data?.type
      if (type === "Video") {
        setTimeout(() => {
        Incomingvideocall.endAllCall();
        navigation.navigate('VideoScreen', {
          appointment: Object.assign({}, events.length != 0 ? events[1]?.data : {}),
        });

        clearTimeout(timer);
      }, 1000);
        const incomingCallAnswer = ({ callUUID }) => {
          console.log('inner  11111');
          navigation.navigate('VideoScreen', {
            appointment: Object.assign({}, events),
          });
          Incomingvideocall.endAllCall();
          Incomingvideocall.endIncomingcallAnswer(callUUID);
          clearTimeout(timer);
        };

        const endIncomingCall = () => {
          Incomingvideocall.endAllCall();
        };

        Incomingvideocall.configure(incomingCallAnswer, endIncomingCall);
      } else if (type === "DISCONNECTED") {
        Incomingvideocall.endAllCall();
      }

    });

    return () => {
      VoipPushNotification.removeEventListener("didLoadWithEvents");
      VoipPushNotification.removeEventListener("register");
      VoipPushNotification.removeEventListener("notification");
    };
  }, []);
  return null;
};
export default NotificationController;`

package.json 文件

` "dependencies": {
    "@react-native-firebase/app": "^16.4.6",
    "@react-native-firebase/messaging": "^16.4.6",
    "react": "18.2.0",
    "react-native": "0.71.3",
    "react-native-callkeep": "^4.3.12",
    "react-native-voip-push-notification": "^3.3.2",
    "react-native-webrtc": "^1.94.0"
  },`

Note:

  • 在 Android 上运行良好
  • 使用 iPhone8 或 iPhone6 和 iPhone SE
  • 在 iPhone12 上不工作

每个州都会有工作电话被杀,背景 或前台,但应用程序在接听电话后未启动

ios react-native callkit videocall react-native-call-keep
1个回答
0
投票

我也遇到了同样的问题,我需要等待导航启动才能导航到 CallScreen。

更新:

VoipPushNotification.addEventListener('notification', ...)

这只是CallKit显示来电时的通知,如果你想在接听时触发该事件,则必须使用RNCallKeep事件:

RNCallKeep.addEventListener('answerCall', rnCallKeepAnswerCall)
RNCallKeep.addEventListener('endCall', rnCallKeepEndCall)
© www.soinside.com 2019 - 2024. All rights reserved.