I can make video calls by using AgoraRtcKit but i cannot send a notification when one device is calling the other.
I have done all the certificates and backgroundmodes things. Here is the viewcontroller's code.
And also i have tried this: Question
I can see the notification when i type the of didReceiveIncomingPushWith in viewDidLoad but cannot see when one device is calling the other. How to make them communicate with each other?
import UIKit
import AgoraRtcKit
import AVFoundation
import CallKit
import PushKit
class VideoCallViewController: UIViewController, CXProviderDelegate, PKPushRegistryDelegate
{
@IBOutlet weak var localView: RoundedCornerView!
@IBOutlet weak var remoteView: UIView!
var apiCaller = ApiCaller()
var videoCall = VideoCall(uId: String(Int.random(in: 1...100000)), channelName: "xxx")
var agoraKit: AgoraRtcEngineKit?
@IBAction func btnEndCall(_ sender: Any)
{
agoraKit?.leaveChannel(nil)
AgoraRtcEngineKit.destroy()
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad()
{
super.viewDidLoad()
initializeAndJoinChannel()
let registry = PKPushRegistry(queue: DispatchQueue.main)
registry.delegate = self
registry.desiredPushTypes = [PKPushType.voIP]
}
func providerDidReset(_ provider: CXProvider) {
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
action.fulfill()
}
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
print(pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined())
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
let config = CXProviderConfiguration()
config.iconTemplateImageData = UIImage(named: "xxx")!.pngData()
config.ringtoneSound = "ringtone.caf"
config.includesCallsInRecents = false;
config.supportsVideo = true;
let provider = CXProvider(configuration: config)
provider.setDelegate(self, queue: DispatchQueue.main)
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: "Person")
update.hasVideo = true
provider.reportNewIncomingCall(with: UUID(), update: update, completion: { error in })
}
override func viewDidDisappear(_ animated: Bool)
{
super.viewDidDisappear(animated)
agoraKit?.leaveChannel(nil)
AgoraRtcEngineKit.destroy()
}
@objc func onDidReceiveAlert(_ notification:Notification? = nil) {
print("Received Notification")
}
func initializeAndJoinChannel()
{
apiCaller.videoCallToken(videoCall: videoCall) { [self] rslt in
switch rslt {
case .success(let response):
if response.result.success {
agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: response.appId, delegate: self)
DispatchQueue.main.async { [self] in
agoraKit?.enableVideo()
}
let config = CXProviderConfiguration()
config.iconTemplateImageData = UIImage(named: "xxx")!.pngData()
config.supportsVideo = true;
let provider = CXProvider(configuration: config)
provider.setDelegate(self, queue: DispatchQueue.main)
let controller = CXCallController()
let transaction = CXTransaction(action: CXStartCallAction(call: UUID(), handle: CXHandle(type: .generic, value: "Person")))
controller.request(transaction, completion: { error in })
DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 5) {
provider.reportOutgoingCall(with: controller.callObserver.calls[0].uuid, connectedAt: nil)
}
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = UInt(videoCall.uId)!
videoCanvas.renderMode = .hidden
videoCanvas.view = localView
agoraKit?.setupLocalVideo(videoCanvas)
agoraKit?.startPreview()
let option = AgoraRtcChannelMediaOptions()
option.clientRoleType = .broadcaster
agoraKit?.joinChannel(
byToken: response.token, channelId: "xxx", uid: UInt(videoCall.uId)!, mediaOptions: option,
joinSuccess: { (channel, uid, elapsed) in
overlayChange = 1
}
)
}
if response.result.success == false {
self.makeAlert(title: "Hata", message: "Bağlanırken hata oluştu!")
}
case .failure(_):
self.makeAlert(title: "Hata", message: "Veriler alınamadı!")
}
}
}
}
extension VideoCallViewController: AgoraRtcEngineDelegate
{
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int)
{
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = uid
videoCanvas.renderMode = .hidden
videoCanvas.view = remoteView
agoraKit?.setupRemoteVideo(videoCanvas)
}
}
I pretty sure you found an answer to your question by now but still for others who still wonder:
CallKit is the tool from which we trigger native UI/UX call. by definition, it's not connected to anything whatsoever. It handles the current call state on your device.
Agora is a service through which, when two devices are connected to the same channel can share data (frame, audio, message etc...). It could be Twillo or Steam.io or any RTC service.
In order to fully communicate, a third piece is missing => ️
When the first device needs to reach a second one, the second one needs to be informed of it somehow...
How ?
PushKit!
Great but it doesn't solve the communication problem.
You can add PushKit delegate to you code, it still does not trigger any communication to anyone so how ?
Here you need a backend service. To which the first device will send a request to, in order to send a Push notification (a PushKit notification) to the second.
When the second receives the push, he can then:
It kinda of sad, this kind of information is missing in their documentations.
Hope I made it clearer !