You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS后台/终止状态下react-native-callkeep无法正常工作

iOS后台/终止状态下react-native-callkeep无法触发来电显示问题

我在React Native项目中使用react-native-callkeep库结合Firebase通知实现来电显示功能,应用处于前台时功能完全正常,但在iOS设备上,当应用处于后台或被终止状态时,无法显示来电界面,也无法唤醒应用。

注:Firebase通知本身在Android和iOS平台均能正常接收。


相关代码文件

AppDelegate.m

#import "AppDelegate.h"
#import "Adjust.h"
#import "Firebase.h"
#import <UserNotifications/UserNotifications.h>
#import <FirebaseMessaging/FirebaseMessaging.h>
#import "FirebaseCore.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNCallKeep.h"
#import <React/RCTLinkingManager.h>
#import <PushKit/PushKit.h>
#import "RNVoipPushNotificationManager.h"
#import <RNCPushNotificationIOS.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [FIRApp configure];
  [RNCallKeep setup:@{@"appName": @"DocMoonlight", @"maximumCallGroups": @3, @"maximumCallsPerCallGroup": @1, @"supportsVideo": @YES}];
  [RNVoipPushNotificationManager voipRegistration];
  // other initialization code
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
  [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
  NSString *uuid = [[[NSUUID UUID] UUIDString] lowercaseString];
  [RNCallKeep reportNewIncomingCall:uuid handle:@"unknown" handleType:@"generic" hasVideo:NO localizedCallerName:@"Unknown" supportsHolding:YES supportsDTMF:YES supportsGrouping:YES supportsUngrouping:YES fromPushKit:YES payload:nil withCompletionHandler:completion];
}
@end

React Native端(App.js)

const options = {
  ios: {
    appName: 'DocMoonlight',
  },
  android: {
    alertTitle: 'Permissions required',
    alertDescription: 'This application needs to access your phone accounts',
    cancelButton: 'Cancel',
    okButton: 'ok',
    imageName: '',
    additionalPermissions: [],
    foregroundService: {
      channelId: 'com.docmoonlight',
      channelName: 'Foreground service for my app',
      notificationTitle: 'My app is running on background',
      notificationIcon: 'ic_notification',
    },
  },
};

CallKeep.setup(options).then(() => {});
CallKeep.setAvailable(true);

通知处理逻辑代码

async function onMessageReceived(remoteMessage) {
  if (remoteMessage.data?.type === 'video_call') {    
    const callUUID = uuidv4();

    CallKeep.displayIncomingCall(
      callUUID,
      remoteMessage.data?.location,
      'Docmoonlight',
      'generic',
      true,
    );

    // Listen to the CallKeep events
    CallKeep.addEventListener('answerCall', async ({callUUID}) => {
      bringAppToForeground();
      CallKeep.endCall(callUUID);

      setTimeout(async () => {
        if (remoteMessage.data) {
          const zoomLink = remoteMessage.data;

          try {
            const jwtToken = generateSignature(zoomLink.meetingNumber);
            await ZoomUs.initialize({
              jwtToken,
            })
              .then(result => {
                console.log(result);

                try {
                  ZoomUs.joinMeeting({
                    userName: zoomLink.name,
                    meetingNumber: zoomLink.meetingNumber,
                    password: zoomLink.password,
                  });
                } catch (error) {
                  console.error('Failed to join the meeting', error);
                }
              })
              .catch(error => console.log('Failed to initialize', error));
          } catch (error) {
            console.log(error);
          }
        }
      }, 1000);
    });

    CallKeep.addEventListener('endCall', ({callUUID}) => {
      console.log('Call ended:', callUUID);
      CallKeep.endCall(callUUID);
    });
  } else {    
    onDisplayNotification(
      remoteMessage.notification?.title,
      remoteMessage.notification?.body,
      remoteMessage.messageId,
    );
  }
}

Podfile

require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, min_ios_version_supported
prepare_react_native_project!
source 'https://github.com/CocoaPods/Specs.git'

