Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
cometchat avatar

Cometchat Ios Push

  • 6 installs
  • 70 repo stars
  • Updated June 23, 2026
  • cometchat/cometchat-skills

Set up push notifications for a CometChat iOS app including APNs configuration, token registration, and notification handling.

About

Teaches how to configure push notifications for CometChat iOS apps via APNs. A developer uses it to register tokens and handle incoming chat notifications on iOS.

  • APNs .p8 key setup via the Apple Developer portal
  • Push requires a physical device (no simulator support)

Cometchat Ios Push by the numbers

  • 6 all-time installs (skills.sh)
  • Ranked #806 of 1,039 Mobile Development skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cometchat/cometchat-skills --skill cometchat-ios-push

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs6
repo stars70
Last updatedJune 23, 2026
Repositorycometchat/cometchat-skills

What it does

Set up push notifications for a CometChat iOS app including APNs configuration, token registration, and notification handling.

Files

SKILL.mdMarkdownGitHub ↗
Ground truth: CometChatUIKitSwift ~> 5 (+ CometChatCallsSDK ~> 5) — Pods/SPM .swiftinterface + ui-kit/ios. Official docs: https://www.cometchat.com/docs/notifications/overview · Docs MCP: claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp (or fetch the URL directly without MCP). Verify symbols against the installed package/source before relying on them.

Purpose

This skill teaches how to set up push notifications for CometChat iOS apps, including APNs configuration, token registration, and handling incoming notifications.

---

1. Prerequisites

Before setting up push notifications:

1. Apple Developer Account — Required for APNs certificates 2. CometChat Dashboard Access — To configure push notification settings 3. Physical iOS Device — Push notifications don't work on simulators

---

2. APNs Certificate Setup

Step 1: Create APNs Key (Recommended)

1. Go to Apple Developer Portal 2. Navigate to Certificates, Identifiers & ProfilesKeys 3. Click + to create a new key 4. Enter a name (e.g., "CometChat Push Key") 5. Enable Apple Push Notifications service (APNs) 6. Click ContinueRegister 7. Download the .p8 file (you can only download it once!) 8. Note the Key ID and your Team ID

Step 2: Configure CometChat Dashboard

1. Go to CometChat Dashboard 2. Select your app 3. Navigate to NotificationsPush Notifications 4. Select iOS tab 5. Upload your .p8 file 6. Enter your Key ID and Team ID 7. Select the environment (Development/Production) 8. Save the configuration

---

3. Xcode Project Configuration

Enable Push Notifications Capability

1. Open your project in Xcode 2. Select your target 3. Go to Signing & Capabilities 4. Click + Capability 5. Add Push Notifications 6. Add Background Modes and enable:

  • Remote notifications
  • Voice over IP (if using calls)

Update Info.plist

Add the following to your Info.plist:

<key>UIBackgroundModes</key>
<array>
    <string>remote-notification</string>
    <string>voip</string>
</array>

---

4. Code Implementation

AppDelegate Setup

