Cómo obtener un evento de llamada usando CTCallCenter: setCallEventHandler: ¿Qué ocurrió mientras se suspendía la aplicación?

La documentación para CTCallCenter: setCallEventHandler: establece que:

Sin embargo, los eventos de llamada también pueden tener lugar mientras se suspende su aplicación. Mientras está suspendido, su aplicación no recibe eventos de llamadas. Cuando su aplicación reanuda el estado activo, recibe un único evento de llamada para cada llamada que cambió de estado

La parte relevante para esta pregunta es

Cuando su aplicación reanuda el estado activo, recibe un único evento de llamada para cada llamada que cambió de estado

Implicar la aplicación recibirá un evento de llamada para una llamada que tuvo lugar en el pasado mientras se suspendió la aplicación. Y esto es posible según la respuesta a esta pregunta: ¿cómo obtiene la aplicación Navita TEM la información del registro de llamadas?

Mi pregunta es: si mi aplicación se suspende y se realiza una llamada, cuando mi aplicación reanude el estado activo, ¿cómo puede recuperar el evento de llamada para la llamada que tuvo lugar?

He intentado muchos, muchos experimentos de código pero no he podido recuperar ninguna información de llamada cuando mi aplicación reanuda el estado activo.

Esto es lo más simple que he intentado: 1) Crear un nuevo proyecto usando la plantilla de aplicación de vista única de Xcode. 2) Agregue el código que se muestra a continuación a didFinishLaunchingWithOptions 3) Inicie la aplicación 4) Tarea fuera de la aplicación 5) Realice una llamada desde otro dispositivo, conteste la llamada, cuelgue la llamada desde cualquier dispositivo 6) Devuelva la aplicación al primer plano reanudando así el estado activo.

El código para registrarse para eventos de llamadas es:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.callCenter = [[CTCallCenter alloc] init]; [self.callCenter setCallEventHandler:^(CTCall *call) { NSLog(@"Event handler called"); if ([call.callState isEqualToString: CTCallStateConnected]) { NSLog(@"Connected"); } else if ([call.callState isEqualToString: CTCallStateDialing]) { NSLog(@"Dialing"); } else if ([call.callState isEqualToString: CTCallStateDisconnected]) { NSLog(@"Disconnected"); } else if ([call.callState isEqualToString: CTCallStateIncoming]) { NSLog(@"Incomming"); } }]; return YES; } 

Con este código puedo obtener eventos de llamadas si la aplicación está en primer plano cuando ocurre la llamada. Pero si realizo tareas lejos de la aplicación antes de realizar la llamada, no puedo recibir un evento de llamada cuando mi aplicación vuelva a activar el estado activo, como lo indica en la documentación de Apple.

Otras cosas que he intentado:

1) La documentación indica que el objeto de bloque se distribuye en la cola de despacho global de prioridad predeterminada, por lo que he intentado colocar el registro de setCallEventHandler en dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{})

2) Llamar a setCallEventHandler: en appBecameActive en lugar de hacerlo en finFinishLaunchingWithOptions

3) Agregar habilidades de fondo a la aplicación – a través de beginBackgroundTaskWithExpirationHandler y / o actualizaciones de ubicación usando startUpdatingLocation o startMonitoringForSignificantLocationChanges.

4) Varias combinaciones de lo anterior.

La recompensa se otorgará una vez que obtenga el código que se ejecuta en mi dispositivo, que es capaz de recibir eventos de llamadas que tuvieron lugar mientras se suspendía la aplicación.

Esto está en iOS 7.

Encontré una solución, pero no tengo idea de por qué está funcionando. Lo único que se me ocurre es un error en GCD y / o CoreTelephony.

Básicamente, CTCallCenter dos instancias de CTCallCenter como esta

 void (^block)(CTCall*) = ^(CTCall* call) { NSLog(@"%@", call.callState); }; -(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { callCenter1 = [[CTCallCenter alloc] init]; callCenter1.callEventHandler = block; callCenter2 = [[CTCallCenter alloc] init]; callCenter2.callEventHandler = block; return YES; } 

Código similar en Swift:

 func block (call:CTCall!) { println(call.callState) } func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { //Declare callcenter in the class like 'var callcenter = CTCallCenter()' callcenter.callEventHandler = block return true } 

Para probar esto hice una llamada, la contesté y luego la colgué mientras la aplicación estaba en segundo plano. Cuando lo lancé, recibí 3 eventos de llamadas: entrantes, conectados, desconectados.

En mi caso, estaba trabajando en una aplicación empresarial que no necesita ser aprobada por el mercado de aplicaciones de Apple, por lo que si desarrolla una aplicación empresarial, esta solución es para usted.

Además, la respuesta elegida no funcionó mientras la aplicación era el fondo.

La solución es simple, básicamente solo necesitas agregar 2 capacidades (VOIP y búsqueda de fondo) en la pestaña Capacidades:

  • Su objective de proyecto -> Capacidades -> Modos de fondo -> marcar Voz sobre IP y búsqueda de fondo

enter image description here

Ahora, su aplicación está registrada en el marco de iOS llamadas “delegar” para que la solución de recorte de código OP:

 [self.callCenter setCallEventHandler:^(CTCall *call) { NSLog(@"Event handler called"); if ([call.callState isEqualToString: CTCallStateConnected]) { NSLog(@"Connected"); } else if ([call.callState isEqualToString: CTCallStateDialing]) { NSLog(@"Dialing"); } else if ([call.callState isEqualToString: CTCallStateDisconnected]) { NSLog(@"Disconnected"); } else if ([call.callState isEqualToString: CTCallStateIncoming]) { NSLog(@"Incomming"); } }]; 

Definitivamente funcionaría y recibirás notificaciones incluso si tu aplicación está en segundo plano.