PushKit notification arriving after call has ended - ios

I have an application that implements PushKit and CallKit. The scenario in which the problem occurs is as follow:
Device A initiates a call, sending a PushKit notification to Device B.
Device B has no internet connection, and therefore does not receive the call.
Device A ends the call.
Device B connects to the internet after some time.
Device B receives the PushKit notification that Device A sent earlier and displays CallKit Incoming Call UI.
As you can see, Device B will display CallKit Incoming Call UI even after Device A ended the call.
How to prevent Device B from receiving the incoming call?
Thanks

You should send the end-call signal through a PushKit notification so that, as soon as device B reconnects, it will receive both the start-call and end-call notifications.

In iOS 13 you must report an incoming call before you leave the PushKit completion handler, otherwise your app will be blocked from receiving further PushKit pushes. Obviously, this is a slight problem when you have a case such as you described where the call no longer exists.
This scenario, and others, were discussed in an Apple Developer Forums thread
The specific advice for your case is:
While you must report an incoming call immediately, you are still free to decide the call has failed and tell the system later, asynchronously. To do this, call reportCallWithUUID:endedAtDate:reason:. This will tear down the incoming call UI even if the user has not answered the call.
If the user is particularly fast at tapping the accept call button, or if the network conditions are poor or there is otherwise a lot of latency, then you should simply wait until the necessary handshakes are complete before calling fulfill on the CXAnswerCallAction. To the user, it simply appears that the call is taking some time to connect, which is a common experience even with standard phone calls.
Note that the system takes a few seconds for the incoming call UI to animate in, during which the app has the opportunity to complete this handshake, so this will only have a user-visible impact if it takes a significant time for the handshake to complete.
So, what you need to do is report the call, then when you determine that the call is no longer valid (which shouldn't take long at all), immediately end the call.

Related

How do I know that an audio interruption ended without receiving AVAudioSessionInterruptionTypeEnded?

I'm using AVAudioSession in my VOIP app (using also CallKit).
I understand that the session can get interrupted by a number of things, for example by a second incoming call.
Apple states towards the bottom of this page:
https://developer.apple.com/library/content/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/HandlingAudioInterruptions/HandlingAudioInterruptions.html#//apple_ref/doc/uid/TP40007875-CH4-SW5
"Note: There is no guarantee that a begin interruption will have a
corresponding end interruption. Your app needs to be aware of a switch
to a foreground running state or the user pressing a Play button. In
either case, determine whether your app should reactivate its audio
session."
On the mentioned page there is an example for a special case, when the user ignores the incoming call and in that case AVAudioSessionInterruptionTypeEnded is being sent.
But what should I do to know when the interruption has ended in every other case (in which cases I will never receive an AVAudioSessionInterruptionTypeEnded)? (E.g. When the user answers the 2nd call and puts me on hold and later he ends the 2nd call?)
Thanks!
I remember when you use CallKit, no app using audio like music will interrupt your app except for those other voip apps or native calls.
In that case, your call will be ended/held according to your response on the call kit ui (If your call do not support held, you will not be shown a thid button accept&hold)----Then, you can get your callback from CallKit delegate methods.
The Interruption api just works when CallKit is not used and CallKit app have a higher priority on audio session than those not using it.

Get caller number from app when it is in background or in open state in iOS 10 or below?

I am looking for some source code for iOS 10 and below by which I can get the caller number when some phone call arrived and that call can be rejected by the application, if call is some fraud call (checking the local database). 

I have followed following post but did not get any fruitful result.
Via call kit: how to get the incoming call number by using callkit

True caller app already added that feature:
https://blog.truecaller.com/2016/10/26/truecaller-now-available-on-ios-10/

I think it is possible, can anyone help me by giving some idea or source code by which that can be achieved?
It is not possible to get caller's number when user receives a call. Truecaller has a lot of conditions for it to be able to show caller's details. The truecaller app should be active. The caller should call using the truecaller app. Both the calling and call receiving devices should be connected to the internet.
So what it basically does is that when a user presses the call button on the app to call somebody, they simply send him a notification that this person is calling you. It has nothing to do with CallKit and the caller id is not displayed on the call receiving screen.

How to perform some action when device is connected to WiFi and app is terminated?

How should I communicate with server or do some action when my device is connected to the WiFi and my app is terminated (not runnning on background/foreground)?
According to the documentation for UIApplicationDelegate's applicationWillTerminate API (which has a companion UIApplicationWillTerminate notification you can observer), you have approximately five seconds to perform any tasks and return before the app dies.
If this were my problem, I'd be wondering if five seconds is that long enough to reliably talk to the server or do any useful action aside from cleanup.
If your app goes in Terminated state, you can't perform any operation. The thing you could've done is in the Background state. You should go through this Apple Documentation for better understanding on iOS App Lifecycle.

One-Way Speech Path After Hold/Resume VoIP Call Through CallKit

We've been able to establish a VoIP call using CallKit. However, Hold and Resume operation on this established VoIP call causes one-way speech path issue. I'm able to hear far-end after I hold and resume. Far-end is not able to hear me.
I've already taken Wireshark traces and confirmed that after the resume, there is only one-way audio. Audio is not sent from my device to far-end.
Since Wireshark already showed the problem, I checked WebRTC code for media session errors. I see no errors in startSend or startPlayout (audio unit processing for send and receive)
I re-checked by CallKit integration code to confirm correct sequences
HOLD OPERATION
Press HOLD button on App UI or long-press MUTE button on CallKit UI.
App requests CXSetHeldCallAction transaction to CallKit with onHold as YES.
App receives provider delegate call back performSetHeldCallAction.
App puts the call on hold and then fulfils performSetHeldCallAction.
App receives provider delegate call back didDeactivateAudioSession.
RESUME OPERATION
Press RESUME button on App UI or HELD button on CallKit UI.
App requests CXSetHeldCallAction transaction to CallKit with onHold as NO.
App receives provider delegate call back performSetHeldCallAction.
App configures audio session (AVAudioSessionCategoryPlayAndRecord, AVAudioSessionModeVoiceChat, preferredSampleRate:44100) and then fulfils performSetHeldCallAction but remembers the call to be taken off-hold.
App receives provider delegate call back didActivateAudioSession. Using this App takes the call off-hold (resumes the call). The call is the one that was stored in the above step.
We've already raised an Apple Ticket using bugreport (with no update) and are pursuing raising an Apple Technical Support Incident (Apple TSI).
Hoping for some valuable inputs.

Central is getting error reponse for write request if Peripheral respond back a little late

I have been using CoreBlueTooth framework to communicate between BTLE iOS devices and I see a strange behavior. Here is what I am doing:
iOS device 1 (Peripheral): Expose a writable characteristics.
iOS device 2 (Central): Scan for the writable characteristics and write data into it.
iOS device 1 (Peripheral): Receives write request. Wait for some time to acknowledge the receipt of data.
iOS device 2 (Central): Get a callback on the below delegate and received the mentioned error.
Issue: Here if I respond back to the write request in few seconds by calling the API [iPeripheral respondToRequest:iRequest withResult:iStatus] then it all works fine and I get a success on my Central. But if I take some time, even if my Peripheral has not responded to the write request, I get error response back.
Is this some kind of connection loss in few seconds or the known CB framework behavior, any idea?
- (void)peripheral:(CBPeripheral *)iPeripheral didWriteValueForCharacteristic:(CBCharacteristic *)iCharacteristic error:(NSError *)iError
Error Domain=CBErrorDomain Code=0 "Unknown error." UserInfo=0x183a6d70 {NSLocalizedDescription=Unknown error.}
Both my Central and Peripheral are running on iOS 7.0.
I also observed this problem when I had deadlocks in my code and couldn't respond in time ;-) The way I observed it, iOS responds with an automatic error request with an arbitrary error code if a request is not answered within 10 seconds. I have not found a way to change this, but it makes sense from a protocol perspective.
In Bluetooth Low Energy, a central can only send a single Characteristic Value Write Request at a time. After it has sent this request, it cannot send a different Write Request unless the first one is responded to. Therefore, it is crucial to always respond to requests as fast as possible.
In the comments, you mentioned that you are waiting for user input to affect the result code you want to send to the central. I guess "Success" if the user confirms in the UI that an operation should be started, and an error code if the user denies that. This is not the way an LE based protocol should be designed. It's like blocking the UI thread until an operation is finished, just from the other side. You are effectively blocking the BT communications until a blocking operation (waiting for user input) completes.
A different design would be to send a write request to the other phone, responding immediately with a "Success" error code to indicate that the request was received and the popup is displayed. Then, send a Characteristic Value Indication with the user's choice from the peripheral to the central.
There's one small caveat if you target iOS 6: indications don't work nicely in many cases (reentrancy bugs etc, best not touch them). There, you should send a Read Request from your central and return the user's choice in this read request if it's already available. Again, don't block while giving the answer, sending back a "user is still choosing" value back if the answer is not yet ready.
Single rule: Answer requests as fast as possible. It's the way, Bluetooth LE is designed to work.
You may be exceeding the maximum time allowed for a write to be acknowledged. Try testing several different ack times and see if it reliably fails beyond a certain threshold.
If you use iPhone 4 devices, this device no suports BLE. BLS are supported in iPhone 4 and later.

Resources