forked from eatvio/eatvio_app
feat(video_calls): removed system ui, fixed wrong app initializing
This commit is contained in:
@@ -13,6 +13,7 @@ import flutter_foreground_task
|
||||
private var voipRegistry: PKPushRegistry?
|
||||
private var voipDiagnosticsChannel: FlutterMethodChannel?
|
||||
private let voipDiagnosticsStorageKey = "EatvioVoipDiagnostics"
|
||||
private let pendingAcceptedVoipCallKey = "EatvioPendingAcceptedVoipCall"
|
||||
private let voipDiagnosticsChannelName = "com.eatvioapp/voip_diagnostics"
|
||||
private let appUrlScheme = "eatvio"
|
||||
|
||||
@@ -43,11 +44,18 @@ import flutter_foreground_task
|
||||
)
|
||||
voipDiagnosticsChannel = channel
|
||||
channel.setMethodCallHandler { [weak self] call, result in
|
||||
guard call.method == "drainVoipDiagnostics" else {
|
||||
result(FlutterMethodNotImplemented)
|
||||
guard let self else {
|
||||
result(nil)
|
||||
return
|
||||
}
|
||||
result(self?.drainVoipDiagnostics() ?? [])
|
||||
switch call.method {
|
||||
case "drainVoipDiagnostics":
|
||||
result(self.drainVoipDiagnostics())
|
||||
case "drainPendingAcceptedVoipCall":
|
||||
result(self.drainPendingAcceptedVoipCall())
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +167,32 @@ import flutter_foreground_task
|
||||
return nil
|
||||
}
|
||||
|
||||
private func storePendingAcceptedCall(_ call: Call) {
|
||||
let payload = sanitizedDiagnosticValue(call.data.toJSON()) as? [String: Any] ?? [:]
|
||||
UserDefaults.standard.set(payload, forKey: pendingAcceptedVoipCallKey)
|
||||
}
|
||||
|
||||
private func drainPendingAcceptedVoipCall() -> [String: Any]? {
|
||||
let defaults = UserDefaults.standard
|
||||
guard let payload = defaults.dictionary(forKey: pendingAcceptedVoipCallKey) else {
|
||||
return nil
|
||||
}
|
||||
defaults.removeObject(forKey: pendingAcceptedVoipCallKey)
|
||||
return payload
|
||||
}
|
||||
|
||||
private func bringAppToForeground() {
|
||||
DispatchQueue.main.async {
|
||||
for scene in UIApplication.shared.connectedScenes {
|
||||
guard let windowScene = scene as? UIWindowScene else { continue }
|
||||
for window in windowScene.windows {
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
self.window?.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
|
||||
private func openAppForAcceptedCall(_ call: Call) {
|
||||
guard let conversationUuid = conversationUuid(fromCall: call), !conversationUuid.isEmpty else {
|
||||
recordVoipDiagnostic(
|
||||
@@ -197,6 +231,8 @@ import flutter_foreground_task
|
||||
]
|
||||
)
|
||||
|
||||
bringAppToForeground()
|
||||
|
||||
UIApplication.shared.open(url, options: [:]) { [weak self] success in
|
||||
self?.recordVoipDiagnostic(
|
||||
success ? "accepted_call_open_app_succeeded" : "accepted_call_open_app_failed",
|
||||
@@ -446,6 +482,7 @@ import flutter_foreground_task
|
||||
|
||||
|
||||
func onAccept(_ call: Call, _ action: CXAnswerCallAction) {
|
||||
storePendingAcceptedCall(call)
|
||||
recordVoipDiagnostic(
|
||||
"callkit_accept_native",
|
||||
data: [
|
||||
@@ -456,6 +493,7 @@ import flutter_foreground_task
|
||||
)
|
||||
voipDiagnosticsChannel?.invokeMethod("acceptedVoipCall", arguments: call.data.toJSON())
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.bringAppToForeground()
|
||||
self?.openAppForAcceptedCall(call)
|
||||
}
|
||||
action.fulfill()
|
||||
|
||||
@@ -14,6 +14,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_callkit_incoming/entities/call_event.dart';
|
||||
import 'package:flutter_callkit_incoming/entities/call_kit_params.dart';
|
||||
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
|
||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
class VideoCallCallKitCoordinator {
|
||||
@@ -57,8 +58,10 @@ class VideoCallCallKitCoordinator {
|
||||
}
|
||||
});
|
||||
await _firebaseApi.registerPushToken();
|
||||
await _drainPendingNativeAcceptedVoipCall();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_scheduleNativeVoipDiagnosticsDrain();
|
||||
unawaited(_drainPendingNativeAcceptedVoipCall());
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -137,6 +140,29 @@ class VideoCallCallKitCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _drainPendingNativeAcceptedVoipCall() async {
|
||||
if (!Platform.isIOS) return;
|
||||
try {
|
||||
final pending = await _voipDiagnosticsChannel.invokeMethod(
|
||||
'drainPendingAcceptedVoipCall',
|
||||
);
|
||||
if (pending == null) return;
|
||||
await _handleNativeAcceptedVoipCall(pending);
|
||||
} on PlatformException catch (e, st) {
|
||||
log(
|
||||
'VideoCallCallKitCoordinator: failed to drain pending native accept: $e',
|
||||
name: 'VideoCallCallKit',
|
||||
stackTrace: st,
|
||||
);
|
||||
} catch (e, st) {
|
||||
log(
|
||||
'VideoCallCallKitCoordinator: failed to process pending native accept: $e',
|
||||
name: 'VideoCallCallKit',
|
||||
stackTrace: st,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onCallKitEvent(CallEvent? event) async {
|
||||
if (event == null) return;
|
||||
unawaited(_captureCallKitEventToSentry(event));
|
||||
@@ -424,7 +450,9 @@ class VideoCallCallKitCoordinator {
|
||||
_suppressedEndCallKitIds.add(callKitId);
|
||||
|
||||
try {
|
||||
await FlutterCallkitIncoming.endCall(callKitId);
|
||||
if (!Platform.isIOS) {
|
||||
await FlutterCallkitIncoming.endCall(callKitId);
|
||||
}
|
||||
|
||||
final binding = WidgetsBinding.instance;
|
||||
final completer = Completer<void>();
|
||||
@@ -439,6 +467,10 @@ class VideoCallCallKitCoordinator {
|
||||
);
|
||||
});
|
||||
await completer.future;
|
||||
|
||||
if (Platform.isIOS) {
|
||||
await FlutterCallkitIncoming.endCall(callKitId);
|
||||
}
|
||||
} finally {
|
||||
unawaited(
|
||||
Future<void>.delayed(const Duration(seconds: 2), () {
|
||||
@@ -454,8 +486,12 @@ class VideoCallCallKitCoordinator {
|
||||
String? counterpartName,
|
||||
String? counterpartAvatarUrl,
|
||||
String? localParticipantName,
|
||||
}) {
|
||||
return VideoCallNotificationNavigator.openIncomingCall(
|
||||
}) async {
|
||||
if (Platform.isIOS) {
|
||||
FlutterNativeSplash.remove();
|
||||
}
|
||||
|
||||
await VideoCallNotificationNavigator.openIncomingCall(
|
||||
conversationUuid: conversationUuid,
|
||||
counterpartName: counterpartName,
|
||||
counterpartAvatarUrl: counterpartAvatarUrl,
|
||||
|
||||
Reference in New Issue
Block a user