flutter_callkeep 0.3.0 copy "flutter_callkeep: ^0.3.0" to clipboard
flutter_callkeep: ^0.3.0 copied to clipboard

iOS CallKit and Android ConnectionService bindings for Flutter

callkeep #

Showing incoming call notification/screen using iOS CallKit and Android Custom UI for Flutter

Native setup #

flutter_callkeep requires the following permissions.

Android #

No extra setup is needed

iOS #

in Info.plist

<key>UIBackgroundModes</key>
<array>
    <string>processing</string>
    <string>remote-notification</string>
    <string>voip</string>
</array>

Then you need to update AppDelegate.swift to follow the example for handling PushKit as push handling must be done through native iOS code due to iOS 13 PushKit VoIP restrictions.

import UIKit
import PushKit
import Flutter
import flutter_callkeep

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        
        //Setup VOIP
        let mainQueue = DispatchQueue.main
        let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [PKPushType.voIP]
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    // Handle updated push credentials
    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
        print(credentials.token)
        let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
        print(deviceToken)
        //Save deviceToken to your server
        SwiftCallKeepPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken)
    }
    
    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        print("didInvalidatePushTokenFor")
        SwiftCallKeepPlugin.sharedInstance?.setDevicePushTokenVoIP("")
    }
    
    // Handle incoming pushes
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        print("didReceiveIncomingPushWith")
        guard type == .voIP else { return }
        
        let id = payload.dictionaryPayload["id"] as? String ?? ""
        let callerName = payload.dictionaryPayload["callerName"] as? String ?? ""
        let userId = payload.dictionaryPayload["callerId"] as? String ?? ""
        let handle = payload.dictionaryPayload["handle"] as? String ?? ""
        let isVideo = payload.dictionaryPayload["isVideo"] as? Bool ?? false
        
        let data = flutter_callkeep.Data(id: id, callerName: callerName, handle: handle, hasVideo: isVideo)
        //set more data
        data.extra = ["userId": callerId, "platform": "ios"]
        data.appName = "Done"
        //data.iconName = ...
        //data.....
        SwiftCallKeepPlugin.sharedInstance?.displayIncomingCall(data, fromPushKit: true)
    }   
}

Usage #

Setup: #

You need to have base CallKeep config setup to reduce code duplication and make it easier to display incoming calls:

 final callKeepBaseConfig = CallKeepBaseConfig(
      appName: 'Done',
      androidConfig: CallKeepAndroidConfig(
        logo: 'logo',
        notificationIcon: 'notification_icon',
        ringtoneFileName: 'ringtone.mp3',
        accentColor: '#34C7C2',
      ),
      iosConfig: CallKeepIosConfig(
        iconName: 'Icon',
        maximumCallGroups: 1,
      ),
    );

Display incoming call: #

// Config and uuid are the only required parameters
final config = CallKeepIncomingConfig.fromBaseConfig(
    config: callKeepBaseConfig,
    uuid: uuid,
    contentTitle: 'Incoming call from Done',
    hasVideo: hasVideo,
    handle: handle,
    callerName: incomingCallUsername,
    extra: callData,
);
await CallKeep.instance.displayIncomingCall(config);

Show missed call notification (Android only): #

// config and uuid are the only required parameters
final config = CallKeepIncomingConfig.fromBaseConfig(
    config: callKeepBaseConfig,
    uuid: uuid,
    contentTitle: 'Incoming call from Done',
    hasVideo: hasVideo,
    handle: handle,
    callerName: incomingCallUsername,
    extra: callData,
);
await CallKeep.instance.showMissCallNotification(config);

Start an outgoing call: #

// config and uuid are the only required parameters
final config = CallKeepOutgoingConfig.fromBaseConfig(
    config: DoneCallsConfig.instance.callKeepBaseConfig,
    uuid: uuid,
    handle: handle,
    hasVideo: hasVideo ?? false,
);
CallKeep.instance.startCall(config);

Handling events: #

CallKeep.instance.onEvent.listen((event) async {
    // TODO: Implement other events
    if (event == null) return;
    switch (event.type) {
        case CallKeepEventType.callAccept:
        final data = event.data as CallKeepCallData;
        print('call answered: ${data.toMap()}');
        NavigationService.instance
            .pushNamedIfNotCurrent(AppRoute.callingPage, args: data.toMap());
        if (callback != null) callback.call(event);
        break;
        case CallKeepEventType.callDecline:
        final data = event.data as CallKeepCallData;
        print('call declined: ${data.toMap()}');
        await requestHttp("ACTION_CALL_DECLINE_FROM_DART");
        if (callback != null) callback.call(data);
        break;
        default:
        break;
    }
});
72
likes
0
pub points
86%
popularity

Publisher

verified publisherdoneservices.co

iOS CallKit and Android ConnectionService bindings for Flutter

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

flutter

More

Packages that depend on flutter_callkeep