quickblox-ios-sdk
quickblox-ios-sdk copied to clipboard
VoIP Push notification not work in background and terminate state.
Hello,
We have performed chatting, audio, video call functionality in our project. we got text message related notification, but we haven't got VoIP notification for audio/video call once the app goes in background and terminate the state. we have used the latest framework for audio/video calls. and also sometimes not subscription not work. So can you guide us to complete this functionality?
Thanks.
need help with same issue
Hello @Navya-ios ,
I have found some way to solve this issue. You can try as below,
-> Have you added PKPushRegistryDelegate method in appdelegate file? and PKPushRegistryDelegate is only in appdelegate file. otherwise you added more than 1 PKPushRegistryDelegate, it will not work.
-> If you will fail to report 2-3 notification, then Apple will block your notification. so you have to first delete your app then reinstall app.
-> If you have added “answerTimeInterval” in didReceiveIncomingPushWith method. then comment it. you must have to incoming call whenever receive VoIP notification.
Hello navya,
I have found some way to solve this issue. You can try as below,
-> Have you added PKPushRegistryDelegate method in appdelegate file? and PKPushRegistryDelegate is only in appdelegate file. otherwise you added more than 1 PKPushRegistryDelegate, it will not work.
-> If you will fail to report 2-3 notification, then Apple will block your notification. so you have to first delete your app then reinstall app.
-> If you have added “answerTimeInterval” in didReceiveIncomingPushWith method. then comment it. you must have to incoming call whenever receive VoIP notification.
Yes PKPushRegistryDelegate methods are in App delegate only, subscription is getting success but incoming call was coming.
Hello @Navya-ios ,
I have found some way to solve this issue. You can try as below,
-> Have you added PKPushRegistryDelegate method in appdelegate file? and PKPushRegistryDelegate is only in appdelegate file. otherwise you added more than 1 PKPushRegistryDelegate, it will not work.
-> If you will fail to report 2-3 notification, then Apple will block your notification. so you have to first delete your app then reinstall app.
-> If you have added “answerTimeInterval” in didReceiveIncomingPushWith method. then comment it. you must have to incoming call whenever receive VoIP notification.
Yes PKPushRegistryDelegate methods are in App delegate only, subscription is getting success but incoming call was coming.
What you are writing in didReceiveIncomingPushWith methods, Can you share here.
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { print("didReceiveIncomingPushwith payload") let application = UIApplication.shared
//in case of bad internet we check how long the VOIP Push was delivered for call(1-1)
//if time delivery is more than “answerTimeInterval” - return
if type == .voIP,
payload.dictionaryPayload[UsersConstant.voipEvent] != nil {
if let timeStampString = payload.dictionaryPayload["timestamp"] as? String,
let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String {
let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",")
if opponentsIDsArray.count == 2 {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
if let startCallDate = formatter.date(from: timeStampString) {
if Date().timeIntervalSince(startCallDate) > QBRTCConfig.answerTimeInterval() {
print("[WaitingRoomVC] timeIntervalSinceStartCall > QBRTCConfig.answerTimeInterval")
return
}
}
}
}
}
if type == .voIP,
payload.dictionaryPayload[UsersConstant.voipEvent] != nil,
application.applicationState == .background {
var opponentsIDs: [String]? = nil
var opponentsNumberIDs: [NSNumber] = []
var opponentsNamesString = "incoming call. Connecting..."
var sessionID: String? = nil
var callUUID = UUID()
var sessionConferenceType = QBRTCConferenceType.audio
self.isUpdatedPayload = false
if let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String,
let allOpponentsNamesString = payload.dictionaryPayload["contactIdentifier"] as? String,
let sessionIDString = payload.dictionaryPayload["sessionID"] as? String,
let callUUIDPayload = UUID(uuidString: sessionIDString) {
self.isUpdatedPayload = true
self.sessionID = sessionIDString
sessionID = sessionIDString
callUUID = callUUIDPayload
if let conferenceTypeString = payload.dictionaryPayload["conferenceType"] as? String {
sessionConferenceType = conferenceTypeString == "1" ? QBRTCConferenceType.video : QBRTCConferenceType.audio
}
let profile = Profile()
guard profile.isFull == true else {
return
}
let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",")
var opponentsNumberIDsArray = opponentsIDsArray.compactMap({NSNumber(value: Int($0)!)})
var allOpponentsNamesArray = allOpponentsNamesString.components(separatedBy: ",")
for i in 0...opponentsNumberIDsArray.count - 1 {
if opponentsNumberIDsArray[i].uintValue == profile.ID {
opponentsNumberIDsArray.remove(at: i)
allOpponentsNamesArray.remove(at: i)
break
}
}
opponentsNumberIDs = opponentsNumberIDsArray
opponentsIDs = opponentsNumberIDs.compactMap({ $0.stringValue })
opponentsNamesString = allOpponentsNamesArray.joined(separator: ", ")
}
let fetchUsersCompletion = { [weak self] (usersIDs: [String]?) -> Void in
if let opponentsIDs = usersIDs {
QBRequest.users(withIDs: opponentsIDs, page: nil, successBlock: { [weak self] (respose, page, users) in
if users.isEmpty == false {
self?.dataSource.update(users: users)
}
}) { (response) in
print("[WaitingRoomVC] error fetch usersWithIDs")
}
}
}
CallKitManager.instance.reportIncomingCall(withUserIDs: opponentsNumberIDs,
outCallerName: opponentsNamesString,
session: nil,
sessionID: sessionID,
sessionConferenceType: sessionConferenceType,
uuid: callUUID,
onAcceptAction: { [weak self] (isAccept) in
guard let self = self else {
return
}
if let session = self.session {
if isAccept == true {
self.openCall(withSession: session,
uuid: callUUID,
sessionConferenceType: sessionConferenceType)
print("[WaitingRoomVC] onAcceptAction")
} else {
session.rejectCall(["reject": "busy"])
print("[WaitingRoomVC] endCallAction")
}
} else {
if isAccept == true {
self.openCall(withSession: nil,
uuid: callUUID,
sessionConferenceType: sessionConferenceType)
print("[WaitingRoomVC] onAcceptAction")
} else {
print("[WaitingRoomVC] endCallAction")
}
self.prepareBackgroundTask()
}
completion()
}, completion: { (isOpen) in
if QBChat.instance.isConnected == false {
self.connectToChat { (error) in
if error == nil {
print("mo error in didreceiveIncoming withpush")
fetchUsersCompletion(opponentsIDs)
}
}
} else {
print("ABChat not connect in didreceiveIncoming withpush")
fetchUsersCompletion(opponentsIDs)
}
self.prepareBackgroundTask()
print("[WaitingRoomVC] callKit did presented")
})
}
}
What you are writing in didReceiveIncomingPushWith methods, Can you share here.
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { print("didReceiveIncomingPushwith payload") let application = UIApplication.shared
//in case of bad internet we check how long the VOIP Push was delivered for call(1-1)
//if time delivery is more than “answerTimeInterval” - return
if type == .voIP,
payload.dictionaryPayload[UsersConstant.voipEvent] != nil {
if let timeStampString = payload.dictionaryPayload["timestamp"] as? String,
let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String {
let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",")
if opponentsIDsArray.count == 2 {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
if let startCallDate = formatter.date(from: timeStampString) {
if Date().timeIntervalSince(startCallDate) > QBRTCConfig.answerTimeInterval() {
print("[WaitingRoomVC] timeIntervalSinceStartCall > QBRTCConfig.answerTimeInterval")
return
}
}
}
}
}
if type == .voIP,
payload.dictionaryPayload[UsersConstant.voipEvent] != nil,
application.applicationState == .background {
var opponentsIDs: [String]? = nil
var opponentsNumberIDs: [NSNumber] = []
var opponentsNamesString = "incoming call. Connecting..."
var sessionID: String? = nil
var callUUID = UUID()
var sessionConferenceType = QBRTCConferenceType.audio
self.isUpdatedPayload = false
if let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String,
let allOpponentsNamesString = payload.dictionaryPayload["contactIdentifier"] as? String,
let sessionIDString = payload.dictionaryPayload["sessionID"] as? String,
let callUUIDPayload = UUID(uuidString: sessionIDString) {
self.isUpdatedPayload = true
self.sessionID = sessionIDString
sessionID = sessionIDString
callUUID = callUUIDPayload
if let conferenceTypeString = payload.dictionaryPayload["conferenceType"] as? String {
sessionConferenceType = conferenceTypeString == "1" ? QBRTCConferenceType.video : QBRTCConferenceType.audio
}
let profile = Profile()
guard profile.isFull == true else {
return
}
let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",")
var opponentsNumberIDsArray = opponentsIDsArray.compactMap({NSNumber(value: Int($0)!)})
var allOpponentsNamesArray = allOpponentsNamesString.components(separatedBy: ",")
for i in 0...opponentsNumberIDsArray.count - 1 {
if opponentsNumberIDsArray[i].uintValue == profile.ID {
opponentsNumberIDsArray.remove(at: i)
allOpponentsNamesArray.remove(at: i)
break
}
}
opponentsNumberIDs = opponentsNumberIDsArray
opponentsIDs = opponentsNumberIDs.compactMap({ $0.stringValue })
opponentsNamesString = allOpponentsNamesArray.joined(separator: ", ")
}
let fetchUsersCompletion = { [weak self] (usersIDs: [String]?) -> Void in
if let opponentsIDs = usersIDs {
QBRequest.users(withIDs: opponentsIDs, page: nil, successBlock: { [weak self] (respose, page, users) in
if users.isEmpty == false {
self?.dataSource.update(users: users)
}
}) { (response) in
print("[WaitingRoomVC] error fetch usersWithIDs")
}
}
}
CallKitManager.instance.reportIncomingCall(withUserIDs: opponentsNumberIDs,
outCallerName: opponentsNamesString,
session: nil,
sessionID: sessionID,
sessionConferenceType: sessionConferenceType,
uuid: callUUID,
onAcceptAction: { [weak self] (isAccept) in
guard let self = self else {
return
}
if let session = self.session {
if isAccept == true {
self.openCall(withSession: session,
uuid: callUUID,
sessionConferenceType: sessionConferenceType)
print("[WaitingRoomVC] onAcceptAction")
} else {
session.rejectCall(["reject": "busy"])
print("[WaitingRoomVC] endCallAction")
}
} else {
if isAccept == true {
self.openCall(withSession: nil,
uuid: callUUID,
sessionConferenceType: sessionConferenceType)
print("[WaitingRoomVC] onAcceptAction")
} else {
print("[WaitingRoomVC] endCallAction")
}
self.prepareBackgroundTask()
}
completion()
}, completion: { (isOpen) in
if QBChat.instance.isConnected == false {
self.connectToChat { (error) in
if error == nil {
print("mo error in didreceiveIncoming withpush")
fetchUsersCompletion(opponentsIDs)
}
}
} else {
print("ABChat not connect in didreceiveIncoming withpush")
fetchUsersCompletion(opponentsIDs)
}
self.prepareBackgroundTask()
print("[WaitingRoomVC] callKit did presented")
})
}
}
@Navya-ios
Comment below section,
if type == .voIP, payload.dictionaryPayload[UsersConstant.voipEvent] != nil { if let timeStampString = payload.dictionaryPayload["timestamp"] as? String, let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String { let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",") if opponentsIDsArray.count == 2 { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" if let startCallDate = formatter.date(from: timeStampString) { if Date().timeIntervalSince(startCallDate) > QBRTCConfig.answerTimeInterval() { print("[WaitingRoomVC] timeIntervalSinceStartCall > QBRTCConfig.answerTimeInterval") return } } } } }
and Are you getting notification?
@Navya-ios
Comment below section,
if type == .voIP, payload.dictionaryPayload[UsersConstant.voipEvent] != nil { if let timeStampString = payload.dictionaryPayload["timestamp"] as? String, let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String { let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",") if opponentsIDsArray.count == 2 { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" if let startCallDate = formatter.date(from: timeStampString) { if Date().timeIntervalSince(startCallDate) > QBRTCConfig.answerTimeInterval() { print("[WaitingRoomVC] timeIntervalSinceStartCall > QBRTCConfig.answerTimeInterval") return } } } } }
and Are you getting notification?
no, im not getting any notification app was in background only
@Navya-ios
Comment below section,
if type == .voIP, payload.dictionaryPayload[UsersConstant.voipEvent] != nil { if let timeStampString = payload.dictionaryPayload["timestamp"] as? String, let opponentsIDsString = payload.dictionaryPayload["opponentsIDs"] as? String { let opponentsIDsArray = opponentsIDsString.components(separatedBy: ",") if opponentsIDsArray.count == 2 { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" if let startCallDate = formatter.date(from: timeStampString) { if Date().timeIntervalSince(startCallDate) > QBRTCConfig.answerTimeInterval() { print("[WaitingRoomVC] timeIntervalSinceStartCall > QBRTCConfig.answerTimeInterval") return } } } } }
and Are you getting notification?
Can you please tell me the step by step procedure to work for background call?
@Navya-ios
How many places to call below method, func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType)
didReceiveIncomingPushWith method is call when your app is in foreground? if not, then first delete the app the reinstall the app.
@Navya-ios
How many places to call below method, func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType)
didReceiveIncomingPushWith method is call when your app is in foreground? if not, then first delete the app the reinstall the app. func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) this is only in one view controller
and didReceiveIncomingPushWith method is call when your app is in foreground? this method is not calling in foreground
Please try to delete the app and reinstall the app. then check it. if this method is not called then your notification is blocked by apple due to not reporting incoming call.
Please try to delete the app and reinstall the app. then check it. if this method is not called then your notification is blocked by apple due to not reporting incoming call.
Yes tried but no progress
Can you share your chat related files?
Can you share your chat related files?
its for video calling
Yes
Yes
I am getting this crash log if i call in foreground. Any idea or suggestion?
2020-09-25 15:53:49.679 rtc::[Signaling Processor] - Did receive signal: call from: 25150912 2020-09-25 15:53:49.700 rtc::[RTCClient] Initializing SSL... 2020-09-25 15:53:49.702 rtc::Create audio track: RTCMediaStreamTrack: audio audioTrack enabled Live 2020-09-25 15:53:49.702 rtc::[CAPT] Init. 2020-09-25 15:53:49.702 rtc::Create video track: RTCMediaStreamTrack: video videoTrack enabled Live 2020-09-25 15:53:49.703 rtc::initialize - QBRTCRecorder 2020-09-25 15:53:49.704 rtc::[SESS]<d44a536b-21bb-419e-84e1-34e2c24272a3, I:25150912, O:[25157650], T:V> Init. 2020-09-25 15:53:49.705 rtc::[TASK]<ID:13, l:session answer time out> Start. 2020-09-25 15:53:49.705 rtc::[RTCClient] <QBRTCClient: 0x2824ac440> created new [SESS]<d44a536b-21bb-419e-84e1-34e2c24272a3, I:25150912, O:[25157650], T:V> didChange : QBRTCSessionState Could not cast value of type '__NSDictionaryM' (0x1ef977050) to 'NSString' (0x1ef97ff18). 2020-09-25 15:53:52.306573+0530 Vivadox[30613:2395236] Could not cast value of type '__NSDictionaryM' (0x1ef977050) to 'NSString' (0x1ef97ff18).
@riteshpatel0 @ritesh5553 @soulfly @dgem
For voIP notification (for call) In admin panel, I am able to get success in subscriptions but not i am not able to get in queue and not receiving any incoming call when app is in background.
@Navya-ios
While you are going to subscribe, did you check QBChat service is connected or not?. If QBChat service is not connected then the subscription will not show in the admin panel. and where you are added PKPushRegistryDelegate. if you are not added in appdelegate then VoIP will not work in background and terminate.
@riteshpatel0
We are disconnecting chat service when app goes to background state so, in that case we are not getting video call in background And if we don't disconnect chat service in didEnterBackground we are not getting messages when app is in background
How to overcome this issue?
@Navya-ios
Can you share VoIP Call functionality related files?
Hello,
This is Nikolay from QuickBlox support.
Please let me know if the issue is still relevant.
Also, please update the SDK to the latest version: https://github.com/QuickBlox/quickblox-ios-sdk/releases/tag/2.17.10
Additionally, please check our new samples: https://docs.quickblox.com/docs/code-samples#video-calling-samples
@muteKey Could you please describe how offline call push notification should work? According to the docs it is not clear who should send this notification(voip)? Is this done on QB backend or each client implementation should send it?