Skip to main content
This guide takes you from zero to a working incoming call screen in your Flutter app.
1

Install the package

flutter pub add flutter_callkit_incoming
Version 2.5.0 and later require Java SDK 17+ for the Android build. Verify with java -version.
2

Configure Android

Add the INTERNET permission and set singleInstance launch mode in android/app/src/main/AndroidManifest.xml:
AndroidManifest.xml
<manifest ...>
    <!-- Required to load avatars/backgrounds from URLs -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application ...>
        <activity
            android:name=".MainActivity"
            android:launchMode="singleInstance">
            <!-- singleInstance is required for the call screen to show correctly -->
        </activity>
    </application>
</manifest>
Add the ProGuard keep rule to android/app/proguard-rules.pro:
-keep class com.hiennv.flutter_callkit_incoming.** { *; }
3

Configure iOS

Add the required background modes to ios/Runner/Info.plist:
Info.plist
<key>UIBackgroundModes</key>
<array>
    <string>voip</string>
    <string>remote-notification</string>
</array>
iOS CallKit only works on a real device. The simulator cannot display the CallKit incoming call screen.
For full iOS setup including AppDelegate configuration, see the iOS setup guide.
4

Show an incoming call

Import the plugin and call showCallkitIncoming with a CallKitParams object:
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:uuid/uuid.dart';

final String currentUuid = const Uuid().v4();

CallKitParams callKitParams = CallKitParams(
  id: currentUuid,
  nameCaller: 'Hien Nguyen',
  appName: 'Callkit',
  avatar: 'https://i.pravatar.cc/100',
  handle: '0123456789',
  type: 0, // 0 = audio, 1 = video
  textAccept: 'Accept',
  textDecline: 'Decline',
  missedCallNotification: const NotificationParams(
    showNotification: true,
    isShowCallback: true,
    subtitle: 'Missed call',
    callbackText: 'Call back',
  ),
  duration: 30000,
  extra: <String, dynamic>{'userId': '1a2b3c4d'},
  android: const AndroidParams(
    isCustomNotification: true,
    ringtonePath: 'system_ringtone_default',
    backgroundColor: '#0955fa',
    actionColor: '#4CAF50',
    textColor: '#ffffff',
    incomingCallNotificationChannelName: 'Incoming Call',
    missedCallNotificationChannelName: 'Missed Call',
  ),
  ios: const IOSParams(
    iconName: 'CallKitLogo',
    handleType: 'generic',
    supportsVideo: true,
    maximumCallGroups: 2,
    maximumCallsPerCallGroup: 1,
    supportsDTMF: true,
    supportsHolding: true,
    ringtonePath: 'system_ringtone_default',
  ),
);
await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
The id field must be a valid UUID. Use the uuid package to generate one.
When using Firebase Cloud Messaging to trigger showCallkitIncoming in a background handler, annotate the handler with @pragma('vm:entry-point').
5

Listen for call events

Subscribe to the onEvent stream to handle user actions:
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
  switch (event?.event) {
    case Event.actionCallIncoming:
      // Received an incoming call
      break;
    case Event.actionCallStart:
      // Started an outgoing call
      break;
    case Event.actionCallAccept:
      // User accepted the call — connect your WebRTC/P2P session here
      break;
    case Event.actionCallDecline:
      // User declined the call
      break;
    case Event.actionCallEnded:
      // Call ended
      break;
    case Event.actionCallTimeout:
      // Call timed out (missed)
      break;
    case Event.actionCallCallback:
      // User tapped "Call back" in missed call notification (Android)
      break;
    case Event.actionCallToggleHold:
      // iOS only — hold toggled
      break;
    case Event.actionCallToggleMute:
      // iOS only — mute toggled
      break;
    default:
      break;
  }
});
After the call is accepted and your WebRTC connection is established, mark the call as connected:
await FlutterCallkitIncoming.setCallConnected(currentUuid);

What’s next

Android setup

Full Android configuration including permission flows

iOS setup

AppDelegate and PushKit configuration

Show incoming call

All options for the incoming call screen

Call events

Complete event reference

Outgoing calls

Start and manage outgoing calls

API reference

Full Dart API documentation

Build docs developers (and LLMs) love