6.8 C
Canberra
Thursday, May 1, 2025

Flutter Conecticube: unable to get name notification on IOS


I am utilizing ConnectyCube Flutter to implement video name performance in my Flutter app.

The decision notifications work wonderful on Android, however on iOS, I do not obtain any notification when a name is initiated from one other gadget.

What I Have Completed So Far:

  • Configured Push Notifications:
  • Arrange Firebase Cloud Messaging (FCM) for push notifications.
  • Uploaded the APNs certificates to ConnectyCube.
  • Checked iOS Permissions: Enabled Push Notifications functionality in
    Xcode. Ensured NSUserNotificationAlert is added within the Data.plist.

Examined with Background & Terminated State: On Android, the
notification is acquired correctly. On iOS, no notification seems in
each foreground and background states. Debugging Logs: No errors
associated to push notifications seem within the logs. Verified that FCM
token is appropriately generated on iOS.

under is my AndroidManifest file

    xmlns:instruments="http://schemas.android.com/instruments"

    bundle="com.sambuq.care_first">
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


    
    
    
    
    
    
        
        
    
    
    
        
        
    

    
        
        
        
    
    

   
        
            
        
        
        
        
        
        
            
        

        
        
        
            
         
        
            
            
            
                
                
            
            
                
                
            
        
        
        
        
    

**name supervisor class **

import 'bundle:care_first/bloc/auth_bloc/bloc/auth_bloc.dart';
import 'bundle:care_first/routing/route_names.dart';
import 'bundle:care_first/screens/settings/my_appointments/doctor_appointment/fashions/my_appointment.dart';
import 'bundle:care_first/shared/helper/helper_methods.dart';
import 'bundle:flutter/basis.dart';
import 'bundle:flutter/materials.dart';
import 'bundle:flutter_bloc/flutter_bloc.dart';
import 'bundle:go_router/go_router.dart';
import 'bundle:universal_io/io.dart';
import 'bundle:connectycube_flutter_call_kit/connectycube_flutter_call_kit.dart';
import 'bundle:connectycube_sdk/connectycube_sdk.dart';

import 'call_kit_manager.dart';
import '../utils/consts.dart';

class CallManager {
  static String TAG = "CallManager";

  static CallManager get occasion => _getInstance();
  static CallManager? _instance;

  static CallManager _getInstance() {
    return _instance ??= CallManager._internal();
  }

  manufacturing unit CallManager() => _getInstance();

  CallManager._internal();

  P2PClient? _callClient;
  P2PSession? _currentCall;
  BuildContext? context;
  MediaStream? localMediaStream;
  Map remoteStreams = {};
  GlobalKey? navigatorKey;
  String? selfCubeId;
  late String resourceId;
  SystemMessagesManager? systemMessagesManager =
      CubeChatConnection.occasion.systemMessagesManager;
  CubeMessage systemMessage = CubeMessage();
  closing participant = AudioPlayer();

  Perform(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.occasion.isAuthenticated()) {
      _initCalls(context);
    } else {
      _initChatConnectionStateListener(context);
    }

