Native incoming & outgoing call UI for Flutter.
CallBundle provides CallKit on iOS and TelecomManager + OEM-adaptive notifications on Android — as a single, reliable federated plugin.
Built by Ikolvi.
Existing call plugins suffer from silent event drops, cold-start failures, and OEM incompatibilities. CallBundle was built from scratch to solve these problems:
| Problem | CallBundle Solution |
|---|---|
| EventChannel accept events silently dropped | MethodChannel for ALL communication |
| 3 parallel accept-detection paths | Single reliable MethodChannel path |
| Budget OEM notifications silently fail | Built-in OEM-adaptive notification strategy |
| Cold-start 3-second hardcoded delay | Deterministic PendingCallStore handshake |
| iOS audio session conflict with HMS | AudioSessionManager with .mixWithOthers |
| 16 ProGuard keep rules in app | Consumer ProGuard rules shipped in plugin |
| 437-line fallback plugin in app code | Built-in AdaptiveCallNotification |
_isEndingCallKitProgrammatically flag |
isUserInitiated field on every event |
| Feature | iOS | Android |
|---|---|---|
| Native incoming call UI | CallKit | TelecomManager + Notification |
| Native outgoing call UI | CallKit | Notification |
| VoIP push token management | PushKit | — |
| Cold-start call acceptance | UserDefaults | SharedPreferences |
| OEM-adaptive notifications | — | 18+ manufacturers detected |
| Missed call notifications | UNNotification | NotificationCompat |
| Audio session management | AVAudioSession | — |
| Caller avatar support | Missed call notifications | Incoming call UI + notifications |
| Consumer ProGuard rules | — | Built-in |
| Background isolate support | — | BinaryMessenger |
dependencies:
callbundle: ^1.0.0The Android and iOS platform packages are endorsed — they are automatically included. No additional dependency lines needed.
import 'package:callbundle/callbundle.dart';
// 1. Configure
await CallBundle.configure(NativeCallConfig(
appName: 'MyApp',
android: AndroidCallConfig(phoneAccountLabel: 'MyApp Calls'),
ios: IosCallConfig(supportsVideo: false, includesCallsInRecents: true),
));
// 2. Listen for events
CallBundle.onEvent.listen((event) {
switch (event.type) {
case NativeCallEventType.accepted:
print('Call accepted: ${event.callId}');
case NativeCallEventType.declined:
print('Call declined: ${event.callId}');
case NativeCallEventType.ended:
print('Call ended: ${event.callId}');
default:
break;
}
});
// 3. Show incoming call
await CallBundle.showIncomingCall(NativeCallParams(
callId: 'unique-call-id',
callerName: 'John Doe',
handle: '+1 234 567 8900',
callType: NativeCallType.voice,
callerAvatar: 'https://example.com/photos/john.jpg',
android: const AndroidCallParams(),
ios: const IosCallParams(),
));
// 4. End call
await CallBundle.endCall('unique-call-id');See the full implementation guide for permissions, FCM integration, cold-start handling, and advanced usage.
| Document | Description |
|---|---|
| Implementation Guide | Full setup, API reference, permissions, FCM, cold-start |
| Platform Interface | Abstract API contract and data models |
| Android Implementation | TelecomManager, notifications, OEM detection |
| iOS Implementation | CallKit, PushKit, audio session management |
| Example App | Working demo with all features |
┌─────────────────────────────────┐
│ Your Flutter App │
│ import 'callbundle.dart' │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ callbundle (app-facing) │
│ Static CallBundle API class │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ callbundle_platform_interface │
│ Abstract API + Models + Enums │
└──────┬──────────────────┬───────┘
│ │
┌──────▼──────┐ ┌───────▼──────┐
│ callbundle │ │ callbundle │
│ _android │ │ _ios │
│ (Kotlin) │ │ (Swift) │
└─────────────┘ └──────────────┘
All communication uses MethodChannel (com.callbundle/main) in both directions. No EventChannel, no WeakReference.
| Platform | Minimum |
|---|---|
| Flutter | 3.10+ |
| Dart SDK | 3.0+ |
| iOS | 13.0+ |
| Android | API 21 (Android 5.0) |
| Kotlin | 1.9+ |
| Swift | 5.0+ |
This project uses Melos for monorepo management and FVM for Flutter version management.
# Bootstrap all packages
melos bootstrap
# Run analysis across all packages
melos run analyze
# Run tests across all packages
melos run test
# Run tests for a specific package
cd callbundle && fvm flutter test
cd callbundle_android && fvm flutter test
cd callbundle_ios && fvm flutter test
# Build example app
cd example && fvm flutter build apk --debug # Android
cd example && fvm flutter build ios --no-codesign # iOSMIT License — see LICENSE for details.
Built with reliability in mind by Ikolvi.