import UIKit
import UserNotifications
import CometChatUIKitSwift
import CometChatSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        // Initialize CometChat
        initializeCometChat()
        
        // Request notification permissions
        requestNotificationPermission()
        
        // Register for remote notifications
        application.registerForRemoteNotifications()
        
        return true
    }
    
    private func initializeCometChat() {
        let uiKitSettings = UIKitSettings()
            .set(appID: "YOUR_APP_ID")
            .set(authKey: "YOUR_AUTH_KEY")
            .set(region: "us")
            .subscribePresenceForAllUsers()
            .build()
        
        CometChatUIKit(uiKitSettings: uiKitSettings) { result in
            switch result {
            case .success:
                print("CometChat initialized")
            case .failure(let error):
                print("CometChat init failed: \(error)")
            }
        }
    }
    
    private func requestNotificationPermission() {
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        
        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted {
                print("Notification permission granted")
            } else if let error = error {
                print("Notification permission error: \(error)")
            }
        }
    }
    
    // MARK: - Remote Notification Registration
    
    func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        print("APNs Device Token: \(token)")
        
        // Register token with CometChat
        registerPushToken(token)
    }
    
    func application(
        _ application: UIApplication,
        didFailToRegisterForRemoteNotificationsWithError error: Error
    ) {
        print("Failed to register for remote notifications: \(error)")
    }
    
    private func registerPushToken(_ token: String) {
        // CANONICAL v5 API: CometChatNotifications.registerPushToken takes a
        // PushPlatforms enum (NOT a settings dict). Use .APNS_IOS_DEVICE for a
        // standard APNs device token, .APNS_IOS_VOIP for a PushKit VoIP token,
        // or .FCM_IOS if you route iOS through FCM. providerId is your dashboard
        // push-provider id (pass nil to use the default).
        CometChatNotifications.registerPushToken(
            pushToken: token,
            platform: .APNS_IOS_DEVICE,
            providerId: nil
        ) { success in
            print("Push token registered: \(success)")
        } onError: { error in
            print("Push token registration failed: \(error.errorDescription)")
        }
        // NOTE: the legacy `CometChat.registerTokenForPushNotification(token:settings:)`
        // (v4-era) still compiles but is superseded — prefer the call above.
    }

    // MARK: - Token lifecycle (register AFTER login, unregister BEFORE logout)
    //
    // ⚠️ `didRegisterForRemoteNotifications` can fire before the user logs in.
    // Registering a token that isn't bound to a CometChat session is a no-op at
    // best. Stash the latest APNs token and register it only once login resolves:
    //
    //   var pendingPushToken: String?   // set in didRegisterForRemoteNotifications
    //   // after CometChatUIKit.login(...) onSuccess:
    //   if let t = pendingPushToken { registerPushToken(t) }
    //
    // And ALWAYS unregister before logout — otherwise the device keeps receiving
    // pushes for the previous user:

    func unregisterPushToken(_ completion: @escaping () -> Void) {
        CometChatNotifications.unregisterPushToken { _ in
            completion()
        } onError: { _ in
            completion()   // proceed with logout regardless
        }
    }

    // Usage at logout:
    //   unregisterPushToken {
    //       CometChatUIKit.logout(onSuccess: { _ in /* route to login */ }, onError: { _ in })
    //   }

    // MARK: - Handle Incoming Notifications
    
    func application(
        _ application: UIApplication,
        didReceiveRemoteNotification userInfo: [AnyHashable: Any],
        fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
    ) {
        print("Received remote notification: \(userInfo)")
        
        // Handle CometChat notification
        if let messageData = userInfo["message"] as? [String: Any] {
            handleCometChatNotification(messageData)
        }
        
        completionHandler(.newData)
    }
    
    private func handleCometChatNotification(_ data: [String: Any]) {
        // Parse notification data
        guard let type = data["type"] as? String else { return }
        
        switch type {
        case "chat":
            handleChatNotification(data)
        case "call":
            handleCallNotification(data)
        default:
            print("Unknown notification type: \(type)")
        }
    }
    
    private func handleChatNotification(_ data: [String: Any]) {
        // Extract sender info
        guard let senderUID = data["sender"] as? String else { return }
        
        // Navigate to conversation
        DispatchQueue.main.async {
            NotificationCenter.default.post(
                name: .openConversation,
                object: nil,
                userInfo: ["uid": senderUID]
            )
        }
    }
    
    private func handleCallNotification(_ data: [String: Any]) {
        // Handle incoming call notification
        print("Incoming call notification")
    }
}

// MARK: - UNUserNotificationCenterDelegate

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    // Handle notification when app is in foreground
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        // Show notification even when app is in foreground
        completionHandler([.banner, .sound, .badge])
    }
    
    // Handle notification tap
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        let userInfo = response.notification.request.content.userInfo
        
        if let messageData = userInfo["message"] as? [String: Any] {
            handleCometChatNotification(messageData)
        }
        
        completionHandler()
    }
}

// MARK: - Notification Names

extension Notification.Name {
    static let openConversation = Notification.Name("openConversation")
}

Handle Notification Navigation

class MainViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Listen for notification navigation
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleOpenConversation(_:)),
            name: .openConversation,
            object: nil
        )
    }
    
    @objc private func handleOpenConversation(_ notification: Notification) {
        guard let uid = notification.userInfo?["uid"] as? String else { return }
        
        // Fetch user and open conversation
        CometChat.getUser(UID: uid) { [weak self] user in
            guard let user = user else { return }
            
            DispatchQueue.main.async {
                let messagesVC = MessagesVC()  // your own VC composing CometChatMessageHeader + List + Composer
                messagesVC.set(user: user)
                self?.navigationController?.pushViewController(messagesVC, animated: true)
            }
        } onError: { error in
            print("Error fetching user: \(error?.errorDescription ?? "")")
        }
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

---

5. VoIP Push Notifications (for Calls)

Import PushKit

import PushKit

Register for VoIP

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var voipRegistry: PKPushRegistry?
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        // ... other setup ...
        
        // Register for VoIP push
        registerForVoIPPush()
        
        return true
    }
    
    private func registerForVoIPPush() {
        voipRegistry = PKPushRegistry(queue: .main)
        voipRegistry?.delegate = self
        voipRegistry?.desiredPushTypes = [.voIP]
    }
}

// MARK: - PKPushRegistryDelegate

extension AppDelegate: PKPushRegistryDelegate {
    
    func pushRegistry(
        _ registry: PKPushRegistry,
        didUpdate pushCredentials: PKPushCredentials,
        for type: PKPushType
    ) {
        let token = pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()
        print("VoIP Token: \(token)")
        
        // Register VoIP token with CometChat — canonical v5 API uses the
        // .APNS_IOS_VOIP platform (NOT settings: ["voip": true]).
        CometChatNotifications.registerPushToken(
            pushToken: token,
            platform: .APNS_IOS_VOIP,
            providerId: nil
        ) { success in
            print("VoIP token registered: \(success)")
        } onError: { error in
            print("VoIP token registration failed: \(error.errorDescription)")
        }
    }
    
