iOS Push Notifications in Swift (APNs, CallKit)
Swift, iOS 13+. Notifications via APNs, calls via PushKit + CallKit. No Firebase needed.
🍎 iOS
Swift, iOS 13+. Notifications via APNs, calls via PushKit + CallKit. No Firebase needed.
Download the SDK from the dashboard (Integration guide) after you create a free account.
Add the SDK to your project
Unzip the download into your project's root folder (this creates
PushConsoleSDK/), then pick one option:- Swift Package Manager: Xcode β File β Add Package Dependenciesβ¦ β Add Localβ¦ β choose the
PushConsoleSDK/iosfolder. - CocoaPods:
Podfile# Podfile pod 'PushConsole', :path => './PushConsoleSDK/ios'
Requires iOS 13+. The SDK doesn't need Firebase.
- Swift Package Manager: Xcode β File β Add Package Dependenciesβ¦ β Add Localβ¦ β choose the
Enable capabilities in Xcode
Target β Signing & Capabilities:
- Push Notifications
- Background Modes β tick Remote notifications and Voice over IP (for calls)
Info.plist<!-- Info.plist (Xcode adds this when you tick Background Modes) --> <key>UIBackgroundModes</key> <array> <string>remote-notification</string> <string>voip</string> </array> <key>NSMicrophoneUsageDescription</key> <string>Microphone is used for calls</string>
Initialize in AppDelegate
Call
initializeindidFinishLaunchingWithOptions: when a call arrives while the app is closed, iOS launches it in the background and the SDK must be ready immediately. SwiftUI apps: use@UIApplicationDelegateAdaptor(AppDelegate.self).AppDelegate.swiftimport UIKit import PushConsole @main class AppDelegate: UIResponder, UIApplicationDelegate, PushConsoleDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { PushConsole.shared.delegate = self PushConsole.shared.initialize( appId: "YOUR_APP_ID", serverURL: URL(string: "https://tingpush.com")!, callConfiguration: PushConsoleCallConfiguration(localizedName: "MyApp") // omit if you don't use calls ) return true } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { PushConsole.shared.didRegisterForRemoteNotifications(deviceToken: deviceToken) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { PushConsole.shared.didFailToRegisterForRemoteNotifications(error: error) } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { PushConsole.shared.handleRemoteNotification(userInfo) completionHandler(.newData) } }The APNs environment is detected automatically: Xcode debug builds = sandbox, TestFlight/App Store = production.
Assign the user at login
Swift// After login — your backend targets this External ID PushConsole.shared.login(externalUserId: "user-123") // On logout PushConsole.shared.logout() // Tag the user for targeted sends PushConsole.shared.setTags(["plan": "vip"])
Handle notification & call events
Swiftextension AppDelegate { // User tapped a notification func pushConsole(didOpenNotification userInfo: [AnyHashable: Any]) { // navigate using userInfo["screen"]... } // User tapped Answer → connect the real call (WebRTC/SIP/Agora…) func pushConsole(didAcceptCall call: PushConsoleCall) { // call.id, call.callerName, call.data["room"] } // CallKit activated audio: start playing/recording func pushConsoleDidActivateAudioSession() { } func pushConsole(didDeclineCall call: PushConsoleCall) { } // declined func pushConsole(didEndCall call: PushConsoleCall) { } // hung up func pushConsole(didMissCall call: PushConsoleCall) { } // missed } // The other side hung up → dismiss the call screen PushConsole.shared.endCall(callId: call.id)
β After integrating, check
- Run the app on a real device with logging on: you should see
[PushConsole] Device registered β¦. - The project's Devices tab: the device appears; iOS devices show the VoIP badge if you use calls.
- The Send tab: send a test to that device.
- Choose π Call and test with the app open, closed and with the screen locked.