Merge pull request #4424 from vector-im/element_4269_additions

VoIP: Fixes for PushKit Crashes
This commit is contained in:
ismailgulek 2021-06-11 17:09:56 +03:00 committed by GitHub
commit 47355c0aa8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 65 deletions

View file

@ -16,6 +16,8 @@ Changes to be released in next version
* RoomDirectCallStatusBubbleCell: Fix crash when entering a DM after a call is hung-up/rejected while being answered (#4403).
* ContactsDataSource: iPad Crashes when you select a contact in search and then collapse a section or clear the query text (#4414).
* SettingsViewController: Fix "auto" theme message to clarify that it matches the system theme on iOS 13+ (#2860).
* VoIP: Handle application inactive state too for VoIP pushes (#4269).
* VoIP: Do not terminate the app if protected data not available (#4419).
⚠️ API Changes
*

View file

@ -178,16 +178,17 @@ Matrix session observer used to detect new opened sessions.
{
[[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications];
[[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:nil];
}
- (void)applicationDidEnterBackground
{
if (_pushNotificationStore.pushKitToken)
{
self.shouldReceiveVoIPPushes = YES;
}
}
- (void)applicationDidEnterBackground
{
}
- (void)applicationDidBecomeActive
{
[[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications];
@ -227,6 +228,8 @@ Matrix session observer used to detect new opened sessions.
{
_shouldReceiveVoIPPushes = shouldReceiveVoIPPushes;
MXLogDebug(@"[PushNotificationService] setShouldReceiveVoIPPushes: %u", _shouldReceiveVoIPPushes)
if (_shouldReceiveVoIPPushes && _pushNotificationStore.pushKitToken)
{
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
@ -256,16 +259,25 @@ Matrix session observer used to detect new opened sessions.
}
else
{
_pushRegistry.delegate = nil;
[self deconfigurePushKit];
}
}
- (void)configurePushKit
{
MXLogDebug(@"[PushNotificationService] configurePushKit")
_pushRegistry.delegate = self;
_pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
- (void)deconfigurePushKit
{
MXLogDebug(@"[PushNotificationService] deconfigurePushKit")
_pushRegistry.delegate = nil;
}
- (void)removePusher:(MXPusher*)pusher inSession:(MXSession*)session
{
MXLogDebug(@"[PushNotificationService][Push] removePusher: %@", pusher.appId);
@ -547,83 +559,83 @@ Matrix session observer used to detect new opened sessions.
[[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications];
[[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:roomId];
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
if (@available(iOS 13.0, *))
{
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is in bg");
// for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here.
MXEvent *callInvite = [_pushNotificationStore callInviteForEventId:eventId];
// remove event
[_pushNotificationStore removeCallInviteWithEventId:eventId];
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
// when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it.
[[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session];
if (@available(iOS 13.0, *))
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13+, callInvite: %@", callInvite);
if (callInvite)
{
// for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here.
MXEvent *callInvite = [_pushNotificationStore callInviteForEventId:eventId];
// remove event
[_pushNotificationStore removeCallInviteWithEventId:eventId];
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
// when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it.
[[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session];
// We're using this dispatch_group to continue event stream after cache fully processed.
dispatch_group_t dispatchGroup = dispatch_group_create();
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: callInvite: %@", callInvite);
dispatch_group_enter(dispatchGroup);
// Not continuing in completion block here, because PushKit mandates reporting a new call in the same run loop.
// 'handleBackgroundSyncCacheIfRequiredWithCompletion' is processing to-device events synchronously.
[session handleBackgroundSyncCacheIfRequiredWithCompletion:^{
dispatch_group_leave(dispatchGroup);
}];
if (callInvite)
if (callInvite.eventType == MXEventTypeCallInvite)
{
// We're using this dispatch_group to continue event stream after cache fully processed.
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_enter(dispatchGroup);
// Not continuing in completion block here, because PushKit mandates reporting a new call in the same run loop.
// 'handleBackgroundSyncCacheIfRequiredWithCompletion' is processing to-device events synchronously.
[session handleBackgroundSyncCacheIfRequiredWithCompletion:^{
dispatch_group_leave(dispatchGroup);
}];
if (callInvite.eventType == MXEventTypeCallInvite)
// process the call invite synchronously
[session.callManager handleCallEvent:callInvite];
MXCallInviteEventContent *content = [MXCallInviteEventContent modelFromJSON:callInvite.content];
MXCall *call = [session.callManager callWithCallId:content.callId];
if (call)
{
// process the call invite synchronously
[session.callManager handleCallEvent:callInvite];
MXCallInviteEventContent *content = [MXCallInviteEventContent modelFromJSON:callInvite.content];
MXCall *call = [session.callManager callWithCallId:content.callId];
if (call)
{
[session.callManager.callKitAdapter reportIncomingCall:call];
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId);
// Wait for the sync response in cache to be processed for data integrity.
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
// After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user.
[self launchBackgroundSync];
});
}
else
{
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId);
}
}
else if ([callInvite.type isEqualToString:kWidgetMatrixEventTypeString] ||
[callInvite.type isEqualToString:kWidgetModularEventTypeString])
{
[[AppDelegate theDelegate].callPresenter processWidgetEvent:callInvite
inSession:session];
[session.callManager.callKitAdapter reportIncomingCall:call];
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId);
// Wait for the sync response in cache to be processed for data integrity.
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
// After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user.
[self launchBackgroundSync];
});
}
else
{
// It's a serious error. There is nothing to avoid iOS to kill us here.
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId);
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId);
}
}
else if ([callInvite.type isEqualToString:kWidgetMatrixEventTypeString] ||
[callInvite.type isEqualToString:kWidgetModularEventTypeString])
{
[[AppDelegate theDelegate].callPresenter processWidgetEvent:callInvite
inSession:session];
}
else
{
// It's a serious error. There is nothing to avoid iOS to kill us here.
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13 and in bg, but we don't have the callInvite event for the eventId: %@. There is something wrong.", eventId);
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId);
}
}
else
{
// below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit.
[self launchBackgroundSync];
// It's a serious error. There is nothing to avoid iOS to kill us here.
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13+, but we don't have the callInvite event for the eventId: %@.", eventId);
}
}
else
{
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is not in bg. There is something wrong.");
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
{
// below iOS 13, we don't have to report a call immediately.
// We can wait for a call invite from event stream and process.
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Below iOS 13 and active app. Do nothing.");
completion();
return;
}
// below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit.
[self launchBackgroundSync];
}
completion();

View file

@ -369,12 +369,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: isProtectedDataAvailable: %@", @([application isProtectedDataAvailable]));
if (![application isProtectedDataAvailable])
{
MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: Terminating the app because protected data not available");
exit(0);
}
_configuration = [AppConfiguration new];
self.appInfo = AppInfo.current;