    func pushRegistry(
        _ registry: PKPushRegistry,
        didReceiveIncomingPushWith payload: PKPushPayload,
        for type: PKPushType,
        completion: @escaping () -> Void
    ) {
        print("Received VoIP push: \(payload.dictionaryPayload)")
        
        // Handle incoming call
        if let callData = payload.dictionaryPayload["call"] as? [String: Any] {
            handleIncomingCall(callData)
        }
        
        completion()
    }
    
    private func handleIncomingCall(_ data: [String: Any]) {
        // Show incoming call UI
        // This should use CallKit for proper iOS call handling
    }
}

---

6. UIKitSettings with Push Tokens

You can also pass tokens during initialization:

let uiKitSettings = UIKitSettings()
    .set(appID: "YOUR_APP_ID")
    .set(authKey: "YOUR_AUTH_KEY")
    .set(region: "us")
    .set(deviceToken: apnsToken)      // APNs token
    .set(voipToken: voipToken)        // VoIP token
    .subscribePresenceForAllUsers()
    .build()

CometChatUIKit(uiKitSettings: uiKitSettings) { result in
    // ...
}

---

7. Notification Service Extension

For rich notifications with images and custom content:

Create Extension

1. In Xcode, go to FileNewTarget 2. Select Notification Service Extension 3. Name it (e.g., "NotificationService")

Implement Extension

// NotificationService.swift
import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    
    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        guard let bestAttemptContent = bestAttemptContent else {
            contentHandler(request.content)
            return
        }
        
        // Customize notification content
        if let messageData = request.content.userInfo["message"] as? [String: Any] {
            customizeNotification(bestAttemptContent, with: messageData)
        }
        
        contentHandler(bestAttemptContent)
    }
    
    private func customizeNotification(
        _ content: UNMutableNotificationContent,
        with data: [String: Any]
    ) {
        // Set title from sender name
        if let senderName = data["senderName"] as? String {
            content.title = senderName
        }
        
        // Set body from message
        if let messageText = data["text"] as? String {
            content.body = messageText
        }
        
        // Add image attachment if available
        if let imageURL = data["imageURL"] as? String,
           let url = URL(string: imageURL) {
            downloadAndAttachImage(url, to: content)
        }
    }
    
    private func downloadAndAttachImage(_ url: URL, to content: UNMutableNotificationContent) {
        let task = URLSession.shared.downloadTask(with: url) { localURL, _, error in
            guard let localURL = localURL, error == nil else { return }
            
            let tempDir = FileManager.default.temporaryDirectory
            let tempFile = tempDir.appendingPathComponent(UUID().uuidString + ".jpg")
            
            try? FileManager.default.moveItem(at: localURL, to: tempFile)
            
            if let attachment = try? UNNotificationAttachment(identifier: "image", url: tempFile) {
                content.attachments = [attachment]
            }
            
            self.contentHandler?(content)
        }
        task.resume()
    }
    
    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

---

8. Badge Count Management

Update Badge Count

// Set badge count
UIApplication.shared.applicationIconBadgeNumber = unreadCount

// Clear badge count
UIApplication.shared.applicationIconBadgeNumber = 0

Sync with CometChat Unread Count

func updateBadgeCount() {
    // getUnreadMessageCount's success closure receives a SINGLE [String: Any]
    // (conversations keyed by uid/guid → count) — NOT two separate dicts.
    CometChat.getUnreadMessageCount { unread in
        var totalUnread = 0
        for (_, count) in unread {
            totalUnread += count as? Int ?? 0
        }

        DispatchQueue.main.async {
            UIApplication.shared.applicationIconBadgeNumber = totalUnread
        }
    } onError: { error in
        print("Error getting unread count: \(error?.errorDescription ?? "")")
    }
}

---

9. Testing Push Notifications

Using Terminal

# Test APNs push (requires authentication)
curl -v \
  --header "apns-topic: com.yourapp.bundleid" \
  --header "apns-push-type: alert" \
  --header "authorization: bearer $JWT_TOKEN" \
  --data '{"aps":{"alert":"Test message"}}' \
  --http2 \
  https://api.push.apple.com/3/device/$DEVICE_TOKEN

Using CometChat Dashboard

1. Go to CometChat Dashboard 2. Navigate to Users 3. Select a user 4. Click Send Push Notification 5. Enter a test message 6. Send

---

Troubleshooting

IssueSolution
Token not registeringEnsure device is physical, not simulator
Notifications not receivedCheck APNs certificate in dashboard
Badge not updatingCheck notification permissions
VoIP not workingEnsure VoIP capability is enabled
Notifications delayedCheck APNs environment (dev vs prod)

---

Best Practices

1. Always request permission before registering for notifications 2. Handle token refresh — tokens can change 3. Test on real devices — simulators don't support push 4. Use Notification Service Extension for rich notifications 5. Implement proper deep linking for notification taps 6. Clear badge count when user opens the app 7. Handle both foreground and background notifications

Related skills

Mobile Developmentfrontendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.