callkeep
callkeep copied to clipboard
How to take control to the flutter application after answering the call
Hi, I am using Fcm background message handler(android) to receive call notification from user-A. when notification is received my background message handler is called and I can able to see the answer or decline view buttons like a normal phone call(I think this is using phone accounts).
my question is how to take control to my application once the user answered the call (can be audio/video call)?
or please do suggest me to get this done. struck here for a long time.
Try this :
_callKeep.backToForeground();
_callKeep.endAllCalls();
or
_callKeep.endCall("your uuid");
Then push to your screen
NavigationService.instance.navigateToRoute(MaterialPageRoute(
builder: (context) => YourScreen(),
));
@MaheshPeri19 Thanks for the reply, will try it and let you know.
@MaheshPeri19
same error , The method 'push' was called on null.
I have tried accessing global state but no luck, In the static method we cannot able to use these context/store context/service context.
I hope there should be a way to get this thing working or any workaround will be there, but I don't have that much knowledge in it. can you guys suggest me to achieve this or any workaround to give a try. thanks
Check with below link for NavigationService class. When you come from background to forground, context will be null. So need to use navigator key.
https://stackoverflow.com/questions/63324364/navigation-in-flutter-without-context
And also if you want to pass any data to pushed screen, get from firebase if you already use. Shared preferences and sqlite are not working properly for me at background to foreground.
@MaheshPeri19
Implemented the same way which you are suggesting, but no luck attaching my screen let me know if anything missed out,
if needed I can share the code snippet.
and my background listener

