Let's integrate our UIKIT in few minutes

Notification Configuration#

iOS configuration#

Step 1: Open Info.plist file and add the notification related code as mentioned below.

...
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>remote-notification</string>
<string>voip</string>
</array>
...

Step 2: Enable the following options to receive push notification when app is in background/killed.

  1. Open Xcode -> Signing & Capabilities -> Background Modes. Make sure you enabled the following checkboxes background-modes-options

Step 3: Go to Xcode -> Signing & Capabilities. Click + Capabality on the top left corner of the sub window. And serach for Push Notification and add it.

Note: Ignore this step if you already have Push Notificiation option.

ad-capabality

push-notification-option

Step 4: Create the bridge header file like <PROJECT_NAME>-Bridging-Header.h file.
Use this file to import your target's public headers that you would like to expose to Swift.

#import "RNCallKeep.h"
#import "RNKeyEvent.h"

Step 5: Open AppDelegate and add the below mentioned codes.

...
// add the below imports
import CallKit
import RNVoipPushNotification
import UserNotifications
...
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
...
// VoIP PushKit registration
RNVoipPushNotificationManager.voipRegistration() // <- add this line just before the below line
...
}
// MARK: - VoIP PushKit
// VoIP configuration section starts here
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
RNVoipPushNotificationManager.didUpdate(pushCredentials, forType: type.rawValue)
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
// --- 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.
}
// --- Handle incoming pushes
func pushRegistry(
_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType,
completion: @escaping () -> Void
) {
// --- NOTE: apple forced us to invoke callkit ASAP when we receive voip push
// --- see: react-native-callkeep
// --- Retrieve information from your voip push payload
let uuid = UUID().uuidString
let payloadDict = payload.dictionaryPayload
let handle = payloadDict["caller_id"] as? String ?? "unknown@mirrorfly"
let callerId = handle.components(separatedBy: "@").first ?? "unknown"
let callerName = payloadDict["caller_name"] as? String ?? callerId
let hasVideoValue = payloadDict["call_type"] as? String ?? "audio"
let hasVideo = (hasVideoValue == "video")
let callObserver = CXCallObserver()
let activeCallCount = callObserver.calls.count
// --- this is optional, only required if you want to call `completion()` on the js side
RNVoipPushNotificationManager.addCompletionHandler(uuid, completionHandler: completion)
if activeCallCount < 1 {
// Check the Mic permission and if the permission is not provided then end the call
RNCallKeep.reportNewIncomingCall(
uuid,
handle: callerId,
handleType: "generic",
hasVideo: hasVideo,
localizedCallerName: callerName,
supportsHolding: true,
supportsDTMF: true,
supportsGrouping: true,
supportsUngrouping: true,
fromPushKit: true,
payload: payloadDict,
withCompletionHandler: completion
)
if hasVideo ? !checkVideoPermission() : !checkAudioPermission() {
RNCallKeep.endCall(withUUID: uuid, reason: 1)
// Showing local notification for the ended incoming call
let content = UNMutableNotificationContent()
content.title = callerId
content.body = "You missed \(hasVideo ? "a" : "an") \(hasVideo ? "video call" : "audio call"). Please enable permission in App Settings."
content.sound = .default
let request = UNNotificationRequest(identifier: "ImmediateNotification", content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Notification error: \(error)")
}
}
}
} else {
// --- sending the received push to JS for the incoming call (while the user is already on a call) to send busy status to the caller
RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue)
}
// --- You don't need to call it if you stored `completion()` and will call it on the js side.
completion()
}
// MARK: - Permissions
func checkAudioPermission() -> Bool {
let status = AVCaptureDevice.authorizationStatus(for: .audio)
if status != .authorized {
if status == .notDetermined {
AVCaptureDevice.requestAccess(for: .audio) { _ in }
}
return false
}
return true
}
func checkVideoPermission() -> Bool {
let micStatus = AVCaptureDevice.authorizationStatus(for: .audio)
let videoStatus = AVCaptureDevice.authorizationStatus(for: .video)
if videoStatus != .authorized || micStatus != .authorized {
if videoStatus == .notDetermined {
AVCaptureDevice.requestAccess(for: .video) { _ in }
}
if micStatus == .notDetermined {
AVCaptureDevice.requestAccess(for: .audio) { _ in }
}
return false
}
return true
}
// VoIP configuration section ends here
@end