|
| 1 | +#import "VoipManager.h" |
| 2 | +#import <PushKit/PushKit.h> |
| 3 | +#import "CallKitManager.h" |
| 4 | + |
| 5 | +@interface VoipManager ()<PKPushRegistryDelegate> |
| 6 | +@property(nonatomic, strong) PKPushRegistry *registry; |
| 7 | +@property(nonatomic, strong) dispatch_queue_t registryQueue; |
| 8 | +@property(copy, readwrite, nullable) NSString *token; |
| 9 | +@property(copy, readwrite, nullable) NSDictionary *pendingIncomingCall; |
| 10 | +@end |
| 11 | + |
| 12 | +@implementation VoipManager |
| 13 | + |
| 14 | ++ (instancetype)shared { |
| 15 | + static VoipManager *sharedInstance = nil; |
| 16 | + static dispatch_once_t onceToken; |
| 17 | + dispatch_once(&onceToken, ^{ |
| 18 | + sharedInstance = [[VoipManager alloc] init]; |
| 19 | + }); |
| 20 | + |
| 21 | + return sharedInstance; |
| 22 | +} |
| 23 | + |
| 24 | ++ (void)registerForVoIPPushes { |
| 25 | + [[self shared] registerForVoIPPushes]; |
| 26 | +} |
| 27 | + |
| 28 | +- (void)registerForVoIPPushes { |
| 29 | + if (self.registry != nil) { |
| 30 | + return; |
| 31 | + } |
| 32 | + |
| 33 | + self.registryQueue = dispatch_queue_create("io.fishjam.voippush", DISPATCH_QUEUE_SERIAL); |
| 34 | + self.registry = [[PKPushRegistry alloc] initWithQueue:self.registryQueue]; |
| 35 | + self.registry.delegate = self; |
| 36 | + self.registry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; |
| 37 | +} |
| 38 | + |
| 39 | +#pragma mark - PKPushRegistryDelegate |
| 40 | + |
| 41 | +- (void)pushRegistry:(PKPushRegistry *)registry |
| 42 | + didUpdatePushCredentials:(PKPushCredentials *)pushCredentials |
| 43 | + forType:(PKPushType)type { |
| 44 | + const unsigned char *bytes = pushCredentials.token.bytes; |
| 45 | + NSMutableString *hex = [NSMutableString stringWithCapacity:pushCredentials.token.length * 2]; |
| 46 | + for (NSUInteger i = 0; i < pushCredentials.token.length; i++) { |
| 47 | + [hex appendFormat:@"%02x", bytes[i]]; |
| 48 | + } |
| 49 | + NSString *tokenString = [hex copy]; |
| 50 | + |
| 51 | + if ([tokenString isEqualToString:self.token]) { |
| 52 | + return; |
| 53 | + } |
| 54 | + self.token = tokenString; |
| 55 | + |
| 56 | + if (self.onTokenUpdated) { |
| 57 | + self.onTokenUpdated(tokenString); |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type { |
| 62 | + self.token = nil; |
| 63 | +} |
| 64 | + |
| 65 | +- (void)pushRegistry:(PKPushRegistry *)registry |
| 66 | + didReceiveIncomingPushWithPayload:(PKPushPayload *)payload |
| 67 | + forType:(PKPushType)type |
| 68 | + withCompletionHandler:(void (^)(void))completion { |
| 69 | + NSMutableDictionary *dict = [payload.dictionaryPayload mutableCopy]; |
| 70 | + NSString *displayName = dict[@"displayName"]; |
| 71 | + BOOL isVideo = [dict[@"isVideo"] boolValue]; |
| 72 | + dict[@"isVideo"] = @(isVideo); |
| 73 | + |
| 74 | + if (displayName == nil || displayName.length == 0) { |
| 75 | + displayName = @"Incoming call"; |
| 76 | + dict[@"displayName"] = displayName; |
| 77 | + } |
| 78 | + |
| 79 | + [[CallKitManager shared] reportIncomingCallWithDisplayName:displayName isVideo:isVideo]; |
| 80 | + |
| 81 | + // Buffer the payload if the app was cold-launched and JS side hasn't yet loaded |
| 82 | + self.pendingIncomingCall = dict; |
| 83 | + |
| 84 | + if (self.onIncomingPush) { |
| 85 | + self.onIncomingPush(dict ?: @{}); |
| 86 | + } |
| 87 | + |
| 88 | + completion(); |
| 89 | +} |
| 90 | + |
| 91 | +- (void)clearPendingIncomingCall { |
| 92 | + self.pendingIncomingCall = nil; |
| 93 | +} |
| 94 | + |
| 95 | +@end |
0 commit comments