-
Notifications
You must be signed in to change notification settings - Fork 0
Manage push notification
First let's activate Push Notification capability of your Xcode project:
Go on https://developer.apple.com/account/ios/certificate/create to generate the VoIP certificate by clicking on the plus button:
Then select VoIP Services Certificate inside Production section (this certificate works on both sandbox and production environments).
Pick your bundle ID associated to your VoIP certificate.
Follow Apple's instructions to generate a .certSigningRequest file: Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority...
...enter your user email address, common name and save to disk.
Upload your CSR file and finally download the .cer file. Double click on it, your certificate now appears inside Keychain Access.
Let's now generate a .p12 file that will be uploaded to the Voxeet developer portal.
Go back to Keychain Access, select your certificate: VoIP Services: YOUR_BUNDLE_ID. Right click on it, export and pick a password.
Go to https://developer.voxeet.com/dashboard > YOUR_APP_NAME and upload your generate .p12 file inside iOS: VoIP APNs P12 from Third party section (don't forget to enter the .p12 file's password).
The Apple VoIP certificate is now generated and uploaded to Voxeet.
Display the system-calling UI for your app's VoIP services.
CallKit is disabled by default. 'Push Notifications' capability needs to be enabled.
Some events can be used along with callKit
to update the UI, such as VTCallKitStarted
, VTCallKitSwapped
, VTCallKitEnded
, VTCallKitMuteToggled
.
If CallKitSound.mp3
is overridden, the ringing sound will be replaced by your mp3. Same as IconMask.png
if overridden, it will replace the CallKit default image by yours (40x40px).
import VoxeetSDK
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Voxeet SDK initialization.
VoxeetSDK.shared.initialize(consumerKey: "YOUR_CONSUMER_KEY", consumerSecret: "YOUR_CONSUMER_SECRET")
VoxeetSDK.shared.notification.push.type = .callKit
return true
}
}
/*
* MARK: - Voxeet VoIP push notifications
* To handle VoIP push notifications before iOS 10, you must use this AppDelegate extension:
*/
extension AppDelegate {
/// Useful below iOS 10.
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
VoxeetSDK.shared.notification.push.application(application, didReceive: notification)
}
/// Useful below iOS 10.
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
VoxeetSDK.shared.notification.push.application(application, handleActionWithIdentifier: identifier, for: notification, completionHandler: completionHandler)
}
}
Warning: CallKit is banned in China (China mainland and Hong Kong) and validation of your application may be rejected from the Apple Store Connect. Fortunately VoxeetSDK automatically switches from CallKit to standard notification if China is detected. But you still may have a rejection (Apple’s bot detects "import CallKit" in VoxeetSDK even if it isn't used and returns you a rejected message at the validation proccess...).
As an example of this post on Stack Overflow, you can try to warn Apple that the application embed CallKit but doesn't use it in China: "In this version and onwards, we do not use CallKit features for users in China. We detect the user’s region using NSLocale." from https://stackoverflow.com/questions/50460864/this-app-cannot-be-approved-with-callkit-functionality-active-in-china-please-m.
If it still doesn't work try to directly contact Apple to finally unlock your validation or remove China mainland and Hong Kong from AppStoreConnect > Pricing and Availability.
Standard push notifications can also be used to display an incoming call.
import VoxeetSDK
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Voxeet SDK initialization.
VoxeetSDK.shared.initialize(consumerKey: "YOUR_CONSUMER_KEY", consumerSecret: "YOUR_CONSUMER_SECRET")
VoxeetSDK.shared.notification.push.type = .standard
// Ask APNs permission.
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound], completionHandler: { (granted, error) in })
} else {
let settings = UIUserNotificationSettings(types: [.alert, .sound], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
}
return true
}
}
/*
* MARK: - Voxeet VoIP push notifications
* To handle VoIP push notifications before iOS 10, you must use this AppDelegate extension:
*/
extension AppDelegate {
/// Useful below iOS 10.
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
VoxeetSDK.shared.notification.push.application(application, didReceive: notification)
}
/// Useful below iOS 10.
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
VoxeetSDK.shared.notification.push.application(application, handleActionWithIdentifier: identifier, for: notification, completionHandler: completionHandler)
}
}
To replace localized strings, simply implement these keys / values inside your Localizable.strings files:
VT_NOTIFICATION_TITLE = "Incoming call from _HANDLE_";
VT_NOTIFICATION_BODY = "Conference: _CONFERENCE_ALIAS_";
VT_NOTIFICATION_ANSWER = "Answer";
VT_NOTIFICATION_DECLINE = "Decline";
VoxeetSDK allows to fully manage your own push notification management.
import VoxeetSDK
import PushKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Voxeet SDK initialization.
VoxeetSDK.shared.initialize(consumerKey: "YOUR_CONSUMER_KEY", consumerSecret: "YOUR_CONSUMER_SECRET", connectSession: false)
VoxeetSDK.shared.notification.push.type = .none
// Push notification initialization.
initPushNotification()
return true
}
func initPushNotification() {
// Init PushKit, register to VoIP notification.
let pushRegistry = PKPushRegistry(queue: DispatchQueue.main)
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = [.voIP]
// Init Voxeet observers.
// Register to VTInvitationReceivedEvent to start a new CallKit incoming call.
NotificationCenter.default.addObserver(self, selector: #selector(incomingCallEvent), name: .VTInvitationReceivedEvent, object: nil)
// Register to VTConferenceDestroyedPush to end a call handled by CallKit.
NotificationCenter.default.addObserver(self, selector: #selector(conferenceDestroyedPush), name: .VTConferenceDestroyedPush, object: nil)
// Set up CallKit / standard notification.
}
}
/*
* MARK: - PKPushRegistryDelegate
*/
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
// Important: pass your push token to Voxeet in order to have custom push notifications.
let pushToken = pushCredentials.token.map{ String(format: "%02x", $0) }.joined()
VoxeetSDK.shared.session.pushToken = pushToken
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type, completion: {})
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
guard type == .voIP else { return }
// Get conference information.
guard let confID = payload.dictionaryPayload["ConfId"] as? String,
let confAlias = payload.dictionaryPayload["ConfAlias"] as? String else {
return
}
let notifType = payload.dictionaryPayload["NotifType"] as? String
if notifType == "1" { /* Check if notification type is an incoming call */
// Show CallKit or standard notification.
completion()
} else if notifType == "5" { /* Check if notification type is a destroy conference */
// Hide CallKit or standard notification.
completion()
}
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {}
}
/*
* MARK: - Voxeet push ups (NotificationCenter)
*/
extension AppDelegate {
@objc func incomingCallEvent(notification: Notification) {
// Show CallKit or standard notification.
}
@objc func conferenceDestroyedPush(notification: Notification) {
// Hide CallKit or standard notification.
}
}
copyright Voxeet 2019
-
Initialization
-
Managing Conference
-
Sharing
-
Advanced