CallKit Integration

Introduction

CallKit allows us to have system-level phone integration on iOS. With that, we can use CallKit to present native incoming call screens, even when the app is closed. CallKit integration also enables the calls made through third-party apps be displayed in the phone’s recent call list in the Phone app.

The StreamVideo SDK is compatible with CallKit, enabling a complete calling experience for your users.

Make sure you created APNs provider and configured push notification manager as described in this section.

Add camera and microphone permissions

Add these permissions to Info.plist in order to support video calling:

<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your camera for video calls.</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your microphone for voice and video calls.</string>

Enable background modes capabilities

To maintain connectivity, handle incoming calls, and manage ongoing calls when the app is not in the foreground, you can enable iOS background modes. These modes ensure your app remains responsive to call events without being suspended by the system.

Enabling Background Modes in Xcode

  • Open your app’s project in Xcode.

  • Select your app’s target.

  • Navigate to the Signing & Capabilities tab.

  • In the Background Modes section, enable the following options:

    • “Voice over IP”
    • “Remote notifications”
    • “Background processing”

Background modes

Adding Background Modes to Info.plist

Alternatively, you can directly configure the necessary background modes in your app’s Info.plist file by adding the following keys:

<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
	 <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
<key>UIBackgroundModes</key>
<array>
	<string>audio</string>
	<string>processing</string>
	<string>remote-notification</string>
	<string>voip</string>
</array>

Ensure Push Notification Capabilities

To properly receive VoIP and remote push notifications, you need to enable the Push Notifications capability in Xcode:

  1. Open your app’s project in Xcode.
  2. Select your app’s target.
  3. Navigate to the Signing & Capabilities tab.
  4. Click the + Capability button.
  5. Search for Push Notifications and add it.

Make sure your app has Push Notification Capabilities set in Signing & Capabilieties.

Handling CallKit events (common for iOS and Android)

CallKit events are exposed by the flutter_callkit_incoming package that we utilize to handle incoming calls on both iOS and Android. It is important to handle these events to ensure a seamless calling experience regardless of which provider is used for push.

In a high-level widget in your app, add this code to listen to CallKit events:

import 'package:rxdart/rxdart.dart';

final _compositeSubscription = CompositeSubscription();

@override
void initState() {
  ...
  _observeCallKitEvents()
}

void _observeCallKitEvents() {
  final streamVideo = StreamVideo.instance;

  // You can use our helper method to observe core CallKit events
  // It will handled call accepted, declined and ended events
  _compositeSubscription.add(
      streamVideo.observeCoreCallKitEvents(
        onCallAccepted: (callToJoin) {
            // Replace with navigation flow of your choice
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => CallScreen()),
            );
        },
      ),
    );

  // Or you can handle them by yourself, and/or add additional events such as handling mute events from CallKit
  // _compositeSubscription.add(streamVideo.onCallKitEvent<ActionCallToggleMute>(_onCallToggleMute));
}

@override
void dispose() {
  // ...
  _compositeSubscription.cancelAll();
}

If you need to manage the ringing flow call, you can use the StreamVideo.pushNotificationManager. As an example, let’s say you want to end all calls, you can end them this way:

StreamVideo.instance.pushNotificationManager?.endAllCalls();

Add native code to the iOS project

In your iOS project, add the following imports to your AppDelegate.swift:

import UIKit
import Flutter
import stream_video_push_notification

In the same file, add an extra line to your AppDelegate class which registers the app for push notifications:

override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    // Register for push notifications.
    StreamVideoPKDelegateManager.shared.registerForPushNotifications()

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

You should now be able to receive a ringing call on iOS.

To test this:

  • Create a ringing call on another device (as describe in previous section).
  • Add the ID of a user logged into the iOS device to the memberIds array in the call.getOrCreate(ringing: true, memberIds: [{ID}]) method.
  • You should see the CallKit ringing notification on the iOS device.

If you encounter any issues, refer to the Troubleshooting section for solutions to common mistakes.

© Getstream.io, Inc. All Rights Reserved.