what is the exact error after implementing navigationservice class ?
try to remove return statement at end of CallKeepPerformAnswerCallAction event and also try _callKeep.endAllCalls() instead of endCall(-) method.
Call gets ended by after answering the call and executing .endCall(id);
and my-app opens as expected.
but not pushing to new page (VideoCall in my case).
Getting error in catch block with message The method 'push' was called on null.
So when the app opens as expected,
- is it opening the home screen ? and all code releated to firebase or callkeep functionality in homescreen itself, right ?
- any parameters passing to VideoCall() ? if missing data also causes null exception.
Otherwise in between, it looses state. Please check the logs
@MaheshPeri19 here is my reply
1.It opens up the app with screen which is put background to test call (not tested by killing the app bcz I need to see log). All code are included in main.dart file. 2.just pushing to new route no params is passing , if it works then I will pass the params to achieve my functionality.
Attaching my log may be it helps in identifying the cause
I/flutter (18517): backgroundMessage: message => {data: {body: Test call, key_1: Data for key one, key_2: Hellowww, title: ALT App Testing}} I/flutter (18517): backgroundMessage: displayIncomingCall (Test call) D/RNCK:VoiceConnectionService(18517): setAvailable: false D/RNCK:VoiceConnectionService(18517): setAvailable: true D/FLT:CallKeepModule(18517): displayIncomingCall number: Test call, callerName: D/FLT:CallKeepModule(18517): backToForeground, app isOpened ?true E/RNCK:VoiceConnectionService(18517): Constructor V/PhoneWindow(18517): DecorView setVisiblity: visibility = 0, Parent = ViewRoot{6b44733 com.example/com.example.MainActivity,ident = 0}, this = DecorView@594d49f[MainActivity] I/flutter (18517): ---state --AppLifecycleState.resumed I/flutter (18517): --------agter update Instance of 'Store<AppState>' D/OpenGLRenderer(18517): CanvasContext() 0x774edd9280 initialize window=0x775fff4000 D/Surface (18517): Surface::connect(this=0x775fff4000,api=1) D/mali_winsys(18517): EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, egl_color_buffer_format *, EGLBoolean) returns 0x3000 D/Surface (18517): Surface::connect(this=0x774ea3f000,api=1) D/mali_winsys(18517): EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, egl_color_buffer_format *, EGLBoolean) returns 0x3000 D/Surface (18517): Surface::disconnect(this=0x7751636000,api=1) E/BpSurfaceComposerClient(18517): Failed to transact (-1) E/BpSurfaceComposerClient(18517): Failed to transact (-1) D/RNCK:VoiceConnectionService(18517): setAvailable: false D/RNCK:VoiceConnectionService(18517): setAvailable: true I/TelecomFramework(18517): VoiceConnectionService: notifyCreateConnectionComplete TC@6_1: (...->CSW.hCCC)->CS.crCoC->H.CS.crCoC@E-E-E-BbE I/zygote64(18517): Do partial code cache collection, code=57KB, data=58KB I/zygote64(18517): After code cache collection, code=57KB, data=58KB I/zygote64(18517): Increasing code cache capacity to 256KB D/RNCK:VoiceConnection(18517): onAnswer called D/RNCK:VoiceConnection(18517): onAnswer executed I/flutter (18517): ---state --AppLifecycleState.inactive I/flutter (18517): --------agter update Instance of 'Store<AppState>' I/flutter (18517): [CallKeep] INFO: received event "CallKeepPerformAnswerCallAction" {callUUID: a0d150b6-0842-4aca-8677-a60943f90c86} I/flutter (18517): backgroundMessage: CallKeepPerformAnswerCallAction a0d150b6-0842-4aca-8677-a60943f90c86 D/FLT:CallKeepModule(18517): backToForeground, app isOpened ?true I/flutter (18517): backgroundMessage global state <<<<--- null I/flutter (18517): ---state --AppLifecycleState.resumed I/flutter (18517): --------agter update Instance of 'Store<AppState>' I/flutter (18517): ---state --AppLifecycleState.inactive I/flutter (18517): --------agter update Instance of 'Store<AppState>' D/FLT:CallKeepModule(18517): endCall called D/RNCK:VoiceConnection(18517): onDisconnect executed D/RNCK:VoiceConnectionService(18517): deinitConnection:a0d150b6-0842-4aca-8677-a60943f90c86 D/FLT:CallKeepModule(18517): endCall executed I/flutter (18517): push to new route error NoSuchMethodError: The method 'push' was called on null. I/flutter (18517): Receiver: null I/flutter (18517): Tried calling: push<Object>(Instance of 'MaterialPageRoute<dynamic>') I/flutter (18517): [CallKeep] INFO: received event "CallKeepDidActivateAudioSession" {} I/flutter (18517): [CallKeep] INFO: received event "CallKeepPerformEndCallAction" {callUUID: a0d150b6-0842-4aca-8677-a60943f90c86} I/flutter (18517): backgroundMessage: CallKeepPerformEndCallAction a0d150b6-0842-4aca-8677-a60943f90c86 I/flutter (18517): ---state --AppLifecycleState.resumed I/flutter (18517): --------agter update Instance of 'Store<AppState>' V/PhoneWindow(18517): DecorView setVisiblity: visibility = 0, Parent = ViewRoot{6b44733 com.example/com.example.MainActivity,ident = 0}, this = DecorView@594d49f[MainActivity]
@aravindhkumar23
Have you implemented CallKeepDidActivateAudioSession callback method ?
Please copy paste below method
Future<void> didActivateAudioSession(
CallKeepDidActivateAudioSession event) async {
print('[didActivateAudioSession] calling...');
final String callUUID = newUUID();
_callKeep.backToForeground();
_callKeep.endCall(callUUID);
}
If this one also not working, you only can do R & D and solve this issue.
If you make you functions static it might work. Here is my navigation service.
class NavigationService {
static final navigatorKey = GlobalKey<NavigatorState>();
static Future<void> pushVideoView() {
return navigatorKey.currentState.push(VideoCallView.route());
}
}
From what I've noticed working with FCM backgroundMessageHandler, what happens is the bgMsgHandler is running on a separate isolate than the main flutter UI thread so it has no way of accessing the navigator. One way to mitigate this is to use the flutter_local_notifications package to instantiate a local notif from within the bgmsghandler and place the navigator code inside the local notif's callback for full-screen intent. I'm not sure if I was able to get my idea across but that was how I worked around it. Hope it helps!
@SirJAKfromSpace @VictorUvarov @MaheshPeri19 Thanks for the suggestion, will give a try for the above suggestions by this weekend and update you guys with the status of the proposed solution.
@SirJAKfromSpace Are you creating a notification that is displayed to the user and they have to tap on the notification? Or is there a way to instantly trigger a silent notification and handle that immediately? Or are you not starting the call until the notification is tapped?
@VictorUvarov i am indeed creating a notification using flutter_local_notifications
which has to be tapped by the user (when the device is unlocked). But if the device is locked the onSelectNotification
callback runs automatically.
If on Android and you set showWhenLocked
and android:turnScreenOn
to "true" in the AndroidManifest, then it launches a fullscreen intent from the lockscreen (like an alarm or a call would). flutter_local_notifs FullscreenIntent
Also, I used the lastest prerelease version of the Firebase Cloud Messaging package, since thats the one that properly supports BgMsgHandler.
I myself learnt all this recently so it may not be the definitive answer. Just sharing my workarounds thats all. Hope it helps.
Hi! Have you found solution? Have the same issue(
From what I've noticed working with FCM backgroundMessageHandler, what happens is the bgMsgHandler is running on a separate isolate than the main flutter UI thread so it has no way of accessing the navigator. One way to mitigate this is to use the flutter_local_notifications package to instantiate a local notif from within the bgmsghandler and place the navigator code inside the local notif's callback for full-screen intent. I'm not sure if I was able to get my idea across but that was how I worked around it. Hope it helps!
Hi, is it possible to share code how to call local notification and local notification callback. I couldnt success to run my app from backgroundmessagehandler function
@xyzbilal @rekonvald
Here's what I did:
- pub get the latest prerelease FCM package and the local_flutter_notifs package
- edit AndroidManifest and set android:showWhenLocked and android:turnScreenOn to "true"
- implement FCM into Flutter app properly according to FlutterFire documentation
- look at "fullscreen intents" in the local_flutter_notifs documentation for how they behave
- initialize flutterlocalnotifs and set callback function for onSelectNotif
- initialize fcm and pass onBgMsg a callback function
- instantiate a flutterLocalNotif from within fcm onBgMsg callback
- add navigator logic in localNotif callback (if using fullscreen intent and screen is locked, app will open up regardless)
Hope this helps. Sorry, I couldn’t comment bits of code because it would result in long confusing and perhaps misleading code that is sure to throw errors upon copy pasting.
If you want, you could look into the dart file in my repo linked here to figure out what I did. Please, feel free to leave a star if it helps :p
Thanks you! so, you did not use callkeep at all? I looked at local_flutter_notifs package. But there is no possibility to add action buttons there to answer call, also, on IOS this notification disappears in 3 sec(It is not ok for me because I am implementing calling notification)
so, you did not use callkeep at all?
Nope, I found using fcm (android) and apn (ios) push notifications to work best for me rather than callkeep (it didnt have enough documentation to be usable).
If you're working on iOS look into CallKit APN.
For iOS the localnotifs wont have any action buttons since Apple requires you use their native APN system for call pushes.
Thank you, I researched CallKit, they also don't have functionality to take control to the fluter app on answering call(
@xyzbilal @rekonvald
Here's what I did:
- pub get the latest prerelease FCM package and the local_flutter_notifs package
- edit AndroidManifest and set android:showWhenLocked and android:turnScreenOn to "true"
- implement FCM into Flutter app properly according to FlutterFire documentation
- look at "fullscreen intents" in the local_flutter_notifs documentation for how they behave
- initialize flutterlocalnotifs and set callback function for onSelectNotif
- initialize fcm and pass onBgMsg a callback function
- instantiate a flutterLocalNotif from within fcm onBgMsg callback
- add navigator logic in localNotif callback (if using fullscreen intent and screen is locked, app will open up regardless)
Hope this helps. Sorry, I couldn’t comment bits of code because it would result in long confusing and perhaps misleading code that is sure to throw errors upon copy pasting.
If you want, you could look into the dart file in my repo linked here to figure out what I did. Please, feel free to leave a star if it helps :p
this looks fine, but the code you referred to is not available on github, can you share it here
For navigation to specific screen when your app is terminated you can use Shared Preferences. Save the call notification data with a key in prefs and when you open the app check this key to see if any data is available and if it is then navigate to call screen with that data and remove it from prefs. Of course you need the delete the notification from prefs when user did't accept call or you get a end call notification. good luck!