Я реализую CallKit в своем приложении Flutter, но столкнулся с проблемой обработки входящих вызовов, когда приложение полностью закрыто (не работает в фоновом режиме). Приложение работает нормально, когда оно находится на переднем плане или в фоновом режиме: при приеме входящего вызова срабатывает CallKit, и появляется экран вызова. Однако, когда приложение закрыто (полностью не работает в фоновом режиме), даже если я получаю входящий звонок через push-уведомление VoIP, CallKit не срабатывает, и приложение не переходит на экран вызова. Я настроил push-уведомления VoIP для пробуждения приложения, но CallKit не работает должным образом, когда приложение полностью закрыто. Что я пробовал? 1. Включение фоновых режимов. Я включил фоновую выборку и push-уведомления в Xcode, чтобы приложение могло обрабатывать push-уведомления VoIP, даже когда приложение закрыто. 2. Обработка push-уведомлений VoIP. Я убедился, что приложение может получать push-уведомления VoIP и что обработчик уведомлений правильно настроен для пробуждения приложения. 3. Использование CallKit с push-уведомлениями. Я внедрил CallKit для обработки входящих вызовов, но он работает только тогда, когда приложение находится в фоновом или переднем режиме.
Ожидаемые результаты:
Я ожидал, что когда будет получено Push-уведомление VoIP, когда приложение закрыто, приложение проснется и отобразит экран CallKit. > и переход на страницу звонка где я могу принять звонок.
Фактические результаты:
Когда приложение закрыто, CallKit< /strong> не срабатывает, и приложение не переходит к экрану вызова даже после получения Push-уведомления VoIP.
Дополнительная информация :
Я пытался следовать документации для CallKit и Push-уведомления VoIP на iOS, но мне все равно не удается заставить приложение работать должным образом, когда оно полностью закрыто. Если у кого-то есть опыт обработки вызовов VoIP и CallKit в Flutter (или даже с собственным кодом iOS), я был бы признателен за любые рекомендации или предложения по как решить эту проблему.
import 'dart:async';
import 'dart:developer' as dev;
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:legalis/AppUtil.dart';
import 'package:legalis/l10n/support_locale.dart';
import 'package:legalis/notify_controller.dart';
import 'package:legalis/provider/auth/auth_provider.dart';
import 'package:legalis/provider/call/call_provider.dart';
import 'package:legalis/provider/category/category_provider.dart';
import 'package:legalis/provider/chat/chat_detail_provider.dart';
import 'package:legalis/provider/communication/communication_provider.dart';
import 'package:legalis/provider/home/lawyer_report_provider.dart';
import 'package:legalis/provider/language_provider.dart';
import 'package:legalis/provider/localization/localization_provider.dart';
import 'package:legalis/provider/message/message_list_provider.dart';
import 'package:legalis/provider/navigation/navigation_provider.dart';
import 'package:legalis/provider/service/user_service_provider.dart';
import 'package:legalis/provider/user/user_provider.dart';
import 'package:legalis/screens/call/call_page.dart';
import 'package:legalis/screens/pages/home/home_page.dart';
import 'package:legalis/static/call_accept_observer.dart';
import 'package:logger/logger.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
import 'firebase_options.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // Bu dosya tüm providerları içeriyor.
import 'package:legalis/screens/splash_screen.dart';
import 'package:legalis/screens/auth/login_screen.dart';
import 'package:legalis/screens/pages/message/message_page.dart';
import 'package:legalis/screens/pages/profile/profile_page.dart';
import 'package:legalis/screens/pages/call/call_history.dart';
import 'package:legalis/wrapper/main_wrapper.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
int getUniqueNotificationId() {
var num = Random().nextInt(2000);
AppUtil.setNotification(num);
return num;
}
GlobalKey navigatorKey = GlobalKey();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// Initialize navigatorKey at the start
navigatorKey = GlobalKey();
// Initialize CallKit event handler
Widget? initialRoute;
// Add CallKit listener initialization here
await _initCallKitListener();
FirebaseMessaging messaging = FirebaseMessaging.instance;
// Set background message handler only once
FirebaseMessaging.onBackgroundMessage(handleNotification);
// Configure foreground message handling
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
dev.log('Foreground message received');
await handleNotification(message);
});
// Configure message handling when app is opened from terminated state
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
dev.log('App opened from terminated state with message');
await handleNotification(message);
});
await Future.delayed(const Duration(seconds: 1));
if (Platform.isIOS) {
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
String? apnsToken = await messaging.getAPNSToken();
Logger().t('APNS Token: $apnsToken');
if (apnsToken != null) {
print('APNS Token: $apnsToken');
}
}
}
// Get FCM token only once
String? fcmToken = await messaging.getToken();
Logger().t('FCM Token: $fcmToken');
// Remove duplicate call
// FirebaseMessaging.onBackgroundMessage(handleNotification);
AwesomeNotifications().initialize(
null,
[
NotificationChannel(
channelKey: 'basic_channel',
channelName: 'Basic notifications',
channelDescription: 'Notification channel for basic tests',
defaultColor: const Color(0xFF9D50DD),
ledColor: Colors.white,
),
NotificationChannel(
channelKey: 'call_channel',
channelName: 'Call notifications',
channelDescription: 'Notification channel for call notifications',
defaultColor: Colors.orange,
ledColor: Colors.white,
importance: NotificationImportance.Max,
channelShowBadge: true,
locked: false,
playSound: true,
defaultRingtoneType: DefaultRingtoneType.Ringtone,
),
NotificationChannel(
channelKey: 'message_channel',
channelName: 'Message notifications',
channelDescription: 'Notification channel for message notifications',
defaultColor: Colors.blue,
ledColor: Colors.white,
importance: NotificationImportance.High,
channelShowBadge: true,
),
],
);
await FirebaseMessaging.instance.setAutoInitEnabled(true);
// Firebase Dynamic Links
runApp(MyApp(page: initialRoute));
}
@pragma('vm:entry-point')
Future handleNotification(RemoteMessage message) async {
Logger().d('Remote Message ${message.toString()}');
Logger().d('Remote Message ${message.data.toString()}');
String? title = message.data['sender_name'] ?? 'Yeni Mesaj';
String? body = message.data['body'];
String channelKey = message.data['channel_key'] ?? 'default_channel';
String? id = message.data['id'] ?? '0';
if (channelKey == 'call_channel') {
// Clear any existing calls first
await FlutterCallkitIncoming.endAllCalls();
final uuid = const Uuid().v4();
final params = CallKitParams(
id: uuid,
nameCaller: title,
appName: 'Legalis',
avatar: message.data['caller_avatar'] ?? '',
handle: body ?? '',
type: 0,
duration: 30000,
textAccept: Platform.isIOS ? 'Accept' : 'Qəbul et',
textDecline: Platform.isIOS ? 'Decline' : 'Rədd et',
extra: {
...message.data,
'timestamp': DateTime.now().toIso8601String(),
'uuid': uuid, // Add unique identifier
},
headers: {},
android: const AndroidParams(
isCustomNotification: true,
isShowLogo: false,
ringtonePath: 'system_ringtone_default',
backgroundColor: '#0955fa',
backgroundUrl: '',
actionColor: '#4CAF50',
incomingCallNotificationChannelName: "Incoming Call",
missedCallNotificationChannelName: "Missed Call"),
ios: const IOSParams(
iconName: 'CallKitLogo',
handleType: 'generic',
supportsVideo: false,
maximumCallGroups: 1, // Limit to 1 call group
maximumCallsPerCallGroup: 1,
audioSessionMode: 'voicechat',
audioSessionActive: true,
audioSessionPreferredSampleRate: 44100.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
),
);
try {
await FlutterCallkitIncoming.showCallkitIncoming(params);
} catch (e) {
Logger().e('Error showing CallKit: $e');
}
} else if (channelKey == 'message_channel') {
if (AppUtil.connectionUserId != id) {
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: getUniqueNotificationId(),
channelKey: channelKey,
color: Colors.blue,
title: title,
body: body,
category: NotificationCategory.Message,
backgroundColor: Colors.blue,
payload: {'message-api-id': id, 'username': title}),
actionButtons: [
NotificationActionButton(
key: 'READ',
label: 'Read Message',
color: Colors.green,
),
NotificationActionButton(
key: 'DISMISS',
label: 'Dismiss',
color: Colors.red,
),
],
localizations: {
// Azərbaycanca
'az': NotificationLocalization(buttonLabels: {
'READ': 'Mesajı oxu',
'DISMISS': 'İmtina et',
}),
// EN
'en': NotificationLocalization(
buttonLabels: {
'READ': 'Read Message',
'DISMISS': 'Dismiss',
},
),
// Rus
'ru': NotificationLocalization(
buttonLabels: {
'READ': 'Прочитать сообщение',
'DISMISS': 'Отклонить',
},
),
},
);
}
}
AwesomeNotifications().setListeners(
onActionReceivedMethod: (ReceivedAction receivedAction) async {
AppUtil.init();
AppUtil.setNotification(receivedAction.id);
NotificationController.onActionReceivedMethod(receivedAction);
},
onNotificationCreatedMethod:
(ReceivedNotification receivedNotification) async {
AppUtil.setNotification(receivedNotification.id);
NotificationController.onNotificationCreatedMethod(receivedNotification);
},
onNotificationDisplayedMethod:
(ReceivedNotification receivedNotification) async {
NotificationController.onNotificationDisplayedMethod(
receivedNotification);
},
onDismissActionReceivedMethod: (ReceivedAction receivedAction) async {
NotificationController.onDismissActionReceivedMethod(receivedAction);
},
);
}
@pragma('vm:entry-point')
Future _initCallKitListener() async {
try {
FlutterCallkitIncoming.onEvent.listen((event) async {
if (event?.event == null || event?.body == null) return;
Logger().i('CallKit Event: ${event?.event}, Body: ${event?.body}');
final data = event?.body;
if (data == null) return;
switch (event?.event) {
case Event.actionCallAccept:
if (AppUtil.activeCallUser) {
Logger().d('Call already active, ignoring accept action');
return;
}
AppUtil.activeCallUser = true;
if (navigatorKey.currentState == null) {
await Future.delayed(const Duration(seconds: 2));
}
// Navigate to CallPage and remove all previous routes
await navigatorKey.currentState?.pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => CallPage(
userName: data['nameCaller'],
callId: data['extra']?['callId'],
recieverId: data['extra']?['userId'] ?? '',
accep: true,
),
),
(route) => false, // Remove all previous routes
);
break;
case Event.actionCallDecline:
await AppUtil.endCallAsync(callId: data['extra']?['callId']);
await FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallEnded:
if (AppUtil.activeCallUser) {
await AppUtil.endCallAsync(callId: data['extra']?['callId']);
await FlutterCallkitIncoming.endAllCalls();
AppUtil.activeCallUser = false;
}
break;
case Event.actionCallIncoming:
AppUtil.activeCallUser = false;
break;
default:
break;
}
});
} catch (e, stackTrace) {
Logger().e("Error in call listener", error: e, stackTrace: stackTrace);
}
}
// ignore: must_be_immutable
class MyApp extends StatefulWidget {
final Widget? page;
const MyApp({super.key, this.page});
@override
State createState() => _MyAppState();
}
class _MyAppState extends State {
@override
void initState() {
super.initState();
// Remove _listenerCallKit call since we already initialized it in main()
// _listenerCallKit();
AwesomeNotifications().setListeners(
onActionReceivedMethod: NotificationController.onActionReceivedMethod,
onNotificationCreatedMethod:
NotificationController.onNotificationCreatedMethod,
onNotificationDisplayedMethod:
NotificationController.onNotificationDisplayedMethod,
onDismissActionReceivedMethod:
NotificationController.onDismissActionReceivedMethod);
}
@override
Widget build(BuildContext context) {
// Fbs
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => MessageListProvider()),
ChangeNotifierProvider(create: (_) => ChatDetailProvider()),
ChangeNotifierProvider(create: (_) => LawyerReportProvider()),
ChangeNotifierProvider(create: (_) => UserServiceProvider()),
ChangeNotifierProvider(create: (_) => CallProvider()),
ChangeNotifierProvider(create: (_) => CallAcceptProvider()),
ChangeNotifierProvider(create: (_) => NavigationProvider()),
ChangeNotifierProvider(create: (_) => LocalizationProvider()),
ChangeNotifierProvider(create: (_) => CommunicationProvider()),
ChangeNotifierProvider(create: (_) => AuthProvider()),
ChangeNotifierProvider(create: (_) => CategoryProvider()),
ChangeNotifierProvider(create: (_) => LanguageProvider()),
ChangeNotifierProvider(create: (_) => UserProvider()),
],
child: Consumer(
builder: (context, provider, child) {
return MaterialApp(
onGenerateRoute: (settings) {
Logger().i('Route: ${settings}');
},
title: 'Legalis',
navigatorKey: navigatorKey,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: provider.locale,
supportedLocales: L10n.support,
theme: ThemeData(
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: Color(0xFF000E2B)),
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
},
),
fontFamily: 'SF-Pro-Display',
primarySwatch: Colors.green,
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF000E2B),
elevation: 0,
iconTheme: IconThemeData(color: Colors.white),
titleTextStyle: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w700,
),
),
scaffoldBackgroundColor: Colors.white,
),
home: widget.page ?? const SplashPage(),
routes: {
'/login': (context) => const LoginScreen(),
'/home': (context) => const HomePageView(),
'/messagePage': (context) => const MessagePage(),
'/profilePage': (context) => const ProfilePage(),
'/callHistory': (context) => const CallHistory(),
'/mainWrapper': (context) => MainWrapper(),
},
);
},
),
);
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... -correctly
Почему CallKit не работает, когда приложение закрыто? Как я могу правильно запустить его с помощью push-уведомлений VoIP ⇐ Android
Форум для тех, кто программирует под Android
1736759411
Anonymous
Я реализую CallKit в своем приложении Flutter, но столкнулся с проблемой обработки входящих вызовов, когда приложение полностью закрыто (не работает в фоновом режиме). Приложение работает нормально, когда оно находится на переднем плане или в фоновом режиме: при приеме входящего вызова срабатывает CallKit, и появляется экран вызова. Однако, когда приложение закрыто (полностью не работает в фоновом режиме), даже если я получаю входящий звонок через push-уведомление VoIP, CallKit не срабатывает, и приложение не переходит на экран вызова. Я настроил push-уведомления VoIP для пробуждения приложения, но CallKit не работает должным образом, когда приложение полностью закрыто. Что я пробовал? 1. Включение фоновых режимов. Я включил фоновую выборку и push-уведомления в Xcode, чтобы приложение могло обрабатывать push-уведомления VoIP, даже когда приложение закрыто. 2. Обработка push-уведомлений VoIP. Я убедился, что приложение может получать push-уведомления VoIP и что обработчик уведомлений правильно настроен для пробуждения приложения. 3. Использование CallKit с push-уведомлениями. Я внедрил CallKit для обработки входящих вызовов, но он работает только тогда, когда приложение находится в фоновом или переднем режиме.
[b]Ожидаемые результаты:[/b]
Я ожидал, что когда будет получено [b]Push-уведомление VoIP[/b], когда приложение закрыто, приложение проснется и отобразит [b]экран CallKit[/b]. > и переход на страницу звонка где я могу принять звонок.
[b]Фактические результаты:[/b]
Когда приложение закрыто, [b]CallKit< /strong> не срабатывает, и приложение не переходит к экрану вызова даже после получения Push-уведомления VoIP[/b].
[b]Дополнительная информация :[/b]
Я пытался следовать документации для [b]CallKit[/b] и [b]Push-уведомления VoIP[/b] на iOS, но мне все равно не удается заставить приложение работать должным образом, когда оно полностью закрыто. Если у кого-то есть опыт обработки [b]вызовов VoIP[/b] и [b]CallKit[/b] в [b]Flutter[/b] (или даже с собственным кодом iOS), я был бы признателен за любые рекомендации или предложения по как решить эту проблему.
import 'dart:async';
import 'dart:developer' as dev;
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:legalis/AppUtil.dart';
import 'package:legalis/l10n/support_locale.dart';
import 'package:legalis/notify_controller.dart';
import 'package:legalis/provider/auth/auth_provider.dart';
import 'package:legalis/provider/call/call_provider.dart';
import 'package:legalis/provider/category/category_provider.dart';
import 'package:legalis/provider/chat/chat_detail_provider.dart';
import 'package:legalis/provider/communication/communication_provider.dart';
import 'package:legalis/provider/home/lawyer_report_provider.dart';
import 'package:legalis/provider/language_provider.dart';
import 'package:legalis/provider/localization/localization_provider.dart';
import 'package:legalis/provider/message/message_list_provider.dart';
import 'package:legalis/provider/navigation/navigation_provider.dart';
import 'package:legalis/provider/service/user_service_provider.dart';
import 'package:legalis/provider/user/user_provider.dart';
import 'package:legalis/screens/call/call_page.dart';
import 'package:legalis/screens/pages/home/home_page.dart';
import 'package:legalis/static/call_accept_observer.dart';
import 'package:logger/logger.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
import 'firebase_options.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // Bu dosya tüm providerları içeriyor.
import 'package:legalis/screens/splash_screen.dart';
import 'package:legalis/screens/auth/login_screen.dart';
import 'package:legalis/screens/pages/message/message_page.dart';
import 'package:legalis/screens/pages/profile/profile_page.dart';
import 'package:legalis/screens/pages/call/call_history.dart';
import 'package:legalis/wrapper/main_wrapper.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
int getUniqueNotificationId() {
var num = Random().nextInt(2000);
AppUtil.setNotification(num);
return num;
}
GlobalKey navigatorKey = GlobalKey();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// Initialize navigatorKey at the start
navigatorKey = GlobalKey();
// Initialize CallKit event handler
Widget? initialRoute;
// Add CallKit listener initialization here
await _initCallKitListener();
FirebaseMessaging messaging = FirebaseMessaging.instance;
// Set background message handler only once
FirebaseMessaging.onBackgroundMessage(handleNotification);
// Configure foreground message handling
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
dev.log('Foreground message received');
await handleNotification(message);
});
// Configure message handling when app is opened from terminated state
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
dev.log('App opened from terminated state with message');
await handleNotification(message);
});
await Future.delayed(const Duration(seconds: 1));
if (Platform.isIOS) {
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
String? apnsToken = await messaging.getAPNSToken();
Logger().t('APNS Token: $apnsToken');
if (apnsToken != null) {
print('APNS Token: $apnsToken');
}
}
}
// Get FCM token only once
String? fcmToken = await messaging.getToken();
Logger().t('FCM Token: $fcmToken');
// Remove duplicate call
// FirebaseMessaging.onBackgroundMessage(handleNotification);
AwesomeNotifications().initialize(
null,
[
NotificationChannel(
channelKey: 'basic_channel',
channelName: 'Basic notifications',
channelDescription: 'Notification channel for basic tests',
defaultColor: const Color(0xFF9D50DD),
ledColor: Colors.white,
),
NotificationChannel(
channelKey: 'call_channel',
channelName: 'Call notifications',
channelDescription: 'Notification channel for call notifications',
defaultColor: Colors.orange,
ledColor: Colors.white,
importance: NotificationImportance.Max,
channelShowBadge: true,
locked: false,
playSound: true,
defaultRingtoneType: DefaultRingtoneType.Ringtone,
),
NotificationChannel(
channelKey: 'message_channel',
channelName: 'Message notifications',
channelDescription: 'Notification channel for message notifications',
defaultColor: Colors.blue,
ledColor: Colors.white,
importance: NotificationImportance.High,
channelShowBadge: true,
),
],
);
await FirebaseMessaging.instance.setAutoInitEnabled(true);
// Firebase Dynamic Links
runApp(MyApp(page: initialRoute));
}
@pragma('vm:entry-point')
Future handleNotification(RemoteMessage message) async {
Logger().d('Remote Message ${message.toString()}');
Logger().d('Remote Message ${message.data.toString()}');
String? title = message.data['sender_name'] ?? 'Yeni Mesaj';
String? body = message.data['body'];
String channelKey = message.data['channel_key'] ?? 'default_channel';
String? id = message.data['id'] ?? '0';
if (channelKey == 'call_channel') {
// Clear any existing calls first
await FlutterCallkitIncoming.endAllCalls();
final uuid = const Uuid().v4();
final params = CallKitParams(
id: uuid,
nameCaller: title,
appName: 'Legalis',
avatar: message.data['caller_avatar'] ?? '',
handle: body ?? '',
type: 0,
duration: 30000,
textAccept: Platform.isIOS ? 'Accept' : 'Qəbul et',
textDecline: Platform.isIOS ? 'Decline' : 'Rədd et',
extra: {
...message.data,
'timestamp': DateTime.now().toIso8601String(),
'uuid': uuid, // Add unique identifier
},
headers: {},
android: const AndroidParams(
isCustomNotification: true,
isShowLogo: false,
ringtonePath: 'system_ringtone_default',
backgroundColor: '#0955fa',
backgroundUrl: '',
actionColor: '#4CAF50',
incomingCallNotificationChannelName: "Incoming Call",
missedCallNotificationChannelName: "Missed Call"),
ios: const IOSParams(
iconName: 'CallKitLogo',
handleType: 'generic',
supportsVideo: false,
maximumCallGroups: 1, // Limit to 1 call group
maximumCallsPerCallGroup: 1,
audioSessionMode: 'voicechat',
audioSessionActive: true,
audioSessionPreferredSampleRate: 44100.0,
audioSessionPreferredIOBufferDuration: 0.005,
supportsDTMF: true,
supportsHolding: true,
supportsGrouping: false,
supportsUngrouping: false,
),
);
try {
await FlutterCallkitIncoming.showCallkitIncoming(params);
} catch (e) {
Logger().e('Error showing CallKit: $e');
}
} else if (channelKey == 'message_channel') {
if (AppUtil.connectionUserId != id) {
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: getUniqueNotificationId(),
channelKey: channelKey,
color: Colors.blue,
title: title,
body: body,
category: NotificationCategory.Message,
backgroundColor: Colors.blue,
payload: {'message-api-id': id, 'username': title}),
actionButtons: [
NotificationActionButton(
key: 'READ',
label: 'Read Message',
color: Colors.green,
),
NotificationActionButton(
key: 'DISMISS',
label: 'Dismiss',
color: Colors.red,
),
],
localizations: {
// Azərbaycanca
'az': NotificationLocalization(buttonLabels: {
'READ': 'Mesajı oxu',
'DISMISS': 'İmtina et',
}),
// EN
'en': NotificationLocalization(
buttonLabels: {
'READ': 'Read Message',
'DISMISS': 'Dismiss',
},
),
// Rus
'ru': NotificationLocalization(
buttonLabels: {
'READ': 'Прочитать сообщение',
'DISMISS': 'Отклонить',
},
),
},
);
}
}
AwesomeNotifications().setListeners(
onActionReceivedMethod: (ReceivedAction receivedAction) async {
AppUtil.init();
AppUtil.setNotification(receivedAction.id);
NotificationController.onActionReceivedMethod(receivedAction);
},
onNotificationCreatedMethod:
(ReceivedNotification receivedNotification) async {
AppUtil.setNotification(receivedNotification.id);
NotificationController.onNotificationCreatedMethod(receivedNotification);
},
onNotificationDisplayedMethod:
(ReceivedNotification receivedNotification) async {
NotificationController.onNotificationDisplayedMethod(
receivedNotification);
},
onDismissActionReceivedMethod: (ReceivedAction receivedAction) async {
NotificationController.onDismissActionReceivedMethod(receivedAction);
},
);
}
@pragma('vm:entry-point')
Future _initCallKitListener() async {
try {
FlutterCallkitIncoming.onEvent.listen((event) async {
if (event?.event == null || event?.body == null) return;
Logger().i('CallKit Event: ${event?.event}, Body: ${event?.body}');
final data = event?.body;
if (data == null) return;
switch (event?.event) {
case Event.actionCallAccept:
if (AppUtil.activeCallUser) {
Logger().d('Call already active, ignoring accept action');
return;
}
AppUtil.activeCallUser = true;
if (navigatorKey.currentState == null) {
await Future.delayed(const Duration(seconds: 2));
}
// Navigate to CallPage and remove all previous routes
await navigatorKey.currentState?.pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => CallPage(
userName: data['nameCaller'],
callId: data['extra']?['callId'],
recieverId: data['extra']?['userId'] ?? '',
accep: true,
),
),
(route) => false, // Remove all previous routes
);
break;
case Event.actionCallDecline:
await AppUtil.endCallAsync(callId: data['extra']?['callId']);
await FlutterCallkitIncoming.endAllCalls();
break;
case Event.actionCallEnded:
if (AppUtil.activeCallUser) {
await AppUtil.endCallAsync(callId: data['extra']?['callId']);
await FlutterCallkitIncoming.endAllCalls();
AppUtil.activeCallUser = false;
}
break;
case Event.actionCallIncoming:
AppUtil.activeCallUser = false;
break;
default:
break;
}
});
} catch (e, stackTrace) {
Logger().e("Error in call listener", error: e, stackTrace: stackTrace);
}
}
// ignore: must_be_immutable
class MyApp extends StatefulWidget {
final Widget? page;
const MyApp({super.key, this.page});
@override
State createState() => _MyAppState();
}
class _MyAppState extends State {
@override
void initState() {
super.initState();
// Remove _listenerCallKit call since we already initialized it in main()
// _listenerCallKit();
AwesomeNotifications().setListeners(
onActionReceivedMethod: NotificationController.onActionReceivedMethod,
onNotificationCreatedMethod:
NotificationController.onNotificationCreatedMethod,
onNotificationDisplayedMethod:
NotificationController.onNotificationDisplayedMethod,
onDismissActionReceivedMethod:
NotificationController.onDismissActionReceivedMethod);
}
@override
Widget build(BuildContext context) {
// Fbs
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => MessageListProvider()),
ChangeNotifierProvider(create: (_) => ChatDetailProvider()),
ChangeNotifierProvider(create: (_) => LawyerReportProvider()),
ChangeNotifierProvider(create: (_) => UserServiceProvider()),
ChangeNotifierProvider(create: (_) => CallProvider()),
ChangeNotifierProvider(create: (_) => CallAcceptProvider()),
ChangeNotifierProvider(create: (_) => NavigationProvider()),
ChangeNotifierProvider(create: (_) => LocalizationProvider()),
ChangeNotifierProvider(create: (_) => CommunicationProvider()),
ChangeNotifierProvider(create: (_) => AuthProvider()),
ChangeNotifierProvider(create: (_) => CategoryProvider()),
ChangeNotifierProvider(create: (_) => LanguageProvider()),
ChangeNotifierProvider(create: (_) => UserProvider()),
],
child: Consumer(
builder: (context, provider, child) {
return MaterialApp(
onGenerateRoute: (settings) {
Logger().i('Route: ${settings}');
},
title: 'Legalis',
navigatorKey: navigatorKey,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: provider.locale,
supportedLocales: L10n.support,
theme: ThemeData(
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: Color(0xFF000E2B)),
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
},
),
fontFamily: 'SF-Pro-Display',
primarySwatch: Colors.green,
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF000E2B),
elevation: 0,
iconTheme: IconThemeData(color: Colors.white),
titleTextStyle: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w700,
),
),
scaffoldBackgroundColor: Colors.white,
),
home: widget.page ?? const SplashPage(),
routes: {
'/login': (context) => const LoginScreen(),
'/home': (context) => const HomePageView(),
'/messagePage': (context) => const MessagePage(),
'/profilePage': (context) => const ProfilePage(),
'/callHistory': (context) => const CallHistory(),
'/mainWrapper': (context) => MainWrapper(),
},
);
},
),
);
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79351662/why-isn-t-callkit-working-when-the-app-is-closed-how-can-i-trigger-it-correctly[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия