WFCCallKitManager.m 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. //
  2. // WFCCallKitManager.m
  3. // WildFireChat
  4. //
  5. // Created by Rain on 2022/4/25.
  6. // Copyright © 2022 WildFireChat. All rights reserved.
  7. //
  8. #import "WFCCallKitManager.h"
  9. #import <CallKit/CallKit.h>
  10. #import <UIKit/UIKit.h>
  11. #import <WFAVEngineKit/WFAVEngineKit.h>
  12. #import "RtckitPlugin.h"
  13. @interface WFCCallKitManager ()
  14. @property(nonatomic, strong) CXProvider *provider;
  15. @property(nonatomic, strong) CXCallController *callController;
  16. @property(nonatomic, strong) NSMutableDictionary<NSString *, NSUUID *> *callUUIDDict;
  17. @property(nonatomic, strong)FlutterMethodChannel* channel;
  18. @end
  19. @implementation WFCCallKitManager
  20. - (instancetype)initWithChannel:(FlutterMethodChannel *)channel {
  21. self = [super init];
  22. if(self) {
  23. self.callUUIDDict = [[NSMutableDictionary alloc] init];
  24. static CXProviderConfiguration* configInternal = nil;
  25. configInternal = [[CXProviderConfiguration alloc] initWithLocalizedName:@"野火"];
  26. configInternal.supportsVideo = true;
  27. configInternal.maximumCallsPerCallGroup = 1;
  28. configInternal.maximumCallGroups = 1;
  29. configInternal.supportedHandleTypes = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:CXHandleTypeGeneric],[NSNumber numberWithInt:CXHandleTypePhoneNumber], nil];
  30. UIImage* iconMaskImage = [UIImage imageNamed:@"callkit_app_icon"];
  31. configInternal.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage);
  32. self.provider = [[CXProvider alloc] initWithConfiguration: configInternal];
  33. [self.provider setDelegate:self queue:dispatch_get_main_queue()];
  34. self.callController = [[CXCallController alloc] initWithQueue:dispatch_get_main_queue()];
  35. self.channel = channel;
  36. }
  37. return self;
  38. }
  39. - (void)didReceiveCall:(WFAVCallSession *)session {
  40. if(self.callUUIDDict[session.callId]) {
  41. session.callUUID = self.callUUIDDict[session.callId];
  42. } else {
  43. if(session.state == kWFAVEngineStateIdle) {
  44. return;
  45. }
  46. NSUUID *currentCall = [NSUUID UUID];
  47. session.callUUID = currentCall;
  48. [self reportIncomingCallWithTitle:[[WFAVEngineKit sharedEngineKit] getUserDisplayName:session.initiator] Sid:session.initiator audioOnly:session.audioOnly callId:session.callId uuid:currentCall];
  49. }
  50. }
  51. - (void)didCallEnded:(WFAVCallEndReason)reason duration:(int)callDuration {
  52. if([WFAVEngineKit sharedEngineKit].currentSession.callUUID) {
  53. CXEndCallAction *endAction = [[CXEndCallAction alloc] initWithCallUUID:[WFAVEngineKit sharedEngineKit].currentSession.callUUID];
  54. CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endAction];
  55. [self.callController requestTransaction:transaction completion:^(NSError * _Nullable error) {
  56. NSLog(@"end call");
  57. }];
  58. }
  59. }
  60. - (void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload
  61. forType:(NSString *)type {
  62. NSLog(@"didReceiveIncomingPushWithPayload");
  63. NSDictionary *wfc = payload.dictionaryPayload[@"wfc"];
  64. if(wfc) {
  65. NSString *sender = wfc[@"sender"];
  66. NSString *senderName = wfc[@"senderName"];
  67. if(!senderName.length) {
  68. senderName = sender;
  69. }
  70. NSString *pushData = wfc[@"pushData"];
  71. NSDictionary *pd = [NSJSONSerialization JSONObjectWithData:[pushData dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
  72. BOOL audioOnly = [pd[@"audioOnly"] boolValue];
  73. NSString *callId = pd[@"callId"];
  74. NSString *name = [[WFAVEngineKit sharedEngineKit] getUserDisplayName:sender];
  75. if(!name.length || [name rangeOfString:@"<"].location == 0) {
  76. name = senderName;
  77. }
  78. [self reportIncomingCallWithTitle:name Sid:sender audioOnly:audioOnly callId:callId];
  79. }
  80. }
  81. - (void)reportIncomingCallWithTitle:(NSString *)title Sid:(NSString *)sid audioOnly:(BOOL)audioOnly callId:(NSString *)callId {
  82. NSUUID *currentCall = [NSUUID UUID];
  83. [self reportIncomingCallWithTitle:title Sid:sid audioOnly:audioOnly callId:callId uuid:currentCall];
  84. }
  85. - (void)reportIncomingCallWithTitle:(NSString *)title Sid:(NSString *)sid audioOnly:(BOOL)audioOnly callId:(NSString *)callId uuid:(NSUUID *)uuid {
  86. CXCallUpdate* update = [[CXCallUpdate alloc] init];
  87. update.supportsDTMF = false;
  88. update.supportsHolding = false;
  89. update.supportsGrouping = false;
  90. update.supportsUngrouping = false;
  91. update.hasVideo = !audioOnly;
  92. update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:sid];
  93. update.localizedCallerName = title;
  94. self.callUUIDDict[callId] = uuid;
  95. [[WFAVEngineKit sharedEngineKit] registerCall:callId uuid:uuid];
  96. NSUUID *uu = [WFAVEngineKit sharedEngineKit].currentSession.callUUID;
  97. NSLog(@"the uuid is %@", uu.UUIDString);
  98. [self.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError * _Nullable error) {
  99. if(error) {
  100. NSLog(@"error:%@", error);
  101. }
  102. }];
  103. }
  104. #pragma - mark CXProviderDelegate
  105. - (void)providerDidReset:(CXProvider *)provider {
  106. NSLog(@"providerDidReset");
  107. }
  108. - (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
  109. NSLog(@"performStartCallAction");
  110. }
  111. - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
  112. NSLog(@"performAnswerCallAction");
  113. [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeVoiceChat options:AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP | AVAudioSessionCategoryOptionMixWithOthers error:nil];
  114. [action fulfill];
  115. }
  116. - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
  117. NSLog(@"performEndCallAction");
  118. NSUUID *uuid = [WFAVEngineKit sharedEngineKit].currentSession.callUUID;
  119. if([action.callUUID isEqual:uuid] || !uuid) {
  120. if ([WFAVEngineKit sharedEngineKit].currentSession.state != kWFAVEngineStateIdle) {
  121. [[WFAVEngineKit sharedEngineKit].currentSession endCall];
  122. }
  123. }
  124. [action fulfill];
  125. }
  126. - (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action {
  127. if([action.callUUID isEqual:[WFAVEngineKit sharedEngineKit].currentSession.callUUID]) {
  128. if ([WFAVEngineKit sharedEngineKit].currentSession.state != kWFAVEngineStateIdle) {
  129. if (action.isMuted) {
  130. [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:YES];
  131. } else {
  132. [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:NO];
  133. }
  134. }
  135. }
  136. [action fulfill];
  137. }
  138. - (void)answerCall {
  139. [[WFAVEngineKit sharedEngineKit].currentSession answerCall:false callExtra:nil];
  140. [self.channel invokeMethod:@"showCallView" arguments:@{@"callSession":[RtckitPlugin callSession2Dict:[WFAVEngineKit sharedEngineKit].currentSession]}];
  141. }
  142. -(void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession {
  143. if ([WFAVEngineKit sharedEngineKit].currentSession.state == kWFAVEngineStateIncomming) {
  144. [self answerCall];
  145. } else {
  146. //有可能用户点击接听以后,IM服务消息还没有同步完成,来电消息还没有被处理,需要等待有来电session再接听.
  147. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  148. int count = 60;
  149. while (count--) {
  150. [NSThread sleepForTimeInterval:0.05];
  151. if ([WFAVEngineKit sharedEngineKit].currentSession.state == kWFAVEngineStateIncomming) {
  152. dispatch_async(dispatch_get_main_queue(), ^{
  153. [self answerCall];
  154. });
  155. break;
  156. }
  157. }
  158. //3秒内没有接听成功,这里设置为失败
  159. [self.provider invalidate];
  160. });
  161. }
  162. }
  163. @end