    _initCallKit();
  }

  destroy() {
    _callClient?.destroy();
    _callClient = null;
  }

  void _initCustomMediaConfigs() {
    RTCMediaConfig mediaConfig = RTCMediaConfig.occasion;
    mediaConfig.minHeight = 340;
    mediaConfig.minWidth = 480;
    mediaConfig.minFrameRate = 25;

    RTCConfig.occasion.statsReportsInterval = 200;
  }

  void _initCalls(BuildContext context) {
    if (_callClient == null) {
      _callClient = P2PClient.occasion;

      _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!.learn().person.persona ==
          "affected person") {
        await participant
            .setReleaseMode(ReleaseMode.loop)
            .then(
                (worth) => participant.setSource(AssetSource('audio/ringtone.mp3')))
            .then((worth) => participant.resume());
      }

      _currentCall = callSession;

      var callState = await _getCallState(_currentCall!.sessionId);
      await Future.delayed(Length(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!.learn().p2pSession =
              callSession;
          // await Future.delayed(Length(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.take away(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 participant.launch();
        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((monitor) async {
          await monitor.cease();
        });
        await localMediaStream?.dispose();
        localMediaStream = null;

        remoteStreams.forEach((key, worth) async {
          await worth.dispose();
        });

        remoteStreams.clear();
        CallKitManager.occasion.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.learn().p2pSession = callSession;
    context.learn().resourceId = resourceId;
    context.learn().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(textual content: businessId ?? '', context: context),
    }, queryParameters: {
      'moduleId': moduleId,
    }, additional: {
      // 'callSession': callSession,
      'appointment': appointment,
    });
  }

  void _showIncomingCallScreen(P2PSession callSession, BuildContext context) {
    if (navigatorKey!.currentContext != null) {
      GoRouter.of(navigatorKey!.currentContext!).pushNamed(
          RoutesName.incomingVideoCall,
          additional: Map.from(
              {"resourceId": resourceId, "selfCubeId": selfCubeId}));
    }
  }

  void acceptCall(
    String sessionId,
    Map userInfo,
    bool fromCallkit,
  ) async {
    await participant.launch();
    log('acceptCall, from callKit: $fromCallkit', TAG);
    //ConnectycubeFlutterCallKit.setOnLockScreenVisibility(isVisible: true);
    if (_currentCall != null) {
      if (context != null) {
        // if (AppLifecycleState.resumed !=
        //     WidgetsBinding.occasion.lifecycleState) {
        await _currentCall?.acceptCall();
        // }
        MyAppointment appointment = MyAppointment(
            id: userInfo['appointment_id'], physician: userInfo['doctor_id']);
        log(userInfo.toString(), "Person Data from AcceptCall");
        if (!fromCallkit) {
          await ConnectycubeFlutterCallKit.reportCallAccepted(
              sessionId: sessionId);
        }
        broadcastSystemMessage("CALL_ACCEPTED");
        navigatorKey!.currentContext!.learn().p2pSession =
            _currentCall;
        GoRouter.of(navigatorKey!.currentContext!).pushReplacementNamed(
          RoutesName.videoCallPatientRoute,
          additional: 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) {
      participant.launch();
      broadcastSystemMessage("CALL_REJECTED");
      if (fromCallkit) {
        ConnectycubeFlutterCallKit.setOnLockScreenVisibility(isVisible: false);
      } else {
        CallKitManager.occasion.processCallFinished(_currentCall!.sessionId);
      }

      _currentCall!.reject();
      _sendEndCallSignalForOffliners(_currentCall, null);
    }
  }

  void hungUp() {
    if (_currentCall != null) {
      participant.launch();
      CallKitManager.occasion.processCallFinished(_currentCall!.sessionId);
      _currentCall!.hungUp();
      _sendEndCallSignalForOffliners(_currentCall, null);
    }
  }

  CreateEventParams _getCallEventParameters(
      P2PSession currentCall, String? callerName) {
    /* String? callerName = customers
        .the place((cubeUser) => cubeUser.id == currentCall.callerId)
        .first
        .fullName; */
    CreateEventParams params = CreateEventParams();
    params.parameters = {
      'message':
          "Incoming ${currentCall.callType == CallType.VIDEO_CALL ? "Video" : "Audio"} name",
      PARAM_CALL_TYPE: currentCall.callType,
      PARAM_SESSION_ID: currentCall.sessionId,
      PARAM_CALLER_ID: currentCall.callerId,
      PARAM_CALL_OPPONENTS: currentCall.opponentsIds.be part of(','),
      PARAM_CALLER_NAME: callerName ?? "Physician",
    };

    params.notificationType = NotificationType.PUSH;
    params.atmosphere = 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("Occasion for offliners created: $cubeEvent");
    }).catchError((error) {
      log("ERROR happens throughout create occasion");
    });
  }

  void _sendEndCallSignalForOffliners(
      P2PSession? currentCall, String? callerName) {
    if (currentCall == null) return;

    CubeUser? currentUser = CubeChatConnection.occasion.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("Occasion for offliners created");
    }).catchError((error) {
      log("ERROR happens throughout create occasion");
    });
  }

  void _initCallKit() {
    CallKitManager.occasion.init(
      onCallAccepted: (uuid) {
        acceptCall(uuid, _currentCall?.cubeSdp.userInfo ?? {}, true);
      },
      onCallEnded: (uuid) {
        reject(uuid, true);
      },
      onMuteCall: (mute, uuid) {
        onMicMuted?.name(mute, uuid);
      },
    );
  }

  void _initChatConnectionStateListener(BuildContext context) {
    CubeChatConnection.occasion.connectionStateStream.pay attention((state) {
      if (CubeChatConnectionState.Prepared == 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.worth(CallState.UNKNOWN);
    }
  }

  void muteCall(String sessionId, bool mute) {
    CallKitManager.occasion.muteCall(sessionId, mute);
  }

  Future _onBackPressed(BuildContext context) {
    return Future.worth(false);
  }

  void broadcastSystemMessage(motion) {
    systemMessage.recipientId = int.tryParse(selfCubeId!);
    systemMessage.properties["resourceId"] = resourceId;
    systemMessage.properties["action"] = motion;
    print("BROADCASTING: $motion EVENT");
    systemMessagesManager?.sendSystemMessage(systemMessage);
  }
}

FCM SETUP CLASS

import 'bundle:connectycube_sdk/connectycube_sdk.dart';
import 'bundle:device_info_plus/device_info_plus.dart';
import 'bundle:firebase_messaging/firebase_messaging.dart';
import 'bundle:flutter/basis.dart';
import 'bundle:package_info_plus/package_info_plus.dart';
import 'bundle:universal_io/io.dart';
import 'bundle:connectycube_flutter_call_kit/connectycube_flutter_call_kit.dart';

class FcmSetup {
  static FcmSetup? _instance;
  FcmSetup._internal();

  manufacturing unit FcmSetup() {
    return _instance ??= FcmSetup._internal();
  }
  FirebaseMessaging? firebaseMessaging;

  Future init({
    required Perform(RemoteMessage remoteMessage) onMessage,
  }) async {
    firebaseMessaging = FirebaseMessaging.occasion;
    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.pay attention((newToken) async {
      subscribe(newToken);
    });

    // FirebaseMessaging.onMessage.pay attention(onMessage);
    // FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
  }

  subscribe(String token) async {
    log('[subscribe] token: $token');

    bool isProduction = bool.fromEnvironment('dart.vm.product');

    CreateSubscriptionParameters parameters = CreateSubscriptionParameters();
    parameters.atmosphere =
        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; // Distinctive ID for Android
    } else if (Platform.isIOS) {
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
      return iosInfo.identifierForVendor!;
    }
    return '';
  }

  void sendPushNotification(Record 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 depend
      'push_sound': 'default', // Performs default notification sound
      'custom_data': {
        'param1': 'value1', // Customized parameters (elective)
        'param2': 'value2',
      },
      'aps': {
        'alert': {'title': title, 'physique': message},
        'sound': 'default',
        'content-available': 1 // Required for silent VoIP pushes
      }
    };

    params.notificationType = NotificationType.PUSH;
    params.atmosphere =
        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 {
    strive {
      Record subscriptionsList = await getSubscriptions();
      log("SUBSCRIBED USER LIST ${subscriptionsList.size}");
      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.atmosphere =
        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');
    });
  }
}

enter image description here

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles