New Architecture Setup issue in iOS - Import RNCallKeep No such module
Closed this issue · 4 comments
Hello everyone.
I’m trying to integrate react-native-callkeep into my React Native iOS project, but I’m facing an issue when using Swift for AppDelegate.swift.
Environment
- React Native: 0.81.0
- react-native-callkeep: 4.3.16
- Xcode: e.g., 15.4
- CocoaPods: e.g., 1.15.2
- iOS: e.g., 17.5 (simulator & device)
- Device: e.g., iPhone 15 Pro simulator / physical device
- Hermes: On
- New Architecture (Fabric/Turbo): Disabled (also reproduced with Enabled)
I can update the above with exact numbers if needed, but the core issue reproduces consistently across our machines.
Current Behavior
Attempting to use CallKeep from a Swift AppDelegate.swift fails because the module cannot be imported or referenced from Swift:
- Using
import RNCallKeep→ Xcode reportsNo such module 'RNCallKeep'. - Using an Objective‑C bridging header to expose the header → Swift can compile the bridging header, but calls like
RNCallKeep.setup(...)in Swift produceUse of unresolved identifier 'RNCallKeep'or header-not-found errors depending on the header path tried.
This prevents initializing CallKeep in didFinishLaunchingWithOptions as shown in the Objective‑C example from the docs.
Expected Behavior
RNCallKeep should be consumable from Swift AppDelegate.swift either by:
- Importing as a Swift module (
import RNCallKeep), or - Via a documented bridging-header approach that reliably exposes
RNCallKeepto Swift.
Steps To Reproduce
- Create a new RN app with a Swift AppDelegate (or migrate AppDelegate to Swift).
Example:npx react-native@0.81.0 init CallKeepSwift --template react-native-template-typescriptand convert AppDelegate to Swift if needed. - Install the library:
yarn add react-native-callkeep@4.3.16. cd ios && pod install(autolinking picks up the pod).
Also tried explicitly adding the pod to Podfile; same result.- In
AppDelegate.swift, attempt to initialize CallKeep on launch (see snippet below).
Tried bothimport RNCallKeepand bridging-header imports. - Build the iOS app in Xcode → build fails with the errors shown below.
Code Snippets
AppDelegate.swift
import UIKit
import React
// Attempt 1: Import as a Swift module (fails)
import RNCallKeep // → No such module 'RNCallKeep'
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Attempt 2: Call via bridging header (fails at call site)
// Expectation: same as Objective‑C example [RNCallKeep setup:@{ @"appName": @"MyApp" }];
RNCallKeep.setup([
"appName": "MyApp",
"maximumCallGroups": 1,
"maximumCallsPerCallGroup": 1,
"supportsVideo": true
])
return true
}
}Bridging Header (when using bridging approach)
// MyApp-Bridging-Header.h
#import <RNCallKeep/RNCallKeep.h> // also tried "RNCallKeep.h"Podfile (relevant parts)
platform :ios, '13.0'
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
project 'MyApp', {
'Debug' => :debug,
'Release' => :release
}
# Tried with and without frameworks
use_frameworks! :linkage => :static # also tried removing this line entirely
target 'MyApp' do
config = use_native_modules!
use_react_native!(
:hermes_enabled => true,
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
# Autolinking picks up CallKeep; also tried explicitly adding:
# pod 'react-native-callkeep', :path => '../node_modules/react-native-callkeep'
post_install do |installer|
react_native_post_install(installer)
end
endBuild Output / Errors
/ios/MyApp/AppDelegate.swift:3:8: error: no such module 'RNCallKeep'
import RNCallKeep
^~~~~~~~~~
Use of unresolved identifier 'RNCallKeep'
'RNCallKeep/RNCallKeep.h' file not found
(Depending on whether the project uses use_frameworks!, the bridging header path, and cache state.)
What I Tried
- Cleaned build folder & deleted DerivedData.
pod deintegrate && pod install --repo-update.- Toggled
use_frameworks!(no line,:linkage => :static, and dynamic).
When enabled, Swift import still fails; when disabled, bridging header import sometimes finds the header butRNCallKeepremains unresolved in Swift. - Explicitly adding the pod (instead of relying on autolinking) → same result.
- Verified that
RNCallKeepappears inPods/and inPodfile.lockat version4.3.16.
Questions for Maintainers
- Is Swift import (
import RNCallKeep) officially supported for 4.3.16? If yes, what are the correct module name and Podspec settings for Swift consumption? - If the recommended path is a bridging header, what is the correct header path (
<RNCallKeep/RNCallKeep.h>vs"RNCallKeep.h"), and are the headers markedpublic_header_filesin the podspec so they're visible to Swift? - Are there known compatibility issues with React Native 0.81.x or with use_frameworks! that would prevent Swift import?
- Should initialization be done exclusively from JavaScript now (i.e.,
RNCallKeep.setup(...)on the JS side), and if so, can the iOS docs clarify what (if anything) must be done inAppDelegatewhen using Swift?
Additional Context
- The same project builds fine until adding the
RNCallKeepusage/import in Swift. - Other Objective‑C based RN pods are accessible from Swift in this project using the bridging-header approach.
Minimal Reproduction (optional)
I can provide a stripped repo if needed. Steps above reproduce consistently on a fresh RN 0.81 project with a Swift AppDelegate.
Thank you for maintaining this library! Happy to test any Podspec changes or provide more logs/screens if that helps.
you need to bridge the object c to switf, coz this is written in object c
I'm also getting same issue. is there any fix?
@elarafyarpit Here are the Steps
-
Create a bridging header file in the ios/appname folder.
-
Add the file path in Xcode → Build Settings → Swift Compiler – General → Objective-C Bridging Header (SWIFT_OBJC_BRIDGING_HEADER).
-
Add the following setup in your AppDelegate.swift:
import UIKit
import React_RCTAppDelegate
import ReactAppDependencyProvider
import UserNotifications
import Firebase
import RNBootSplash
import PushKit
import RNVoipPushNotification
// ❌ Do NOT import CallKeep here
@main
class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var reactNativeDelegate: ReactNativeDelegate?
var reactNativeFactory: RCTReactNativeFactory?
var voipRegistry: PKPushRegistry?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
// 🔹 Firebase
FirebaseApp.configure()
// 🔹 CallKeep setup
let localizedAppName = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String
let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String
RNCallKeep.setup([
"appName": localizedAppName ?? appName ?? "App",
"supportsVideo": true,
"includesCallsInRecents": false, // iOS 10+ only
])
// 🔹 VoIP Push registration
RNVoipPushNotificationManager.voipRegistration()
voipRegistry = PKPushRegistry(queue: .main)
voipRegistry?.delegate = self
voipRegistry?.desiredPushTypes = [.voIP]
// 🔹 Notifications delegate
UNUserNotificationCenter.current().delegate = self
// 🔹 React Native setup
let delegate = ReactNativeDelegate()
let factory = RCTReactNativeFactory(delegate: delegate)
delegate.dependencyProvider = RCTAppDependencyProvider()
reactNativeDelegate = delegate
reactNativeFactory = factory
window = UIWindow(frame: UIScreen.main.bounds)
factory.startReactNative(
withModuleName: "appName",
in: window,
launchOptions: launchOptions
)
return true
}
// MARK: - PushKit Delegates
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
RNVoipPushNotificationManager.didUpdate(credentials, forType: type.rawValue)
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
guard let stream = payload.dictionaryPayload["stream"] as? [String: Any],
let createdCallerName = stream["created_by_display_name"] as? String else {
completion()
return
}
let uuid = UUID().uuidString
let videoIncluded = stream["video"] as? String
let hasVideo = videoIncluded != "false"
RNVoipPushNotificationManager.addCompletionHandler(uuid, completionHandler: completion)
RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue)
// 🔹 CallKeep report
RNCallKeep.reportNewIncomingCall(
uuid,
handle: createdCallerName,
handleType: "generic",
hasVideo: hasVideo,
localizedCallerName: createdCallerName,
supportsHolding: false,
supportsDTMF: false,
supportsGrouping: false,
supportsUngrouping: false,
fromPushKit: true,
payload: stream,
withCompletionHandler: nil
)
}
// MARK: - Notifications
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound, .alert, .badge])
}
}
4. Important: Do not import CallKeep directly in AppDelegate.swift.
Here you go.....
@elarafyarpit Here are the Steps
- Create a bridging header file in the ios/appname folder.
- Add the file path in Xcode → Build Settings → Swift Compiler – General → Objective-C Bridging Header (SWIFT_OBJC_BRIDGING_HEADER).
- Add the following setup in your AppDelegate.swift:
import UIKit import React_RCTAppDelegate import ReactAppDependencyProvider import UserNotifications import Firebase import RNBootSplash import PushKit import RNVoipPushNotification // ❌ Do NOT import CallKeep here
@main class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate { var window: UIWindow? var reactNativeDelegate: ReactNativeDelegate? var reactNativeFactory: RCTReactNativeFactory? var voipRegistry: PKPushRegistry?
func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { // 🔹 Firebase FirebaseApp.configure()
// 🔹 CallKeep setup let localizedAppName = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String RNCallKeep.setup([ "appName": localizedAppName ?? appName ?? "App", "supportsVideo": true, "includesCallsInRecents": false, // iOS 10+ only ]) // 🔹 VoIP Push registration RNVoipPushNotificationManager.voipRegistration() voipRegistry = PKPushRegistry(queue: .main) voipRegistry?.delegate = self voipRegistry?.desiredPushTypes = [.voIP] // 🔹 Notifications delegate UNUserNotificationCenter.current().delegate = self // 🔹 React Native setup let delegate = ReactNativeDelegate() let factory = RCTReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() reactNativeDelegate = delegate reactNativeFactory = factory window = UIWindow(frame: UIScreen.main.bounds) factory.startReactNative( withModuleName: "appName", in: window, launchOptions: launchOptions ) return true}
// MARK: - PushKit Delegates func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { RNVoipPushNotificationManager.didUpdate(credentials, forType: type.rawValue) }
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { guard let stream = payload.dictionaryPayload["stream"] as? [String: Any], let createdCallerName = stream["created_by_display_name"] as? String else { completion() return }
let uuid = UUID().uuidString let videoIncluded = stream["video"] as? String let hasVideo = videoIncluded != "false" RNVoipPushNotificationManager.addCompletionHandler(uuid, completionHandler: completion) RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue) // 🔹 CallKeep report RNCallKeep.reportNewIncomingCall( uuid, handle: createdCallerName, handleType: "generic", hasVideo: hasVideo, localizedCallerName: createdCallerName, supportsHolding: false, supportsDTMF: false, supportsGrouping: false, supportsUngrouping: false, fromPushKit: true, payload: stream, withCompletionHandler: nil )}
// MARK: - Notifications func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.sound, .alert, .badge]) } } 4. Important: Do not import CallKeep directly in AppDelegate.swift.
Here you go.....
Okay, Thanks. It's working.