Flutter callkit
Flutter SDK for CallKit integration to Flutter applications on iOS
Flutter SDK for CallKit integration to Flutter applications on iOS The project is written primarily in Dart, distributed under the MIT License license, first published in 2020. Key topics include: callkit, client-sdk, flutter, ios, voip.
flutter_callkit_voximplant
Flutter SDK for CallKit integration to Flutter applications on iOS
Requirements
| Minimum version | |
|---|---|
| Flutter | 3.24.0 |
| Dart | 3.5.0 |
| iOS | 12.0 |
We wrote an article about the plugin - "How we make Flutter work with CallKit Call Directory".
Install
- Add
flutter_callkit_voximplantas a dependency in yourpubspec.yamlfile. - Add the following entry to your
Info.plistfile, located in<project root>/ios/Runner/Info.plist:
xml<key>UIBackgroundModes</key> <array> <string>voip</string> </array>
This entry required for CallKit to work
Usage
API of the SDK is designed as close as possible to CallKit iOS Framework.
CallKit documentation can be found here
A few differences explained:
- Use FlutterCallkitPlugin.sharedInstance.reportNewIncomingCallWithUUID: native iOS method to report new incoming call received via VoIP push notification
- Use FlutterCallkitPlugin.sharedInstance.hasCallWithUUID: native iOS method to check if CallKit already has a call with the given UUID
- Use FCXPlugin.didDisplayIncomingCall (dart) handle incoming call reported with reportNewIncomingCallWithUUID
- Use FCXPlugin.logLevel (dart) to adjust logging
- Use FCXPlugin.processPushCompletion (dart) to execute completion block received from push (iOS 11+ only)
- FCXCallController and FCXProvider are only allowed in single instance (use it as a singletone)
Note that UUID's passed to FCXProvider will be uppercased by the CallKit.
Initialization
dartimport 'package:flutter_callkit_voximplant/flutter_callkit_voximplant.dart'; // init main plugin class: FCXPlugin _plugin = FCXPlugin(); // init main CallKit classes: FCXProvider _provider = FCXProvider(); FCXCallController _callController = FCXCallController(); // at this point CallKit classes are not ready yet // configure it to use: try { await _callController.configure(); await _provider.configure(FCXProviderConfiguration('ExampleLocalizedName')); } catch (_) { // handle exception }
Making outgoing calls
To make an outgoing call, an app requests a FCXStartCallAction object from its FCXCallController object.
The action consists of a UUID to uniquely identify the call and a FCXHandle object to specify the recipient.
dartFuture<void> makeCall(String contactName, String uuid) async { FCXHandle handle = FCXHandle(FCXHandleType.Generic, contactName); FCXStartCallAction action = FCXStartCallAction(uuid, handle); await _callController.requestTransactionWithAction(action); }
After the call is connected, the system calls the provider's performStartCallAction method. In your implementation,
this method is responsible for configuring an AVAudioSession and calling fulfill() on the action when finished.
dart_provider.performStartCallAction = (startCallAction) async { // configure audio session await startCallAction.fulfill(); };
Receiving an Incoming Call
Using the information provided by the external notification,
the app creates a UUID and a CXCallUpdate object to uniquely identify the call and the caller,
and passes them both to the provider using the reportNewIncomingCall() method.
dartFuture<void> handleIncomingCall(String contactName, String uuid) async { FCXCallUpdate callUpdate = FCXCallUpdate(localizedCallerName: contactName); await _provider.reportNewIncomingCall(uuid, callUpdate); }
After the recipient answers the call, the system calls the performAnswerCallAction method of the provider.
In your implementation of that method, configure an AVAudioSession and call the fulfill() method
on the action object when finished.
dart_provider.performAnswerCallAction = (answerCallAction) async { // configure audio session await answerCallAction.fulfill(); };
Handling push notifications
Note: This SDK is not related to PushKit
Push handling must be done through native iOS code due to iOS 13 PushKit VoIP restrictions.
Flutter CallKit SDK has built-in reportNewIncomingCallWithUUID:callUpdate:providerConfiguration:pushProcessingCompletion:) method (iOS) to correctly work with it
Swift
swiftimport Flutter import flutter_callkit_voximplant import PushKit import CallKit class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate { // 1. override PKPushRegistryDelegate methods func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType ) { processPush(with: payload.dictionaryPayload, and: nil) } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void ) { processPush(with: payload.dictionaryPayload, and: completion) } // 2. process push private func processPush(with payload: Dictionary<AnyHashable, Any>, and completion: (() -> Void)? ) { // 3. get uuid and other needed information from payload guard let uuidString = payload["UUID"] as? String, let uuid = UUID(uuidString: uuidString), let localizedName = payload["identifier"] as? String else { return } // 4. prepare call update let callUpdate = CXCallUpdate() callUpdate.localizedCallerName = localizedName // 5. prepare provider configuration let configuration = CXProviderConfiguration(localizedName: "ExampleLocalizedName") // 6. send it to the plugin FlutterCallkitPlugin.sharedInstance.reportNewIncomingCall( with: uuid, callUpdate: callUpdate, providerConfiguration: configuration, pushProcessingCompletion: completion ) } }
Objective-C
objective#import <Flutter/Flutter.h> #import <FlutterCallkitPlugin.h> #import <PushKit/PushKit.h> #import <CallKit/CallKit.h> @interface AppDelegate : FlutterAppDelegate<PKPushRegistryDelegate> @end @implementation AppDelegate // 1. override PKPushRegistryDelegate methods - (void) pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type { [self processPushWithPayload:payload.dictionaryPayload andCompletionHandler:nil]; } - (void) pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { [self processPushWithPayload:payload.dictionaryPayload andCompletionHandler:completion]; } // 2. process push -(void)processPushWithPayload:(NSDictionary *)payload andCompletionHandler:(dispatch_block_t)completion { // 3. get uuid and other needed information from payload NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:payload[@"UUID"]]; NSString *localizedName = payload[@"identifier"]; // 4. prepare call update CXCallUpdate *callUpdate = [CXCallUpdate new]; callUpdate.localizedCallerName = localizedName; // 5. prepare provider configuration CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:@"ExampleLocalizedName"]; // 6. send it to plugin [FlutterCallkitPlugin.sharedInstance reportNewIncomingCallWithUUID:UUID callUpdate:callUpdate providerConfiguration:configuration pushProcessingCompletion:completion]; } @end
At this point CallKit will be set up to handle incoming call and will present its UI.
didDisplayIncomingCall of FCXPlugin will be called in dart code.
Call processPushCompletion from dart code once call successfully connected.
Call Blocking and Identification
Apps can create a Call Directory app extension to identify and block incoming callers by their phone number.
When a phone number is blocked, the system telephony provider will disallow incoming calls
from that phone number without displaying them to the user.
When a phone number has an identification entry, incoming calls from that phone number will display
its associated label to the user.
To integrate CallDirectory App Extension functionality to an Flutter application,
it is required:
- add a CallDirectory Extenstion to the XCode project.
- implement data storage for blocked and/or identifiable numders
in the native iOS code and connect it with CallDirectory Extension. - assign
FlutterCallkitPluginCallDirectory related properties with
functions that access numbers storage.
More on the CallDirectory App Extension
Example App with CallDirectory App Extension implemented
Reference
iOS CallKit Framework Documentation by Apple: https://developer.apple.com/documentation/callkit
Contributors
Showing top 6 contributors by commit count.
