flutter_callkeep

Last updated:

0 purchases

flutter_callkeep Image
flutter_callkeep Images
Add to Cart

Description:

flutter callkeep

callkeep #
Showing incoming call notification/screen using iOS CallKit and Android Custom UI for Flutter
Web is supported but user must build their own incoming call UI in Flutter, see below.
Native setup #
flutter_callkeep requires the following permissions.
Android #
in AndroidManifest.xml, set launchMode to singleInstance for our main activity.
<manifest...>

...
<activity ...
android:name=".MainActivity"
android:launchMode="singleInstance">
...
...

</manifest>
copied to clipboard
on Android 13+ you need to ask for Notifications permission in order to show incoming call notification.
You can either achieve that using firebase messaging:
final firebaseMessaging = FirebaseMessaging.instance;
final notificationSettings = await firebaseMessaging.getNotificationSettings();
final isPermissionDenied =
notificationSettings.authorizationStatus == AuthorizationStatus.denied;

...
// We request Android 13 and above permission as it is denied by default and we have to ask
// But for iOS we only ask if permission is not denied, as it defaults to notDetermined on first boot
final isAndroid13OrAbove = (UniversalPlatform.isAndroid &&
((await DeviceInfoPlugin().androidInfo).version.sdkInt) >= 33);

// TODO(any): maybe show a custom UI if permission is denied for all platforms
// to get through how important notification permissions are
final shouldPrompt =
(isAndroid13OrAbove && isPermissionDenied) || !isPermissionDenied;

if(shouldPrompt){
final settings = await firebaseMessaging.requestPermission();

}
...

copied to clipboard
or by using the permission_handler package
iOS #
in Info.plist
<key>UIBackgroundModes</key>
<array>
<string>processing</string>
<string>remote-notification</string>
<string>voip</string>
</array>
copied to clipboard
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)
}
}
copied to clipboard
Usage #
Dependency: #
Add the dependency manually to your pubspec.yaml file:
dependencies:
flutter_callkeep: ^(latest_version)
copied to clipboard
or run:
flutter pub add flutter_callkeep
copied to clipboard
Setup: #
You need to configure the package before displaying incoming calls:
void configureCallkeep() {
final config = CallKeepConfig(
appName: 'CallKeep',
// Other plugin configurations
android: CallKeepAndroidConfig(
// Android configuration
),
ios: CallKeepIosConfig(
// iOS configuration
),
// Headers if needed
headers: <String, dynamic>{'apiKey': 'Abc@123!', 'platform': 'flutter'},
);
CallKeep.instance.configure(config);
}
copied to clipboard
Display incoming call: #
final data = CallEvent(
uuid: uuid,
callerName: 'Test User',
handle: '0123456789',
hasVideo: false,
duration: 30000,
extra: <String, dynamic>{'userId': '1a2b3c4d'},
);

await CallKeep.instance.displayIncomingCall(data);
copied to clipboard
Show missed call notification (Android only and may be removed in later versions): #
final data = CallEvent(
uuid: uuid,
callerName: 'Test User',
handle: '0123456789',
hasVideo: false,
duration: 30000,
extra: <String, dynamic>{'userId': '1a2b3c4d'},
);

await CallKeep.instance.showMissCallNotification(data);
copied to clipboard
Start an outgoing call: #
final data = CallEvent(
uuid: uuid,
callerName: 'Test User',
handle: '0123456789',
hasVideo: false,
duration: 30000,
extra: <String, dynamic>{'userId': '1a2b3c4d'},
);

CallKeep.instance.startCall(data);
copied to clipboard
Handling events and showing custom UI (Web): #
You need to pass your callbacks for each event to the plugin's handler property
if the platform doesn't support incoming call display - such as CallKit for iOS or custom activity for Android -,
you can show your own incoming call UI using the onCallIncoming event.
We can check first if the plugin is displaying incoming call UI or not using CallKeep.instance.isIncomingCallDisplayed and show our custom UI accordingly.
Future<void> setEventHandler() async {
CallKeep.instance.handler = CallEventHandler(
onCallIncoming: (event) {
print('call incoming: ${event.toMap()}');
if (!CallKeep.instance.isIncomingCallDisplayed) {
showAdaptiveDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Incoming Call"),
content: Text("Incoming call from ${event.callerName}"),
actions: [
TextButton(
onPressed: () {
CallKeep.instance.acceptCall(event.uuid);
Navigator.pop(context);
},
child: Text("Accept"),
),
TextButton(
onPressed: () {
CallKeep.instance.endCall(event.uuid);
Navigator.pop(context);
},
child: Text("Decline"),
),
],
);
});
}
},
onCallStarted: (event) {
print('call started: ${event.toMap()}');
},
onCallEnded: (event) {
print('call ended: ${event.toMap()}');
},
onCallAccepted: (event) {
print('call answered: ${event.toMap()}');
NavigationService.instance
.pushNamedIfNotCurrent(AppRoute.callingPage, args: event.toMap());
},
onCallDeclined: (event) async {
print('call declined: ${event.toMap()}');
},
);
}
copied to clipboard
Customization (Android): #
You can customize background color and add localizations to text through adding the values to your '{{yourApp}}/android/app/src/main/res/values' and '{{yourApp}}/android/app/src/main/res/values-{{languageCode}}' for localizations.
The main values are:
in colors.xml
<!-- A hex color value to be displayed on the top part of the custom incoming call UI -->
<color name="incoming_call_bg_color">#80ffffff</color>
copied to clipboard
in strings.xml
<!-- Accept button call text, useful for localization -->
<string name="accept_text">Accept</string>
<!-- Decline button call text, useful for localization -->
<string name="decline_text">Decline</string>
<!-- Missed call text, useful for localization -->
<string name="text_missed_call">Missed call</string>
<!-- Callback button text, useful for localization -->
<string name="text_call_back">Call back</string>
<!-- Incoming call custom UI header, useful for localization -->
<!-- This can be set from Flutter as well when displaying incoming call -->
<string name="call_header">Call from CallKeep</string>
copied to clipboard

License:

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Customer Reviews

There are no reviews.