# Disable Flipper temporarily
flipper_config = FlipperConfiguration.disabled

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end

target 'DocMoonlight' do
  config = use_native_modules!
  
  pod 'Firebase', :modular_headers => true
  pod 'FirebaseCoreInternal', :modular_headers => true
  pod 'GoogleUtilities', :modular_headers => true
  pod 'FirebaseCore', :modular_headers => true

  pod 'RNPermissions', :path => '../node_modules/react-native-permissions'
  permissions_path = '../node_modules/react-native-permissions/ios'
  pod 'FirebaseInstallations', :modular_headers => true
  pod 'FirebaseCoreExtension', :modular_headers => true
  pod 'GoogleDataTransport', :modular_headers => true
  pod 'nanopb', :modular_headers => true
  pod 'RNCallKeep', :path => '../node_modules/react-native-callkeep'

  # Flags change depending on the env values.
  flags = get_default_flags()

  use_react_native!(
    :path => config[:reactNativePath],
    :hermes_enabled => flags[:hermes_enabled],
    :fabric_enabled => flags[:fabric_enabled],
    :flipper_configuration => flipper_config,
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

  target 'DocMoonlightTests' do
    inherit! :complete
  end

  post_install do |installer|
    react_native_post_install(
      installer,
      :mac_catalyst_enabled => false
    )
  end
end

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>com.docmoonlight.app.fetch-updates</string>
    </array>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleDisplayName</key>
    <string>Docmoonlight</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>$(MARKETING_VERSION)</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>$(CURRENT_PROJECT_VERSION)</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>localhost</key>
            <dict>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>
    <key>NSBluetoothPeripheralUsageDescription</key>
    <string>We will use your Bluetooth to access your Bluetooth headphones.</string>
    <key>NSCameraUsageDescription</key>
    <string>For people to see you during meetings, we need access to your camera.</string>
    <key>NSDocumentsFolderUsageDescription</key>
    <string>Docmoonlight's app requires access to your Documents Folder to allow you to upload necessary documents and files, such as proof of medical licensing or certifications, during the registration process</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Docmoonlight's app requires access to your location while in use to provide  accurate clock-in and clock-out times for payment purposes. </string>
    <key>NSMicrophoneUsageDescription</key>
    <string>For people to hear you during meetings, we need access to your microphone.</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Docmoonlight's app requires access to your Photo Library and file storage to allow you to upload necessary documents and files, such as proof of medical licensing or certifications, during the registration process</string>
    <key>UIAppFonts</key>
    <array>
        <string>Poppins-Medium.ttf</string>
        <string>Poppins-Regular.ttf</string>
        <string>Poppins-SemiBold.ttf</string>
        <string>AntDesign.ttf</string>
        <string>Entypo.ttf</string>
        <string>EvilIcons.ttf</string>
        <string>Feather.ttf</string>
        <string>FontAwesome.ttf</string>
        <string>FontAwesome5_Brands.ttf</string>
        <string>FontAwesome5_Regular.ttf</string>
        <string>FontAwesome5_Solid.ttf</string>
        <string>Foundation.ttf</string>
        <string>Ionicons.ttf</string>
        <string>MaterialIcons.ttf</string>
        <string>MaterialCommunityIcons.ttf</string>
        <string>SimpleLineIcons.ttf</string>
        <string>Octicons.ttf</string>
        <string>Zocial.ttf</string>
        <string>FontAwesome6_Regular.ttf</string>
        <string>FontAwesome6_Solid.ttf</string>
        <string>FontAwesome6_Brands.ttf</string>
    </array>
    <key>UIBackgroundModes</key>
    <array>
        <string>audio</string>
        <string>fetch</string>
        <string>remote-notification</string>
        <string>voip</string>
    </array>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>armv7</string>
    </array>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
        <string>UIInterfaceOrientationPortrait</string>
    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
</dict>
</plist>

我已经尝试了多种方法,但问题仍未解决。


内容的提问来源于stack exchange,提问作者Kero Fawzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:09:52