Open haninhn opened 8 months ago
ok i find a workaround just for now , when i got a notification in bacground through Firebase i am initializing or listning its events again in background and if accept or decliened is clicked saving the data in sharedprefreences and when app is opened then getting those data from sharedprefrenses below is my
` if (messageData['notificationType'] == 1) { log('notificationType background :- ${messageData["notificationType"]}');
CallUtils.showIncomingCall(messageData);
initforbackground();
}`
and create saperate utils CallUtils
`import 'dart:developer'; import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; import 'package:uuid/uuid.dart';
class CallUtils {
static Future
String defaultImage = 'https://i.pravatar.cc/500';
String? profilePic = body['profile'];
String imageUrl;
if (profilePic != null) {
imageUrl = imgBaseurl + profilePic;
} else {
imageUrl = defaultImage;
}
bool calltype = body['call_type'] == 10; //11 video call or 10 audio call
log('calltype is $calltype');
log('imageUrl is $imageUrl');
log('imageUrl is ${body['name']}');
log('fcmToken is ${body['fcmToken']}');
CallKitParams callKitParams = CallKitParams(
id: currentUuid,
nameCaller: body['astrologerName'] ?? 'Astrologer',
appName: 'Astroway',
handle: 'Astroway Partner',
type: calltype ? 0 : 1, // 0 for audio call, 1 for video call
textAccept: 'Accept',
textDecline: 'Decline',
duration: 30000,
missedCallNotification: const NotificationParams(
showNotification: true,
isShowCallback: true,
subtitle: 'Missed call',
callbackText: 'Call back',
),
extra: <String, dynamic>{
'astrologerId': body['astrologerId'],
'astrologerName': body['astrologerName'],
'call_type': body['call_type'],
'channelName': body['channelName'],
'callId': body['callId'],
'profile': body['profile'],
'token': body['token'],
'fcmToken': body['fcmToken'],
'call_duration': body['call_duration'],
},
headers: <String, dynamic>{'apiKey': 'sunil@123!', 'platform': 'flutter'},
android: const AndroidParams(
isCustomNotification: true,
isShowLogo: false,
ringtonePath: 'system_ringtone_default',
backgroundColor: '#0955fa',
actionColor: '#4CAF50',
textColor: '#ffffff',
incomingCallNotificationChannelName: "Incoming Call 1",
isShowCallID: true, //for showing handle in incoming call notification
),
ios: IOSParams(
iconName: 'CallKitLogo',
handleType: 'generic',
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
audioSessionMode: 'default',
audioSessionActive: true,
audioSessionPreferredSampleRate: 44100.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
ringtonePath: 'system_ringtone_default',
),
);
await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
} } `
and
`@pragma('vm:entry-point') void initforbackground() async { final prefs = await SharedPreferences.getInstance();
debugPrint('inside initforbackground'); FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async { debugPrint('inside initforbackground $event');
if (event == null) {
await prefs.setBool('is_accepted', false);
await prefs.setBool('is_rejected', false);
return;
}
switch (event.event) {
case Event.actionCallStart:
// Handle call accept action
print('actionCallStart call incoming');
break;
case Event.actionCallAccept:
// Handle call decline action
print('actionCallAccept call incoming');
await prefs.setBool('is_accepted', true);
String extraDataJson = jsonEncode(event.body['extra']);
print('actionCallAccept extraDataJson $extraDataJson');
await prefs.setString('is_accepted_data', extraDataJson);
break;
case Event.actionCallDecline:
print('call rejected');
// Handle call end action
await chatController.rejectedChat(event.body['extra']['callId']);
await prefs.setBool('is_rejected', true);
await prefs.setBool('is_accepted', false);
await prefs.setBool('is_rejected', false);
await prefs.setString('is_accepted_data', '');
break;
case Event.actionCallCallback:
print('actionCallCallback initforbackground call incoming click');
break;
case Event.actionCallTimeout:
print('actionCallTimeout initforbackground call incoming click');
//clear background data when missed call so whenever app open agian then this data
//not open direactly callscreens
await prefs.setBool('is_accepted', false);
await prefs.setBool('is_rejected', false);
await prefs.setString('is_accepted_data', '');
break;
default:
break;
}
}); }`
and remember to make a check in splashscreen after main.dart fully initialized like i have done below
Load Saved Data
`Future
bool? isacceptedcall = await prefs.getBool('is_accepted');
print('is accepted or not $isacceptedcall');
if (isacceptedcall == true) {
// Handle call end action
String? dataaccepted = await prefs.getString('is_accepted_data');
if (dataaccepted!.isNotEmpty) {
await prefs.setBool('is_accepted', false);
print('is accepted dataaccepted $dataaccepted}');
callAccept(jsonDecode(dataaccepted));
await prefs.setString('is_accepted_data', '');
}
}
bool? isrejectedcall = await prefs.getBool('is_rejected');
if (isrejectedcall == true) {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('is_accepted', false);
await prefs.setString('is_accepted_data', '');
}
} `
and again map it as per Your need
`
@pragma('vm:entry-point')
void callAccept(Map<String, dynamic> extraData) async {
final callController = Get.find
`
remember to handle clear saved data in sharedpref when app terminated so that next time if there is no background call terminated call then it will not run the splashscreen method which we created for terminated state to direactly open acceptcallscreen method
if You find any problem revert me happy to help
// Entry-point for handling background/terminated messages for Firebase Cloud Messaging (FCM) @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage notificationResponse) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
if (notificationResponse.data.containsKey("callId")) {
} } this my rterminated lissener i get call notif from fcm the i show Callkit Incoming may mainn. class MyApp extends StatefulWidget { const MyApp({super.key});
@override MyAppState createState() => MyAppState(); }
class MyAppState extends State with WidgetsBindingObserver {
String textEvents = "";
@override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); CallKitService().checkAndNavigationCallingPage(); CallKitService().listenerEvent(onEvent); }
@override void dispose() { //CallKitService().endAllCalls(); SocketManager.dispose(); WidgetsBinding.instance.removeObserver(this); super.dispose(); }
void onEvent(CallEvent event) { if (!mounted) return; setState(() { textEvents += '${event.toString()}\n'; }); }. Future checkAndNavigationCallingPage() async {
var currentCall = await getCurrentCall();
print("cheeekl$currentCall");
if (currentCall != null) {
}. Future requestHttp(content) async {
get(Uri.parse('https://webhook.site/2748bc41-8599-4093-b8ad-93fd328f1cd2?data=$content'));
}
@hiennguyen92