callkeep
callkeep copied to clipboard
backToForeground() does not work when app is closed on Android
First of all: This is a very nice library! I am using callkeep to display an incoming call notification when a message is received via firebase_messaging in onBackgroundMessage. When the user answers the incoming call I call backToForeground() and endCall() to just open the app when answering the call. This works pretty good when the app is running and in the background.
But when the app is closed and a message is received it shows the incoming call notification but when you click on answer, it doesn't launch the app.
I think this is a critical feature for such use case since it can't be guaranteed that the app is alive. I don't know how easy it is to extend backToForeground() so it handles this case properly or if this is even possible at all.
I have yet to test the behavior on iOS if it launches the app by default because backToForeground is not implemented for iOS according to the source code of callkeep.
If you know an alternative solution, please let me know.
I've read your issue and I have not tried it that way. I am answering the call and then answering the SIP INVITE in dart-sip-ua and staying in the native dialler screen and using all the callbacks for hold/dtmf etc.
Once a successful call is ended I am about to use backtoforeground, but I haven't tested that yet.
If you end the call, what are you doing about the native dialler call logs? Isn't the call recorded there? What is the architecture of your app like? SIP?
Regarding iOS, I understand true background messages do not work with FCM, just onLaunch and onResume, so I am using what apple say to use for VoIP:
https://github.com/FirebaseExtended/flutterfire/issues/116#issuecomment-583854658 https://github.com/masashi-sutou/flutter_ios_voip_kit
I may move to this though for a custom inbound call screen or copy it to this project:
https://github.com/doneservices/flutter_callkeep/blob/01e683d16be6d6675cf678d85be683718382a96a/lib/flutter_callkeep.dart#L248
https://github.com/doneservices/flutter_callkeep/issues/16
It looks like it’s not implemented
https://github.com/flutter-webrtc/callkeep/search?q=foreground
It is in another project https://github.com/doneservices/flutter_callkeep/blob/b15c0caffacdf4aa2cc3f118f66a6980cb11cb24/android/src/main/kotlin/co/doneservices/callkeep/CallKeep.kt#L381
Actually, callKeep.backToForeground(); is working for me. It is there https://github.com/flutter-webrtc/callkeep/blob/002ea8eac7a5d961675c77ab3a0df7d52c8f923d/android/src/main/java/io/wazo/callkeep/CallKeepModule.java#L546
If you end the call, what are you doing about the native dialler call logs? Isn't the call recorded there? What is the architecture of your app like? SIP?
I planned to use it only for the incoming call notification and I didn't thought alot about call logs. Can you prevent it from being written to the call logs? If it's not possible then I think it is not that dramatic. I want to use Agora for Video Calling with custom UI and therefore I just need the incoming call notification to open the app. This library is the most promising thing I found which could work on iOS and Android with Flutter.
Regarding iOS, I understand true background messages do not work with FCM, just onLaunch and onResume, so I am using what apple say to
I know that onBackgroundMessage is not supported by firebase_messaging yet but there is a PR (https://github.com/FirebaseExtended/flutterfire/pull/2016) and a Google dev commented "Hold on to your hats... New dev release coming soon." so I think this is going to be merged soon. I also read somewhere that CallKit which is used for iOS always opens the app. So if onBackgroundMessage is working reliably on iOS this might be a good solution if Android behaved the same.
use for VoIP: FirebaseExtended/flutterfire#116 (comment) https://github.com/masashi-sutou/flutter_ios_voip_kit
This also looks interesting if the PR with onBackgroundMessage won't work reliably on iOS.
I may move to this though for a custom inbound call screen or copy it to this project:
https://github.com/doneservices/flutter_callkeep/blob/01e683d16be6d6675cf678d85be683718382a96a/lib/flutter_callkeep.dart#L248
That also looks interesting
Actually, callKeep.backToForeground(); is working for me. It is there
https://github.com/flutter-webrtc/callkeep/blob/002ea8eac7a5d961675c77ab3a0df7d52c8f923d/android/src/main/java/io/wazo/callkeep/CallKeepModule.java#L546
It is working for you when the app is killed? It is working for me only when the app is in background but not when it was killed. What Android version?
Thanks for all your replies. Great info.
Ah, not tested a killed app.
I wanted to test if the implementation of backToForeground() of the other library (https://github.com/doneservices/flutter_callkeep) can open the app when it was killed but I could not get it running in the background, only foreground. It's the same problem another person was facing: https://github.com/doneservices/flutter_callkeep/issues/19
I read up on the flag used to do this on the android native side, and the app needs to be running as it's moved up the activity stack. Read the source and have a Google to confirm yourself.
That's my understanding anyway.
I read up on the flag used to do this on the android native side, and the app needs to be running as it's moved up the activity stack. Read the source and have a Google to confirm yourself. That's my understanding anyway.
That's what I picked up too but I made an interesting observation: When I kill the app after the incoming call notification is shown and then click on answer it works despite when backToForeground() is called when the app is closed. This seems contradicting to me.
I am also initializing CallKeep and setting the CallKeepPerformAnswerCallAction "listener" when receciving a notification. I tried initializing and setting the listener with a static instance when the app is started but that's not working. I guess because onBackgroundMessage is running as it's own service.
Hi @jfaltis it looks like we have the same use case :). I also want to use callkeep plugin to inform user about incoming call and then redirect to app with webrtc call. I also tried the other flutter_callkeep plugin with the same error in background mode as described here.
One question for you, how did you make callkeep plugin to work when app is terminated? Other plugins that used (flutter_local_notifications, flutter_ringtone_player) are working ok in background mode when app is terminated, but callkeep is not, nothing is shown. Any suggestions?
It would be nice if you could share your implementation of backgroundMessageHandler
Hi @aponski, I am doing all the initialization of callkeep in the onBackgroundMessage because doing it somewhere else did not properly work for me.
static Future<dynamic> onBackgroundMessage(
Map<String, dynamic> message,
) async {
final FlutterCallkeep _callKeep = FlutterCallkeep();
_callKeep.setup(<String, dynamic>{
'ios': {
'appName': 'CallKeepDemo',
},
'android': {
'alertTitle': 'Permissions required',
'alertDescription':
'This application needs to access your phone accounts',
'cancelButton': 'Cancel',
'okButton': 'ok',
},
});
final String callUUID = Uuid().v4();
_callKeep.on(CallKeepPerformAnswerCallAction(),
(CallKeepPerformAnswerCallAction event) {
_callKeep.backToForeground();
_callKeep.endCall(event.callUUID);
});
_callKeep.displayIncomingCall(callUUID, "Caller Name");
}
Maybe you haven't registered the Plugin properly?
My Application.kt
package your.package.name
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
import com.github.cloudwebrtc.flutter_callkeep.FlutterCallkeepPlugin
class Application : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
FlutterFirebaseMessagingService.setPluginRegistrant(this)
}
override fun registerWith(registry: PluginRegistry?) {
io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
FlutterCallkeepPlugin.registerWith(registry?.registrarFor("com.github.cloudwebrtc.flutter_callkeep"));
}
}
@jfaltis thanks a lot, initialization in background message handler did the job, it's working. Now I guess we have to figure out hot to make backToForeground() work when app is terminated. Any ideas?
@aponski I am happy to help you :) Yes I guess that is the only thing we have to figure out to make it work reliably on Android. But I don't know if this will also work reliably on iOS with the onBackgroundMessage PR for iOS (https://github.com/FirebaseExtended/flutterfire/pull/2016). I currently don't have an iOS Device nor an Apple Developer Account to test this. Could you maybe test that?
@jfaltis sure, I will test it on iOS and let you know
@jfaltis Here is a nice summary of what’s working regarding notifications on Android and iOS: link. On iOS I think the only way is to use voip notifications (Apple PushKit) with an additional flutter plugin flutter_voip_push_notification. I will try it but currently my main concern is to make it fully work on Android first.
This is also my understanding and my plan too. Android first, but I have a feeling the background message is isolating some of my code which I am investigating.
Also found this stackoverflow topic which I think is worth checking.
Also found this stackoverflow topic which I think is worth checking.
Yep, this is the solution and something I've known now for a long while. We can put iOS to bed: :-)
The only exception for that are calls, which were was my case. I had to use apple VoIP notifications, There are two separate flutter packages to deal with that flutter_voip_push_notification and flutter_call_kit
I also knew about https://pub.dev/packages/bringtoforeground and there is this too:
https://github.com/doneservices/flutter_callkeep/wiki/Native-android-code-that-handles-incoming-calls
@jfaltis Here is a nice summary of what’s working regarding notifications on Android and iOS: link. On iOS I think the only way is to use voip notifications (Apple PushKit) with an additional flutter plugin flutter_voip_push_notification. I will try it but currently my main concern is to make it fully work on Android first.
This looks interesting and could be one solution for iOS. @aponski Can you verify that my idea with the new PR on iOS is definitely not working?
I also knew about https://pub.dev/packages/bringtoforeground and there is this too:
https://github.com/doneservices/flutter_callkeep/wiki/Native-android-code-that-handles-incoming-calls
@ghenry I also tried to get this working for bringing the Android App to foreground when the app is killed but for me it did not work. When I had the plugin in my pubspec.yml somehow none of my messages were caught by onBackgroundMessage even though I wasn't calling any code of that plugin. But I am not 100 percent sure if it was the fault of the plugin. If you get it working please let me know.
Another problem I see with the library is that it only works up to Android 9 and that some vendors don't allow bringing activites into foreground.
Some android vendors like Xaiomi will prevent your app's services from bringing activities to the foreground, so you have to tell the user: go to settings, enable some setting, which differs by vendor
The proposed solution is unfortunately bad user experience in my opinion.
If we get https://pub.dev/packages/bringtoforeground working for Android 9 and lower the problems left are no support for Android 10 and some vendors will disallow it.
@jfaltis @aponski I have the Same Scenario and the same issue. did you find out any solution for this issue?
@payam-zahedi I have not found a solution but I also did not investigate alot further and don't plan to in the future.
@jfaltis i have the same problem when app is killed _callKeep.backToForeground(); is not working and an exception is shown Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'int android.content.Context.checkPermission(java.lang.String, int, int)' on a null object reference, null, java.lang.NullPointerException: Attempt to invoke virtual method 'int android.content.Context.checkPermission(java.lang.String, int, int)' on a null object reference
@jfaltis thanks a lot, initialization in background message handler did the job, it's working. Now I guess we have to figure out hot to make backToForeground() work when app is terminated. Any ideas?
Any workaround for this issue for backToForeground() ?
@payam-zahedi I haven't found a solution yet and I had to park this project for a while.
@jfaltis @ghenry @MaheshPeri19 @ahmedJD @payam-zahedi
fixed https://github.com/flutter-webrtc/callkeep/commit/b09080e5ed1e0fde09b64c006a3648f818240986
you can use it like this:
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
print('backgroundMessage: message => ${message.toString()}');
Map<dynamic, dynamic> payload = message['data'] as Map<dynamic, dynamic>;
String callerId = payload['caller_id'] as String;
String callerName = payload['caller_name'] as String;
bool appIsOpened = await _callKeep.backToForeground();
if (appIsOpened) {
print('APP is opened, use callkeep display incoming call now.');
await displayIncomingCall(callerId, callerName);
} else {
print('APP is closed, wake it up and use callkeep to display incoming calls.');
}
}
@ghenry I did a test and can wake up the app to the foreground. The logic code you used in the background can be moved to the app after startup, so there is no need to perform registration in the background.
Thanks. I'll try just waking it up on receipt of a push like iOS does.
@jfaltis @ghenry @MaheshPeri19 @ahmedJD @payam-zahedi
fixed b09080e
you can use it like this:
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) { print('backgroundMessage: message => ${message.toString()}'); Map<dynamic, dynamic> payload = message['data'] as Map<dynamic, dynamic>; String callerId = payload['caller_id'] as String; String callerName = payload['caller_name'] as String; bool appIsOpened = await _callKeep.backToForeground(); if (appIsOpened) { print('APP is opened, use callkeep display incoming call now.'); await displayIncomingCall(callerId, callerName); } else { print('APP is closed, wake it up and use callkeep to display incoming calls.'); } }
You can't use await in the background handler :-(
Stupid me. It returns a future so can use async in the definition.
Hello i have the same problem it cant ork in android 10,, _callKeep.backToForeground(),,seems not working on android 10 but in android 9 works