Einrichten von Firebase Cloud Messaging (FCM) für Push -Benachrichtigungen. hat sichergestellt, dass nsusernotificationalert in der info.plist hinzugefügt wird. Auf iOS erscheint in
im Vordergrund und im Hintergrund keine Benachrichtigung. Debugging -Protokolle: In den Protokollen werden keine Fehler
in Bezug auf Push -Benachrichtigungen angezeigt. Überprüft, dass FCM
Token auf iOS korrekt erzeugt wird.
Code: Select all
xmlns:tools="http://schemas.android.com/tools"
package="com.sambuq.care_first">
android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
android:authorities="${applicationId}.flutter_downloader.provider"
android:exported="false"
android:grantUriPermissions="true">
< /code>
** Call Manager-Klasse ** < /p>
import 'package:care_first/bloc/auth_bloc/bloc/auth_bloc.dart';
import 'package:care_first/routing/route_names.dart';
import 'package:care_first/screens/settings/my_appointments/doctor_appointment/models/my_appointment.dart';
import 'package:care_first/shared/helper/helper_methods.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:universal_io/io.dart';
import 'package:connectycube_flutter_call_kit/connectycube_flutter_call_kit.dart';
import 'package:connectycube_sdk/connectycube_sdk.dart';
import 'call_kit_manager.dart';
import '../utils/consts.dart';
class CallManager {
static String TAG = "CallManager";
static CallManager get instance => _getInstance();
static CallManager? _instance;
static CallManager _getInstance() {
return _instance ??= CallManager._internal();
}
factory CallManager() => _getInstance();
CallManager._internal();
P2PClient? _callClient;
P2PSession? _currentCall;
BuildContext? context;
MediaStream? localMediaStream;
Map remoteStreams = {};
GlobalKey? navigatorKey;
String? selfCubeId;
late String resourceId;
SystemMessagesManager? systemMessagesManager =
CubeChatConnection.instance.systemMessagesManager;
CubeMessage systemMessage = CubeMessage();
final player = AudioPlayer();
Function(bool, String)? onMicMuted;
init(
BuildContext context,
GlobalKey navigatorKey,
String selfCubeId,
String resourceId,
) {
this.context = context;
this.navigatorKey = navigatorKey;
this.selfCubeId = selfCubeId;
this.resourceId = resourceId;
_initCustomMediaConfigs();
if (CubeChatConnection.instance.isAuthenticated()) {
_initCalls(context);
} else {
_initChatConnectionStateListener(context);
}
_initCallKit();
}
destroy() {
_callClient?.destroy();
_callClient = null;
}
void _initCustomMediaConfigs() {
RTCMediaConfig mediaConfig = RTCMediaConfig.instance;
mediaConfig.minHeight = 340;
mediaConfig.minWidth = 480;
mediaConfig.minFrameRate = 25;
RTCConfig.instance.statsReportsInterval = 200;
}
void _initCalls(BuildContext context) {
if (_callClient == null) {
_callClient = P2PClient.instance;
_callClient!.init();
}
// _callClient is P2PClient
_callClient!.onReceiveNewSession = (callSession) async {
print("${'*' * 10} RECEIVED NEW CALL SESSION ${'*' * 10}");
// if (_currentCall != null &&
// _currentCall!.sessionId != callSession.sessionId &&
// _currentCall!.opponentsIds.first.toString() != selfCubeId) {
// callSession.reject();
// return;
// }
if (navigatorKey!.currentContext!.read().user.persona ==
"patient") {
await player
.setReleaseMode(ReleaseMode.loop)
.then(
(value) => player.setSource(AssetSource('audio/ringtone.mp3')))
.then((value) => player.resume());
}
_currentCall = callSession;
var callState = await _getCallState(_currentCall!.sessionId);
await Future.delayed(Duration(seconds: 1));
if (callState == CallState.REJECTED) {
reject(_currentCall!.sessionId, false);
} else if (callState == CallState.ACCEPTED) {
acceptCall(_currentCall!.sessionId,
_currentCall?.cubeSdp.userInfo ?? {}, false);
} else if (callState == CallState.UNKNOWN ||
callState == CallState.PENDING) {
if (callState == CallState.UNKNOWN &&
(Platform.isIOS || Platform.isAndroid)) {
await ConnectycubeFlutterCallKit.setCallState(
sessionId: _currentCall!.sessionId, callState: CallState.PENDING);
}
if (_currentCall!.cubeSdp.callerId.toString() != selfCubeId) {
navigatorKey!.currentContext!.read().p2pSession =
callSession;
// await Future.delayed(Duration(seconds: 1));
// await ConnectycubeFlutterCallKit.showCallNotification(CallEvent(
// sessionId: _currentCall!.sessionId,
// callType: CallType.VIDEO_CALL,
// callerId: _currentCall!.cubeSdp.callerId,
// callerName: "YASH",
// opponentsIds: _currentCall!.opponentsIds,
// userInfo: _currentCall?.cubeSdp.userInfo ?? {},
// ));
print("NOTIFICATION NOT CALLED");
_showIncomingCallScreen(_currentCall!, navigatorKey!.currentContext!);
}
}
_currentCall?.onLocalStreamReceived = (localStream) {
localMediaStream = localStream;
};
_currentCall?.onRemoteStreamReceived = (session, userId, stream) {
remoteStreams[userId] = stream;
};
_currentCall?.onRemoteStreamRemoved = (session, userId, stream) {
remoteStreams.remove(userId);
};
_currentCall?.onReceiveHungUpFromUser =
(session, userId, [userInfo]) async {
print("CALL_MANAGER: onReceiveHungUpFromUser");
/* systemMessage.recipientId = int.tryParse(selfCubeId!);
systemMessage.properties["resourceId"] = resourceId;
systemMessage.properties["action"] = "CALL_HUNGUP";
print("-------------BROADCASTING CALL HUNGUP EVENT-----------");
systemMessagesManager?.sendSystemMessage(systemMessage); */
broadcastSystemMessage("CALL_HUNGUP");
await player.release();
if (GoRouter.of(navigatorKey!.currentContext!)!.location ==
RoutesName.incomingVideoCall) {
GoRouter.of(navigatorKey!.currentContext!).pop();
}
};
};
_callClient!.onSessionClosed = (callSession) async {
if (_currentCall != null &&
_currentCall!.sessionId == callSession.sessionId) {
_currentCall = null;
localMediaStream?.getTracks().forEach((track) async {
await track.stop();
});
await localMediaStream?.dispose();
localMediaStream = null;
remoteStreams.forEach((key, value) async {
await value.dispose();
});
remoteStreams.clear();
CallKitManager.instance.processCallFinished(callSession.sessionId);
if (GoRouter.of(navigatorKey!.currentContext!)!.location ==
RoutesName.incomingVideoCall) {
GoRouter.of(navigatorKey!.currentContext!).pop();
}
}
};
}
void startNewCall(BuildContext context, int callType, int patientCubeId,
MyAppointment appointment, String? businessId, String? moduleId) async {
this.context = context;
Set opponents = {patientCubeId};
if (opponents.isEmpty) return;
if (!kIsWeb) {
if (Platform.isIOS) {
Helper.setAppleAudioIOMode(AppleAudioIOMode.localAndRemote,
preferSpeakerOutput: true);
}
}
P2PSession callSession =
_callClient!.createCallSession(callType, opponents);
_currentCall = callSession;
// storing it in authbloc
context.read().p2pSession = callSession;
context.read().resourceId = resourceId;
context.read().selfCubeId = selfCubeId;
String callerName;
if (appointment.doctorMap?["firstname"] != null) {
callerName =
"${appointment.doctorMap?["firstname"]} ${appointment.doctorMap?["lastname"]}";
} else {
callerName = "";
}
_sendStartCallSignalForOffliners(_currentCall!, callerName);
GoRouter.of(context)
.pushNamed(RoutesName.videoCallDoctorRoute, pathParameters: {
'businessId': encrypt(text: businessId ?? '', context: context),
}, queryParameters: {
'moduleId': moduleId,
}, extra: {
// 'callSession': callSession,
'appointment': appointment,
});
}
void _showIncomingCallScreen(P2PSession callSession, BuildContext context) {
if (navigatorKey!.currentContext != null) {
GoRouter.of(navigatorKey!.currentContext!).pushNamed(
RoutesName.incomingVideoCall,
extra: Map.from(
{"resourceId": resourceId, "selfCubeId": selfCubeId}));
}
}
void acceptCall(
String sessionId,
Map userInfo,
bool fromCallkit,
) async {
await player.release();
log('acceptCall, from callKit: $fromCallkit', TAG);
//ConnectycubeFlutterCallKit.setOnLockScreenVisibility(isVisible: true);
if (_currentCall != null) {
if (context != null) {
// if (AppLifecycleState.resumed !=
// WidgetsBinding.instance.lifecycleState) {
await _currentCall?.acceptCall();
// }
MyAppointment appointment = MyAppointment(
id: userInfo['appointment_id'], doctor: userInfo['doctor_id']);
log(userInfo.toString(), "User Info from AcceptCall");
if (!fromCallkit) {
await ConnectycubeFlutterCallKit.reportCallAccepted(
sessionId: sessionId);
}
broadcastSystemMessage("CALL_ACCEPTED");
navigatorKey!.currentContext!.read().p2pSession =
_currentCall;
GoRouter.of(navigatorKey!.currentContext!).pushReplacementNamed(
RoutesName.videoCallPatientRoute,
extra: Map.from({
// 'currentCall': _currentCall!,
'appointment': appointment,
}),
);
/* systemMessage.recipientId = int.tryParse(selfCubeId!);
systemMessage.properties["resourceId"] = resourceId;
systemMessage.properties["action"] = "CALL_ACCEPTED";
print("-------------BROADCASTING ACCEPT CALL EVENT-----------");
systemMessagesManager?.sendSystemMessage(systemMessage); */
}
if (!kIsWeb) {
if (Platform.isIOS) {
await Helper.setAppleAudioIOMode(AppleAudioIOMode.localAndRemote,
preferSpeakerOutput: true);
}
}
}
}
void reject(String sessionId, bool fromCallkit) {
if (_currentCall != null) {
player.release();
broadcastSystemMessage("CALL_REJECTED");
if (fromCallkit) {
ConnectycubeFlutterCallKit.setOnLockScreenVisibility(isVisible: false);
} else {
CallKitManager.instance.processCallFinished(_currentCall!.sessionId);
}
_currentCall!.reject();
_sendEndCallSignalForOffliners(_currentCall, null);
}
}
void hungUp() {
if (_currentCall != null) {
player.release();
CallKitManager.instance.processCallFinished(_currentCall!.sessionId);
_currentCall!.hungUp();
_sendEndCallSignalForOffliners(_currentCall, null);
}
}
CreateEventParams _getCallEventParameters(
P2PSession currentCall, String? callerName) {
/* String? callerName = users
.where((cubeUser) => cubeUser.id == currentCall.callerId)
.first
.fullName; */
CreateEventParams params = CreateEventParams();
params.parameters = {
'message':
"Incoming ${currentCall.callType == CallType.VIDEO_CALL ? "Video" : "Audio"} call",
PARAM_CALL_TYPE: currentCall.callType,
PARAM_SESSION_ID: currentCall.sessionId,
PARAM_CALLER_ID: currentCall.callerId,
PARAM_CALL_OPPONENTS: currentCall.opponentsIds.join(','),
PARAM_CALLER_NAME: callerName ?? "Doctor",
};
params.notificationType = NotificationType.PUSH;
params.environment = CubeEnvironment.DEVELOPMENT;
//kReleaseMode ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;
params.usersIds = currentCall.opponentsIds.toList();
return params;
}
Future _sendStartCallSignalForOffliners(
P2PSession currentCall, String callerName) async {
CreateEventParams params = _getCallEventParameters(currentCall, callerName);
params.parameters[PARAM_SIGNAL_TYPE] = SIGNAL_TYPE_START_CALL;
params.parameters[PARAM_IOS_VOIP] = 1;
params.parameters[PARAM_EXPIRATION] = 0;
params.parameters['ios_push_type'] = 'background';
await createEvent(params.getEventForRequest()).then((cubeEvent) {
log("Event for offliners created: $cubeEvent");
}).catchError((error) {
log("ERROR occurs during create event");
});
}
void _sendEndCallSignalForOffliners(
P2PSession? currentCall, String? callerName) {
if (currentCall == null) return;
CubeUser? currentUser = CubeChatConnection.instance.currentUser;
if (currentUser == null || currentUser.id != currentCall.callerId) return;
CreateEventParams params = _getCallEventParameters(currentCall, callerName);
params.parameters[PARAM_SIGNAL_TYPE] = SIGNAL_TYPE_END_CALL;
createEvent(params.getEventForRequest()).then((cubeEvent) {
log("Event for offliners created");
}).catchError((error) {
log("ERROR occurs during create event");
});
}
void _initCallKit() {
CallKitManager.instance.init(
onCallAccepted: (uuid) {
acceptCall(uuid, _currentCall?.cubeSdp.userInfo ?? {}, true);
},
onCallEnded: (uuid) {
reject(uuid, true);
},
onMuteCall: (mute, uuid) {
onMicMuted?.call(mute, uuid);
},
);
}
void _initChatConnectionStateListener(BuildContext context) {
CubeChatConnection.instance.connectionStateStream.listen((state) {
if (CubeChatConnectionState.Ready == state) {
_initCalls(context);
}
});
}
Future _getCallState(String sessionId) async {
if (Platform.isAndroid || Platform.isIOS) {
var callState =
await ConnectycubeFlutterCallKit.getCallState(sessionId: sessionId);
log("CONECTICUBE CALL STATE: $callState");
return callState;
} else {
return Future.value(CallState.UNKNOWN);
}
}
void muteCall(String sessionId, bool mute) {
CallKitManager.instance.muteCall(sessionId, mute);
}
Future _onBackPressed(BuildContext context) {
return Future.value(false);
}
void broadcastSystemMessage(action) {
systemMessage.recipientId = int.tryParse(selfCubeId!);
systemMessage.properties["resourceId"] = resourceId;
systemMessage.properties["action"] = action;
print("BROADCASTING: $action EVENT");
systemMessagesManager?.sendSystemMessage(systemMessage);
}
}
Code: Select all
import 'package:connectycube_sdk/connectycube_sdk.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:universal_io/io.dart';
import 'package:connectycube_flutter_call_kit/connectycube_flutter_call_kit.dart';
class FcmSetup {
static FcmSetup? _instance;
FcmSetup._internal();
factory FcmSetup() {
return _instance ??= FcmSetup._internal();
}
FirebaseMessaging? firebaseMessaging;
Future init({
required Function(RemoteMessage remoteMessage) onMessage,
}) async {
firebaseMessaging = FirebaseMessaging.instance;
log("INT STARTED");
await firebaseMessaging!.requestPermission(
alert: false,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
String? token;
if (Platform.isAndroid || kIsWeb) {
token = await firebaseMessaging!.getToken();
} else if (Platform.isIOS || Platform.isMacOS) {
token = await firebaseMessaging!.getAPNSToken();
log("APNS TOKEN $token");
}
if (token != null) {
subscribe(token);
}
if (Platform.isIOS || Platform.isMacOS) {
String? voipToken = await ConnectycubeFlutterCallKit.getToken();
log("VOIP TOKEN $voipToken");
if (voipToken != null) {
subscribeVoIP(voipToken);
}
}
firebaseMessaging!.onTokenRefresh.listen((newToken) async {
subscribe(newToken);
});
// FirebaseMessaging.onMessage.listen(onMessage);
// FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
}
subscribe(String token) async {
log('[subscribe] token: $token');
bool isProduction = bool.fromEnvironment('dart.vm.product');
CreateSubscriptionParameters parameters = CreateSubscriptionParameters();
parameters.environment =
isProduction ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;
if (Platform.isAndroid) {
parameters.channel = NotificationsChannels.GCM;
parameters.platform = CubePlatform.ANDROID;
parameters.bundleIdentifier = "com.360carefirst.app";
} else if (Platform.isIOS) {
parameters.channel = NotificationsChannels.APNS;
parameters.platform = CubePlatform.IOS;
parameters.bundleIdentifier = Platform.isIOS
? "com.360carefirst.app"
: "com.connectycube.flutter.chatSample.macOS";
}
String deviceId = await getDeviceId();
parameters.udid = deviceId;
parameters.pushToken = token;
createSubscription(parameters.getRequestParameters())
.then((cubeSubscription) {
getSubscriptions().then((subscriptions) {
log("Subscriptions: ${subscriptions.toString()}");
});
log("SUBSCRIPTION CREATED");
}).catchError((error) {
log("SUBSCRIPTION ERROR ${error}");
});
}
Future getDeviceId() async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
return androidInfo.id; // Unique ID for Android
} else if (Platform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
return iosInfo.identifierForVendor!;
}
return '';
}
void sendPushNotification(List ids, String message, String title) {
bool isProduction = bool.fromEnvironment('dart.vm.product');
CreateEventParams params = CreateEventParams();
params.parameters = {
'message': message, // Required
'title': title, // Required
'ios_voip': 1, // Required for iOS VoIP push
'push_badge': 1, // Updates app badge count
'push_sound': 'default', // Plays default notification sound
'custom_data': {
'param1': 'value1', // Custom parameters (optional)
'param2': 'value2',
},
'aps': {
'alert': {'title': title, 'body': message},
'sound': 'default',
'content-available': 1 // Required for silent VoIP pushes
}
};
params.notificationType = NotificationType.PUSH;
params.environment =
isProduction ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;
params.usersIds = ids;
createEvent(params.getEventForRequest()).then((cubeEvent) {
log("SENT TO IDS ${ids.toString()}");
}).catchError((error) {
log("ERROR WHILE SEDING TO IDS");
});
}
Future unsubscribe() async {
try {
List subscriptionsList = await getSubscriptions();
log("SUBSCRIBED USER LIST ${subscriptionsList.length}");
for (CubeSubscription subscription in subscriptionsList) {
log("SUBSCRIPTION ID ${subscription.id}");
await deleteSubscription(subscription.id!);
}
log("UNSUBSCRIBED SUC");
} on Exception catch (e) {
log("UNSUBSCRIBED ERROR ${e}");
}
}
subscribeVoIP(String token) async {
log('[subscribeVoIP] token: $token');
CreateSubscriptionParameters parameters = CreateSubscriptionParameters();
parameters.pushToken = token;
if (Platform.isIOS) {
parameters.channel = NotificationsChannels.APNS_VOIP;
parameters.platform = CubePlatform.IOS;
}
String deviceId = await getDeviceId();
parameters.udid = deviceId;
parameters.environment =
kReleaseMode ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;
var packageInfo = await PackageInfo.fromPlatform();
parameters.bundleIdentifier = packageInfo.packageName;
createSubscription(parameters.getRequestParameters())
.then((cubeSubscriptions) {
log('[subscribeVoIP] subscription SUCCESS');
}).catchError((error) {
log('[subscribeVoIP] subscription ERROR: $error');
});
}
}