{"id":27999252,"url":"https://github.com/voximplant/flutter_callkit","last_synced_at":"2025-07-09T20:32:31.975Z","repository":{"id":37082346,"uuid":"249414563","full_name":"voximplant/flutter_callkit","owner":"voximplant","description":"Flutter SDK for CallKit integration to Flutter applications on iOS","archived":false,"fork":false,"pushed_at":"2022-06-17T16:20:33.000Z","size":967,"stargazers_count":54,"open_issues_count":9,"forks_count":19,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-05-08T22:57:30.306Z","etag":null,"topics":["callkit","client-sdk","flutter","ios","voip","voximplant"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voximplant.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-23T11:39:31.000Z","updated_at":"2025-01-23T15:49:15.000Z","dependencies_parsed_at":"2022-08-19T06:30:41.590Z","dependency_job_id":null,"html_url":"https://github.com/voximplant/flutter_callkit","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/voximplant/flutter_callkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voximplant%2Fflutter_callkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voximplant%2Fflutter_callkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voximplant%2Fflutter_callkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voximplant%2Fflutter_callkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voximplant","download_url":"https://codeload.github.com/voximplant/flutter_callkit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voximplant%2Fflutter_callkit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264502662,"owners_count":23618669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["callkit","client-sdk","flutter","ios","voip","voximplant"],"created_at":"2025-05-08T22:57:27.598Z","updated_at":"2025-07-09T20:32:31.944Z","avatar_url":"https://github.com/voximplant.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flutter_callkit_voximplant\n\nFlutter SDK for CallKit integration to Flutter applications on iOS\n\nSupported on iOS \u003e= 10\n\n\u003e We wrote an article about the plugin - \"How we make Flutter work with CallKit Call Directory\".\n\u003e\n\u003e Available on [English](https://dev.to/imaximova/how-we-make-flutter-work-with-callkit-call-directory-5334) and [Russian](https://habr.com/ru/company/Voximplant/blog/553422/) languages.\n\n## Install\n\n1. Add `flutter_callkit_voximplant` as a dependency in your pubspec.yaml file.\n\n2. Add the following entry to your `Info.plist` file, located in `\u003cproject root\u003e/ios/Runner/Info.plist`:\n\n```xml\n\u003ckey\u003eUIBackgroundModes\u003c/key\u003e\n\u003carray\u003e\n  \u003cstring\u003evoip\u003c/string\u003e\n\u003c/array\u003e\n```\n\nThis entry required for CallKit to work\n\n## Usage\n\nAPI of the SDK is designed as close as possible to CallKit iOS Framework.\n\nCallKit documentation can be found [here](https://developer.apple.com/documentation/callkit)\n\nA few differences explained:\n\n- Use FlutterCallkitPlugin.sharedInstance.reportNewIncomingCallWithUUID: native iOS method to report new incoming call received via VoIP push notification\n- Use FlutterCallkitPlugin.sharedInstance.hasCallWithUUID: native iOS method to check if CallKit already has a call with the given UUID\n- Use FCXPlugin.didDisplayIncomingCall (dart) handle incoming call reported with reportNewIncomingCallWithUUID\n- Use FCXPlugin.logLevel (dart) to adjust logging\n- Use FCXPlugin.processPushCompletion (dart) to execute completion block received from push (iOS 11+ only)\n- FCXCallController and FCXProvider are only allowed in single instance (use it as a singletone)\n\nNote that UUID's passed to FCXProvider will be uppercased by the CallKit.\n\n### Initialization\n\n```dart\nimport 'package:flutter_callkit_voximplant/flutter_callkit_voximplant.dart';\n\n// init main plugin class:\nFCXPlugin _plugin = FCXPlugin();\n// init main CallKit classes:\nFCXProvider _provider = FCXProvider();\nFCXCallController _callController = FCXCallController();\n// at this point CallKit classes are not ready yet\n// configure it to use:\ntry {\n  await _callController.configure();\n  await _provider.configure(FCXProviderConfiguration('ExampleLocalizedName'));\n} catch (_) {\n  // handle exception\n}\n```\n\n### Making outgoing calls\n\nTo make an outgoing call, an app requests a FCXStartCallAction object from its FCXCallController object.\nThe action consists of a UUID to uniquely identify the call and a FCXHandle object to specify the recipient.\n\n```dart\nFuture\u003cvoid\u003e makeCall(String contactName, String uuid) async {\n  FCXHandle handle = FCXHandle(FCXHandleType.Generic, contactName);\n  FCXStartCallAction action = FCXStartCallAction(uuid, handle);\n  await _callController.requestTransactionWithAction(action);\n}\n```\n\nAfter the call is connected, the system calls the provider's performStartCallAction method. In your implementation, \nthis method is responsible for configuring an AVAudioSession and calling fulfill() on the action when finished.\n\n```dart\n_provider.performStartCallAction = (startCallAction) async {\n  // configure audio session\n  await startCallAction.fulfill();\n};\n```\n\n### Receiving an Incoming Call\n\nUsing the information provided by the external notification, \nthe app creates a UUID and a CXCallUpdate object to uniquely identify the call and the caller,\nand passes them both to the provider using the reportNewIncomingCall() method.\n\n```dart\nFuture\u003cvoid\u003e handleIncomingCall(String contactName, String uuid) async {\n  FCXCallUpdate callUpdate = FCXCallUpdate(localizedCallerName: contactName);\n  await _provider.reportNewIncomingCall(uuid, callUpdate);\n}\n```\n\nAfter the recipient answers the call, the system calls the performAnswerCallAction method of the provider.\nIn your implementation of that method, configure an AVAudioSession and call the fulfill() method\non the action object when finished.\n\n```dart\n_provider.performAnswerCallAction = (answerCallAction) async {\n  // configure audio session\n  await answerCallAction.fulfill();\n};\n```\n\n### Handling push notifications\n\nNote: This SDK is not related to PushKit\n\nPush handling must be done through native iOS code due to [iOS 13 PushKit VoIP restrictions](https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry).\n\nFlutter CallKit SDK has built-in reportNewIncomingCallWithUUID:callUpdate:providerConfiguration:pushProcessingCompletion:) method (iOS) to correctly work with it\n\n#### Swift\n\n```swift\nimport Flutter\nimport flutter_callkit_voximplant\nimport PushKit\nimport CallKit\n\nclass AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate {\n    // 1. override PKPushRegistryDelegate methods\n    func pushRegistry(_ registry: PKPushRegistry,\n                      didReceiveIncomingPushWith payload: PKPushPayload,\n                      for type: PKPushType\n    ) {\n        processPush(with: payload.dictionaryPayload, and: nil)\n    }\n\n    func pushRegistry(_ registry: PKPushRegistry,\n                      didReceiveIncomingPushWith payload: PKPushPayload,\n                      for type: PKPushType,\n                      completion: @escaping () -\u003e Void\n    ) {\n        processPush(with: payload.dictionaryPayload, and: completion)\n    }\n\n    // 2. process push\n    private func processPush(with payload: Dictionary\u003cAnyHashable, Any\u003e,\n                             and completion: (() -\u003e Void)?\n    ) {\n        // 3. get uuid and other needed information from payload\n        guard let uuidString = payload[\"UUID\"] as? String,\n            let uuid = UUID(uuidString: uuidString),\n            let localizedName = payload[\"identifier\"] as? String\n            else {\n                return\n        }\n        // 4. prepare call update\n        let callUpdate = CXCallUpdate()\n        callUpdate.localizedCallerName = localizedName\n        // 5. prepare provider configuration\n        let configuration = CXProviderConfiguration(localizedName: \"ExampleLocalizedName\")\n        // 6. send it to the plugin\n        FlutterCallkitPlugin.sharedInstance.reportNewIncomingCall(\n            with: uuid,\n            callUpdate: callUpdate,\n            providerConfiguration: configuration,\n            pushProcessingCompletion: completion\n        )\n    }\n}\n```\n\n#### Objective-C\n\n```objective-c\n#import \u003cFlutter/Flutter.h\u003e\n#import \u003cFlutterCallkitPlugin.h\u003e\n#import \u003cPushKit/PushKit.h\u003e\n#import \u003cCallKit/CallKit.h\u003e\n\n@interface AppDelegate : FlutterAppDelegate\u003cPKPushRegistryDelegate\u003e\n\n@end\n\n@implementation AppDelegate\n\n// 1. override PKPushRegistryDelegate methods\n- (void)             pushRegistry:(PKPushRegistry *)registry\ndidReceiveIncomingPushWithPayload:(PKPushPayload *)payload\n                          forType:(PKPushType)type {\n    [self processPushWithPayload:payload.dictionaryPayload \n            andCompletionHandler:nil];\n}\n\n- (void)             pushRegistry:(PKPushRegistry *)registry\ndidReceiveIncomingPushWithPayload:(PKPushPayload *)payload\n                          forType:(PKPushType)type\n            withCompletionHandler:(void (^)(void))completion {\n    [self processPushWithPayload:payload.dictionaryPayload\n            andCompletionHandler:completion];\n}\n\n// 2. process push\n-(void)processPushWithPayload:(NSDictionary *)payload\n         andCompletionHandler:(dispatch_block_t)completion {\n    // 3. get uuid and other needed information from payload\n    NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:payload[@\"UUID\"]];\n    NSString *localizedName = payload[@\"identifier\"];\n    // 4. prepare call update\n    CXCallUpdate *callUpdate = [CXCallUpdate new];\n    callUpdate.localizedCallerName = localizedName;\n    // 5. prepare provider configuration\n    CXProviderConfiguration *configuration =\n        [[CXProviderConfiguration alloc]\n              initWithLocalizedName:@\"ExampleLocalizedName\"];\n    // 6. send it to plugin\n    [FlutterCallkitPlugin.sharedInstance reportNewIncomingCallWithUUID:UUID\n                                                            callUpdate:callUpdate\n                                                 providerConfiguration:configuration\n                                              pushProcessingCompletion:completion];\n}\n@end\n```\n\nAt this point CallKit will be set up to handle incoming call and will present its UI.\n\ndidDisplayIncomingCall of FCXPlugin will be called in dart code.\n\nCall processPushCompletion from dart code once call successfully connected.\n\n### Call Blocking and Identification\n\nApps can create a Call Directory app extension to identify and block incoming callers by their phone number.\n\n\u003e When a phone number is blocked, the system telephony provider will disallow incoming calls \nfrom that phone number without displaying them to the user.\n\n\u003e When a phone number has an identification entry, incoming calls from that phone number will display \nits associated label to the user.\n\nTo integrate CallDirectory App Extension functionality to an Flutter application,\nit is required:\n- add a CallDirectory Extenstion to the XCode project.\n- implement data storage for blocked and/or identifiable numders\n  in the native iOS code and connect it with CallDirectory Extension.\n- assign `FlutterCallkitPlugin` CallDirectory related properties with\n  functions that access numbers storage.\n  \n[More on the CallDirectory App Extension](doc/call_directory/README.md)\n\n[Example App with CallDirectory App Extension implemented](example/)\n\n### Reference\niOS CallKit Framework Documentation by Apple: https://developer.apple.com/documentation/callkit","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoximplant%2Fflutter_callkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoximplant%2Fflutter_callkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoximplant%2Fflutter_callkit/lists"}