Flutter Callkit Incoming

A Flutter plugin to show incoming call in your Flutter app(Custom for Android/Callkit for iOS).

pub package Build Status

:star: Features

  • Show an incoming call

  • Start an outgoing call

  • Custom UI Android/Callkit for iOS

  • Example using Pushkit/VoIP for iOS

iOS: ONLY WORKING ON REAL DEVICE, not on simulator(Callkit framework not working on simulator)

🚀  Installation

  1. Install Packages
  • Run this command:
    flutter pub add billtech_incoming_call
  • Add pubspec.yaml:
          billtech_incoming_call: any
  1. Configure Project
  • Android
    • AndroidManifest.xml
             Using for load image from internet
         <uses-permission android:name="android.permission.INTERNET"/>
  • iOS
    • Info.plist
  1. Usage
  • Import

    import 'package:billtech_incoming_call/billtech_incoming_call.dart';
  • Received an incoming call

      this._currentUuid = _uuid.v4();
      var params = <String, dynamic>{
        'id': _currentUuid,
        'nameCaller': 'Hien Nguyen',
        'appName': 'Callkit',
        'avatar': 'https://i.pravatar.cc/100',
        'handle': '0123456789',
        'type': 0,
        'textAccept': 'Accept',
        'textDecline': 'Decline',
        'textMissedCall': 'Missed call',
        'textCallback': 'Call back',
        'duration': 30000,
        'extra': <String, dynamic>{'userId': '1a2b3c4d'},
        'headers': <String, dynamic>{'apiKey': 'Abc@123!', 'platform': 'flutter'},
        'android': <String, dynamic>{
          'isCustomNotification': true,
          'isShowLogo': false,
          'isShowCallback': false,
          'isShowMissedCallNotification': true,
          'ringtonePath': 'system_ringtone_default',
          'backgroundColor': '#0955fa',
          'backgroundUrl': 'https://i.pravatar.cc/500',
          'actionColor': '#4CAF50'
        'ios': <String, dynamic>{
          'iconName': 'CallKitLogo',
          'handleType': 'generic',
          'supportsVideo': true,
          'maximumCallGroups': 2,
          'maximumCallsPerCallGroup': 1,
          'audioSessionMode': 'default',
          'audioSessionActive': true,
          'audioSessionPreferredSampleRate': 44100.0,
          'audioSessionPreferredIOBufferDuration': 0.005,
          'supportsDTMF': true,
          'supportsHolding': true,
          'supportsGrouping': false,
          'supportsUngrouping': false,
          'ringtonePath': 'system_ringtone_default'
      await BilltechIncomingCall.showCallkitIncoming(params);
  • Show miss call notification

      this._currentUuid = _uuid.v4();
      var params = <String, dynamic>{
        'id': this._currentUuid,
        'nameCaller': 'Hien Nguyen',
        'handle': '0123456789',
        'type': 1,
        'textMissedCall': 'Missed call',
        'textCallback': 'Call back',
        'extra': <String, dynamic>{'userId': '1a2b3c4d'},
      await BilltechIncomingCall.showMissCallNotification(params);
  • Started an outgoing call

      this._currentUuid = _uuid.v4();
      var params = <String, dynamic>{
        'id': this._currentUuid,
        'nameCaller': 'Hien Nguyen',
        'handle': '0123456789',
        'type': 1,
        'extra': <String, dynamic>{'userId': '1a2b3c4d'},
        'ios': <String, dynamic>{'handleType': 'generic'}
      await BilltechIncomingCall.startCall(params);
  • Ended an incoming/outgoing call

      var params = <String, dynamic>{'id': this._currentUuid};
      await BilltechIncomingCall.endCall(params);
  • Ended all calls

      await BilltechIncomingCall.endAllCalls();
  • Get active calls. iOS: return active calls from Callkit, Android: only return last call

      await BilltechIncomingCall.activeCalls();


    [{"id": "8BAA2B26-47AD-42C1-9197-1D75F662DF78", ...}]
  • Get device push token VoIP. iOS: return deviceToken, Android: Empty

      await BilltechIncomingCall.getDevicePushTokenVoIP();


    <device token>

    Make sure using SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken) inside AppDelegate.swift (Example)

    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
        let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
        //Save deviceToken to your server
    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
  • Listen events

      BilltechIncomingCall.onEvent.listen((event) {
        switch (event!.name) {
          case CallEvent.ACTION_CALL_INCOMING:
            // TODO: received an incoming call
          case CallEvent.ACTION_CALL_START:
            // TODO: started an outgoing call
            // TODO: show screen calling in Flutter
          case CallEvent.ACTION_CALL_ACCEPT:
            // TODO: accepted an incoming call
            // TODO: show screen calling in Flutter
          case CallEvent.ACTION_CALL_DECLINE:
            // TODO: declined an incoming call
          case CallEvent.ACTION_CALL_ENDED:
            // TODO: ended an incoming/outgoing call
          case CallEvent.ACTION_CALL_TIMEOUT:
            // TODO: missed an incoming call
          case CallEvent.ACTION_CALL_CALLBACK:
            // TODO: only Android - click action `Call back` from missed call notification
          case CallEvent.ACTION_CALL_TOGGLE_HOLD:
            // TODO: only iOS
          case CallEvent.ACTION_CALL_TOGGLE_MUTE:
            // TODO: only iOS
          case CallEvent.ACTION_CALL_TOGGLE_DMTF:
            // TODO: only iOS
          case CallEvent.ACTION_CALL_TOGGLE_GROUP:
            // TODO: only iOS
            // TODO: only iOS
            // TODO: only iOS
  • Call from Native (iOS PushKit)

      var info = [String: Any?]()
      info["id"] = "44d915e1-5ff4-4bed-bf13-c423048ec97a"
      info["nameCaller"] = "Hien Nguyen"
      info["handle"] = "0123456789"
      info["type"] = 1
      //... set more data
      SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(flutter_callkit_incoming.Data(args: info), fromPushKit: true)

      let data = flutter_callkit_incoming.Data(id: "44d915e1-5ff4-4bed-bf13-c423048ec97a", nameCaller: "Hien Nguyen", handle: "0123456789", type: 0)
      data.nameCaller = "Johnny"
      data.extra = ["user": "abc@123", "platform": "ios"]
      //... set more data
      SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true)

      #if __has_include(<flutter_callkit_incoming/flutter_callkit_incoming-Swift.h>)
      #import <flutter_callkit_incoming/flutter_callkit_incoming-Swift.h>
      #import "flutter_callkit_incoming-Swift.h"
      Data * data = [[Data alloc]initWithId:@"44d915e1-5ff4-4bed-bf13-c423048ec97a" nameCaller:@"Hien Nguyen" handle:@"0123456789" type:1];
      [data setNameCaller:@"Johnny"];
      [data setExtra:@{ @"userId" : @"HelloXXXX", @"key2" : @"value2"}];
      //... set more data
      [SwiftFlutterCallkitIncomingPlugin.sharedInstance showCallkitIncoming:data fromPushKit:YES];

      //send custom event from native
      SwiftFlutterCallkitIncomingPlugin.sharedInstance?.sendEventCustom("customEvent", body: ["customKey": "customValue"])
  1. Properties

    Prop Description Default
    id UUID identifier for each call. UUID should be unique for every call and when the call is ended, the same UUID for that call to be used. suggest using uuid Required
    nameCaller Caller's name. None
    appName App's name. using for display inside Callkit(iOS). App Name, Deprecated for iOS > 14, default using App name
    avatar Avatar's URL used for display for Android. /android/src/main/res/drawable-xxxhdpi/ic_default_avatar.png None
    handle Phone number/Email/Any. None
    type 0 - Audio Call, 1 - Video Call 0
    duration Incoming call/Outgoing call display time (second). If the time is over, the call will be missed. 30000
    textAccept Text Accept used in Android Accept
    textDecline Text Decline used in Android Decline
    textMissedCall Text Missed Call used in Android (show in miss call notification) Missed Call
    textCallback Text Call back used in Android (show in miss call notification) Call back
    extra Any data added to the event when received. {}
    headers Any data for custom header avatar/background image. {}
    android Android data needed to customize UI. Below
    ios iOS data needed. Below

  • Android

    Prop Description Default
    isCustomNotification Using custom notifications. false
    isShowLogo Show logo app inside full screen. /android/src/main/res/drawable-xxxhdpi/ic_logo.png false
    isShowMissedCallNotification Show missed call notification when timeout true
    isShowCallback Show callback action from miss call notification. true
    ringtonePath File name ringtone. put file into /android/app/src/main/res/raw/ringtone_default.pm3 system_ringtone_default
    using ringtone default of the phone
    backgroundColor Incoming call screen background color. #0955fa
    backgroundUrl Using image background for Incoming call screen. example: http://... https://... or "assets/abc.png" None
    actionColor Color used in button/text on notification. #4CAF50

  • iOS

    Prop Description Default
    iconName App's Icon. using for display inside Callkit(iOS) CallKitLogo
    using from Images.xcassets/CallKitLogo
    handleType Type handle call generic, number, email generic
    supportsVideo true
    maximumCallGroups 2
    maximumCallsPerCallGroup 1
    audioSessionMode None, gameChat, measurement, moviePlayback, spokenAudio, videoChat, videoRecording, voiceChat, voicePrompt
    audioSessionActive true
    audioSessionPreferredSampleRate 44100.0
    audioSessionPreferredIOBufferDuration 0.005
    supportsDTMF true
    supportsHolding true
    supportsGrouping true
    supportsUngrouping true
    ringtonePath Add file to root project xcode /ios/Runner/Ringtone.caf and Copy Bundle Resources(Build Phases) Ringtone.caf
    using ringtone default of the phone
  1. Source code

    please checkout repo github

  1. Pushkit - Received VoIP and Wake app from Terminated State (only for IOS)
  1. Todo

:bulb: Demo

  1. Demo Illustration:
  2. Image
iOS(Lockscreen) iOS(full screen) iOS(Alert)
Android(Lockscreen) - Audio Android(Alert) - Audio Android(Lockscreen) - Video
Android(Alert) - Video isCustomNotification: false