ios react原生推送通知应用程序在接受呼叫后无法启动

70gysomp  于 11个月前  发布在  iOS
关注(0)|答案(2)|浏览(66)

所以我目前正在开发一个在iOS上实现VoIP呼叫的应用程序,要做到这一点,我使用RNCallKeepRNVoipPushNotification .我设法处理所有的状态,包括在前台和后台的应用程序,但事情是,当应用程序处于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`

字符串

RNVoipPushNotificationController文件

import React, { useEffect } from 'react';
    import { useNavigation } from '@react-navigation/native';
    import Incomingvideocall from './components/incomingCallUi/Incomingvideocall';      import VoipPushNotification from "react-native-voip-push-notification";
    

    const NotificationController = () => {
      const navigation = useNavigation();
      useEffect(() => {
        VoipPushNotification.registerVoipToken();
        VoipPushNotification.addEventListener("notification", (notification) => {
         
          const { type } = notification;
          if (type === "Video") {
            const incomingCallAnswer = ({ callUUID }) => {
              navigation.navigate('McoVideoCall', {
                appointment: Object.assign({}, notification),
              });
              Incomingvideocall.endIncomingcallAnswer(callUUID);
              clearTimeout(timer);
              Incomingvideocall.endAllCall();
            };
            const endIncomingCall = () => {
              Incomingvideocall.endAllCall();
            };
            Incomingvideocall.configure(incomingCallAnswer, endIncomingCall);
          } else if (type === "DISCONNECTED") {
            Incomingvideocall.endAllCall();
          }
          VoipPushNotification.onVoipNotificationCompleted(notification.uuid);
        });
    
        VoipPushNotification.addEventListener("didLoadWithEvents", (events) => {
          const  type  =  events.length != 0 && events[1]?.data?.type
          if (type === "Video") {
           
            Incomingvideocall.endAllCall();
            navigation.navigate('VideoScreen', {
              appointment: Object.assign({}, events.length != 0 ? events[1]?.data : {}),
            });
    
            const incomingCallAnswer = ({ callUUID }) => {
              navigation.navigate('VideoScreen', {
                appointment: Object.assign({}, events),
              });
              Incomingvideocall.endAllCall();
              Incomingvideocall.endIncomingcallAnswer(callUUID);
            
            };
    
            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中无法使用

工作呼叫在每个状态下都被杀死,后台或前台,但应用程序在接受呼叫后不会启动

xqnpmsa8

xqnpmsa81#

我的问题解决了,我只是将此代码添加到视频屏幕Incomingvideocall.endAllCall();'如果我们使用接受调用代码调用它,那么应用程序将无法打开,因为调用终止应用程序进程,因此将此行移动到下一个屏幕(视频屏幕)或显示和隐藏VoIP通知。从API端管理VoIP接受和拒绝

nom7f22z

nom7f22z2#

我也遇到过同样的问题,我需要等待导航启动后才能导航到CallScreen。
最新消息:

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

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

RNCallKeep.addEventListener('answerCall', rnCallKeepAnswerCall)
RNCallKeep.addEventListener('endCall', rnCallKeepEndCall)

相关问题