From 895443e747e070363fb043bea538ec77f43c8e24 Mon Sep 17 00:00:00 2001 From: misha Date: Tue, 16 Jun 2026 21:11:45 +0300 Subject: [PATCH] feat(video_calls): added more logs for sentry --- ios/Runner/AppDelegate.swift | 53 +++++++++++++++---- .../video_call_callkit_coordinator.dart | 37 +++++++++++++ pubspec.yaml | 2 +- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 4fa2445b..e2f16042 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -221,15 +221,19 @@ import flutter_foreground_task ?? conversationUuid(fromActionUrl: dict["action_url"] as? String) ?? (dict["handle"] as? String) ?? "" - let id = [ - dict["call_id"] as? String, - dict["id"] as? String, - dict["message_id"] as? String, - conversationUuid, + let callKitIdSource = [ + (key: "call_id", value: dict["call_id"] as? String), + (key: "id", value: dict["id"] as? String), + (key: "message_id", value: dict["message_id"] as? String), ] - .compactMap { $0?.trimmingCharacters(in: .whitespacesAndNewlines) } - .first { !$0.isEmpty && UUID(uuidString: $0) != nil } - ?? UUID().uuidString + .first { item in + guard let trimmed = item.value?.trimmingCharacters(in: .whitespacesAndNewlines) else { + return false + } + return !trimmed.isEmpty && UUID(uuidString: trimmed) != nil + } + let id = callKitIdSource?.value?.trimmingCharacters(in: .whitespacesAndNewlines) ?? UUID().uuidString + let callKitIdSourceName = callKitIdSource?.key ?? "generated" let isVideo = (dict["isVideo"] as? Bool) ?? (dict["is_video"] as? Bool) ?? true @@ -280,6 +284,7 @@ import flutter_foreground_task "voip_incoming_received", data: [ "callKitId": id, + "callKitIdSource": callKitIdSourceName, "conversationUuid": conversationUuid, "nameCaller": nameCaller, "isVideo": isVideo, @@ -288,11 +293,24 @@ import flutter_foreground_task ] ) - SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming( + guard let callkitPlugin = SwiftFlutterCallkitIncomingPlugin.sharedInstance else { + NSLog("[EatvioVoIP] CallKit plugin missing id=\(id)") + recordVoipDiagnostic( + "callkit_plugin_missing", + data: [ + "callKitId": id, + "conversationUuid": conversationUuid, + ] + ) + completion() + return + } + + callkitPlugin.showCallkitIncoming( data, fromPushKit: true ) { - let activeCalls = SwiftFlutterCallkitIncomingPlugin.sharedInstance?.activeCalls() ?? [] + let activeCalls = callkitPlugin.activeCalls() let activeIds = activeCalls.compactMap { $0["id"] as? String }.joined(separator: ",") NSLog( "[EatvioVoIP] report incoming completed id=\(id) activeCallIds=\(activeIds)" @@ -301,11 +319,26 @@ import flutter_foreground_task "callkit_report_completed", data: [ "callKitId": id, + "callKitIdSource": callKitIdSourceName, "conversationUuid": conversationUuid, "activeCallIds": activeIds, "activeCallsCount": activeCalls.count, ] ) + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + let delayedActiveCalls = callkitPlugin.activeCalls() + let delayedActiveIds = delayedActiveCalls.compactMap { $0["id"] as? String }.joined(separator: ",") + self.recordVoipDiagnostic( + "callkit_active_calls_delayed", + data: [ + "callKitId": id, + "callKitIdSource": callKitIdSourceName, + "conversationUuid": conversationUuid, + "activeCallIds": delayedActiveIds, + "activeCallsCount": delayedActiveCalls.count, + ] + ) + } completion() } } diff --git a/lib/features/video_calls/services/video_call_callkit_coordinator.dart b/lib/features/video_calls/services/video_call_callkit_coordinator.dart index a6006f7d..02c7c3fd 100644 --- a/lib/features/video_calls/services/video_call_callkit_coordinator.dart +++ b/lib/features/video_calls/services/video_call_callkit_coordinator.dart @@ -136,6 +136,7 @@ class VideoCallCallKitCoordinator { Future _onCallKitEvent(CallEvent? event) async { if (event == null) return; + unawaited(_captureCallKitEventToSentry(event)); switch (event) { case CallEventActionDidUpdateDevicePushTokenVoip(): @@ -157,6 +158,42 @@ class VideoCallCallKitCoordinator { } } + Future _captureCallKitEventToSentry(CallEvent event) async { + if (!Platform.isIOS) return; + final context = { + 'eventName': event.eventName, + 'eventType': event.runtimeType.toString(), + }; + switch (event) { + case CallEventActionCallIncoming(:final callKitParams): + context.addAll({ + 'id': callKitParams.id, + 'handle': callKitParams.handle, + 'nameCaller': callKitParams.nameCaller, + 'isAccepted': callKitParams.isAccepted, + 'extra': callKitParams.extra?.toString(), + }); + case CallEventActionCallAccept(:final id): + case CallEventActionCallCallback(:final id): + case CallEventActionCallDecline(:final id): + case CallEventActionCallEnded(:final id): + case CallEventActionCallTimeout(:final id): + context['id'] = id; + default: + break; + } + + await Sentry.captureMessage( + 'iOS CallKit event: ${event.runtimeType}', + level: SentryLevel.info, + withScope: (scope) { + scope.setTag('origin', 'iOS CallKit'); + scope.setTag('callkit_event', event.runtimeType.toString()); + scope.setContexts('callkit_event', context); + }, + ); + } + void _cacheCallKitParams(CallKitParams params) { _callKitParamsById[params.id] = params; _activeCallKitId = params.id; diff --git a/pubspec.yaml b/pubspec.yaml index c6783736..209f5b05 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: eatvio_app description: A new Flutter project. -version: 1.3.27+111 +version: 1.3.27+112 publish_to: 'none' environment: