{"id":"6608911c-52e0-4469-9e00-f6703abc1d6b","shortId":"Jn9Nnt","kind":"skill","title":"cometchat-ios-push","tagline":"Set up push notifications for CometChat iOS apps — APNs configuration, token registration, and notification handling.","description":"## Purpose\n\nThis skill teaches how to set up push notifications for CometChat iOS apps, including APNs configuration, token registration, and handling incoming notifications.\n\n---\n\n## 1. Prerequisites\n\nBefore setting up push notifications:\n\n1. **Apple Developer Account** — Required for APNs certificates\n2. **CometChat Dashboard Access** — To configure push notification settings\n3. **Physical iOS Device** — Push notifications don't work on simulators\n\n---\n\n## 2. APNs Certificate Setup\n\n### Step 1: Create APNs Key (Recommended)\n\n1. Go to [Apple Developer Portal](https://developer.apple.com/account)\n2. Navigate to **Certificates, Identifiers & Profiles** → **Keys**\n3. Click **+** to create a new key\n4. Enter a name (e.g., \"CometChat Push Key\")\n5. Enable **Apple Push Notifications service (APNs)**\n6. Click **Continue** → **Register**\n7. Download the `.p8` file (you can only download it once!)\n8. Note the **Key ID** and your **Team ID**\n\n### Step 2: Configure CometChat Dashboard\n\n1. Go to [CometChat Dashboard](https://app.cometchat.com)\n2. Select your app\n3. Navigate to **Notifications** → **Push Notifications**\n4. Select **iOS** tab\n5. Upload your `.p8` file\n6. Enter your **Key ID** and **Team ID**\n7. Select the environment (Development/Production)\n8. Save the configuration\n\n---\n\n## 3. Xcode Project Configuration\n\n### Enable Push Notifications Capability\n\n1. Open your project in Xcode\n2. Select your target\n3. Go to **Signing & Capabilities**\n4. Click **+ Capability**\n5. Add **Push Notifications**\n6. Add **Background Modes** and enable:\n   - Remote notifications\n   - Voice over IP (if using calls)\n\n### Update Info.plist\n\nAdd the following to your `Info.plist`:\n\n```xml\n<key>UIBackgroundModes</key>\n<array>\n    <string>remote-notification</string>\n    <string>voip</string>\n</array>\n```\n\n---\n\n## 4. Code Implementation\n\n### AppDelegate Setup\n\n```swift\nimport UIKit\nimport UserNotifications\nimport CometChatUIKitSwift\nimport CometChatSDK\n\n@main\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    \n    func application(\n        _ application: UIApplication,\n        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n    ) -> Bool {\n        \n        // Initialize CometChat\n        initializeCometChat()\n        \n        // Request notification permissions\n        requestNotificationPermission()\n        \n        // Register for remote notifications\n        application.registerForRemoteNotifications()\n        \n        return true\n    }\n    \n    private func initializeCometChat() {\n        let uiKitSettings = UIKitSettings()\n            .set(appID: \"YOUR_APP_ID\")\n            .set(authKey: \"YOUR_AUTH_KEY\")\n            .set(region: \"us\")\n            .subscribePresenceForAllUsers()\n            .build()\n        \n        CometChatUIKit(uiKitSettings: uiKitSettings) { result in\n            switch result {\n            case .success:\n                print(\"CometChat initialized\")\n            case .failure(let error):\n                print(\"CometChat init failed: \\(error)\")\n            }\n        }\n    }\n    \n    private func requestNotificationPermission() {\n        let center = UNUserNotificationCenter.current()\n        center.delegate = self\n        \n        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in\n            if granted {\n                print(\"Notification permission granted\")\n            } else if let error = error {\n                print(\"Notification permission error: \\(error)\")\n            }\n        }\n    }\n    \n    // MARK: - Remote Notification Registration\n    \n    func application(\n        _ application: UIApplication,\n        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data\n    ) {\n        let token = deviceToken.map { String(format: \"%02.2hhx\", $0) }.joined()\n        print(\"APNs Device Token: \\(token)\")\n        \n        // Register token with CometChat\n        registerPushToken(token)\n    }\n    \n    func application(\n        _ application: UIApplication,\n        didFailToRegisterForRemoteNotificationsWithError error: Error\n    ) {\n        print(\"Failed to register for remote notifications: \\(error)\")\n    }\n    \n    private func registerPushToken(_ token: String) {\n        CometChat.registerTokenForPushNotification(\n            token: token,\n            settings: [\"voip\": false]\n        ) { success in\n            print(\"Push token registered: \\(success)\")\n        } onError: { error in\n            print(\"Push token registration failed: \\(error?.errorDescription ?? \"\")\")\n        }\n    }\n    \n    // MARK: - Handle Incoming Notifications\n    \n    func application(\n        _ application: UIApplication,\n        didReceiveRemoteNotification userInfo: [AnyHashable: Any],\n        fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void\n    ) {\n        print(\"Received remote notification: \\(userInfo)\")\n        \n        // Handle CometChat notification\n        if let messageData = userInfo[\"message\"] as? [String: Any] {\n            handleCometChatNotification(messageData)\n        }\n        \n        completionHandler(.newData)\n    }\n    \n    private func handleCometChatNotification(_ data: [String: Any]) {\n        // Parse notification data\n        guard let type = data[\"type\"] as? String else { return }\n        \n        switch type {\n        case \"chat\":\n            handleChatNotification(data)\n        case \"call\":\n            handleCallNotification(data)\n        default:\n            print(\"Unknown notification type: \\(type)\")\n        }\n    }\n    \n    private func handleChatNotification(_ data: [String: Any]) {\n        // Extract sender info\n        guard let senderUID = data[\"sender\"] as? String else { return }\n        \n        // Navigate to conversation\n        DispatchQueue.main.async {\n            NotificationCenter.default.post(\n                name: .openConversation,\n                object: nil,\n                userInfo: [\"uid\": senderUID]\n            )\n        }\n    }\n    \n    private func handleCallNotification(_ data: [String: Any]) {\n        // Handle incoming call notification\n        print(\"Incoming call notification\")\n    }\n}\n\n// MARK: - UNUserNotificationCenterDelegate\n\nextension AppDelegate: UNUserNotificationCenterDelegate {\n    \n    // Handle notification when app is in foreground\n    func userNotificationCenter(\n        _ center: UNUserNotificationCenter,\n        willPresent notification: UNNotification,\n        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void\n    ) {\n        // Show notification even when app is in foreground\n        completionHandler([.banner, .sound, .badge])\n    }\n    \n    // Handle notification tap\n    func userNotificationCenter(\n        _ center: UNUserNotificationCenter,\n        didReceive response: UNNotificationResponse,\n        withCompletionHandler completionHandler: @escaping () -> Void\n    ) {\n        let userInfo = response.notification.request.content.userInfo\n        \n        if let messageData = userInfo[\"message\"] as? [String: Any] {\n            handleCometChatNotification(messageData)\n        }\n        \n        completionHandler()\n    }\n}\n\n// MARK: - Notification Names\n\nextension Notification.Name {\n    static let openConversation = Notification.Name(\"openConversation\")\n}\n```\n\n### Handle Notification Navigation\n\n```swift\nclass MainViewController: UIViewController {\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        // Listen for notification navigation\n        NotificationCenter.default.addObserver(\n            self,\n            selector: #selector(handleOpenConversation(_:)),\n            name: .openConversation,\n            object: nil\n        )\n    }\n    \n    @objc private func handleOpenConversation(_ notification: Notification) {\n        guard let uid = notification.userInfo?[\"uid\"] as? String else { return }\n        \n        // Fetch user and open conversation\n        CometChat.getUser(UID: uid) { [weak self] user in\n            guard let user = user else { return }\n            \n            DispatchQueue.main.async {\n                let messagesVC = MessagesVC()  // your own VC composing CometChatMessageHeader + List + Composer\n                messagesVC.set(user: user)\n                self?.navigationController?.pushViewController(messagesVC, animated: true)\n            }\n        } onError: { error in\n            print(\"Error fetching user: \\(error?.errorDescription ?? \"\")\")\n        }\n    }\n    \n    deinit {\n        NotificationCenter.default.removeObserver(self)\n    }\n}\n```\n\n---\n\n## 5. VoIP Push Notifications (for Calls)\n\n### Import PushKit\n\n```swift\nimport PushKit\n```\n\n### Register for VoIP\n\n```swift\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    \n    var voipRegistry: PKPushRegistry?\n    \n    func application(\n        _ application: UIApplication,\n        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n    ) -> Bool {\n        \n        // ... other setup ...\n        \n        // Register for VoIP push\n        registerForVoIPPush()\n        \n        return true\n    }\n    \n    private func registerForVoIPPush() {\n        voipRegistry = PKPushRegistry(queue: .main)\n        voipRegistry?.delegate = self\n        voipRegistry?.desiredPushTypes = [.voIP]\n    }\n}\n\n// MARK: - PKPushRegistryDelegate\n\nextension AppDelegate: PKPushRegistryDelegate {\n    \n    func pushRegistry(\n        _ registry: PKPushRegistry,\n        didUpdate pushCredentials: PKPushCredentials,\n        for type: PKPushType\n    ) {\n        let token = pushCredentials.token.map { String(format: \"%02.2hhx\", $0) }.joined()\n        print(\"VoIP Token: \\(token)\")\n        \n        // Register VoIP token with CometChat\n        CometChat.registerTokenForPushNotification(\n            token: token,\n            settings: [\"voip\": true]\n        ) { success in\n            print(\"VoIP token registered: \\(success)\")\n        } onError: { error in\n            print(\"VoIP token registration failed: \\(error?.errorDescription ?? \"\")\")\n        }\n    }\n    \n    func pushRegistry(\n        _ registry: PKPushRegistry,\n        didReceiveIncomingPushWith payload: PKPushPayload,\n        for type: PKPushType,\n        completion: @escaping () -> Void\n    ) {\n        print(\"Received VoIP push: \\(payload.dictionaryPayload)\")\n        \n        // Handle incoming call\n        if let callData = payload.dictionaryPayload[\"call\"] as? [String: Any] {\n            handleIncomingCall(callData)\n        }\n        \n        completion()\n    }\n    \n    private func handleIncomingCall(_ data: [String: Any]) {\n        // Show incoming call UI\n        // This should use CallKit for proper iOS call handling\n    }\n}\n```\n\n---\n\n## 6. UIKitSettings with Push Tokens\n\nYou can also pass tokens during initialization:\n\n```swift\nlet uiKitSettings = UIKitSettings()\n    .set(appID: \"YOUR_APP_ID\")\n    .set(authKey: \"YOUR_AUTH_KEY\")\n    .set(region: \"us\")\n    .set(deviceToken: apnsToken)      // APNs token\n    .set(voipToken: voipToken)        // VoIP token\n    .subscribePresenceForAllUsers()\n    .build()\n\nCometChatUIKit(uiKitSettings: uiKitSettings) { result in\n    // ...\n}\n```\n\n---\n\n## 7. Notification Service Extension\n\nFor rich notifications with images and custom content:\n\n### Create Extension\n\n1. In Xcode, go to **File** → **New** → **Target**\n2. Select **Notification Service Extension**\n3. Name it (e.g., \"NotificationService\")\n\n### Implement Extension\n\n```swift\n// NotificationService.swift\nimport UserNotifications\n\nclass NotificationService: UNNotificationServiceExtension {\n    \n    var contentHandler: ((UNNotificationContent) -> Void)?\n    var bestAttemptContent: UNMutableNotificationContent?\n    \n    override func didReceive(\n        _ request: UNNotificationRequest,\n        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void\n    ) {\n        self.contentHandler = contentHandler\n        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)\n        \n        guard let bestAttemptContent = bestAttemptContent else {\n            contentHandler(request.content)\n            return\n        }\n        \n        // Customize notification content\n        if let messageData = request.content.userInfo[\"message\"] as? [String: Any] {\n            customizeNotification(bestAttemptContent, with: messageData)\n        }\n        \n        contentHandler(bestAttemptContent)\n    }\n    \n    private func customizeNotification(\n        _ content: UNMutableNotificationContent,\n        with data: [String: Any]\n    ) {\n        // Set title from sender name\n        if let senderName = data[\"senderName\"] as? String {\n            content.title = senderName\n        }\n        \n        // Set body from message\n        if let messageText = data[\"text\"] as? String {\n            content.body = messageText\n        }\n        \n        // Add image attachment if available\n        if let imageURL = data[\"imageURL\"] as? String,\n           let url = URL(string: imageURL) {\n            downloadAndAttachImage(url, to: content)\n        }\n    }\n    \n    private func downloadAndAttachImage(_ url: URL, to content: UNMutableNotificationContent) {\n        let task = URLSession.shared.downloadTask(with: url) { localURL, _, error in\n            guard let localURL = localURL, error == nil else { return }\n            \n            let tempDir = FileManager.default.temporaryDirectory\n            let tempFile = tempDir.appendingPathComponent(UUID().uuidString + \".jpg\")\n            \n            try? FileManager.default.moveItem(at: localURL, to: tempFile)\n            \n            if let attachment = try? UNNotificationAttachment(identifier: \"image\", url: tempFile) {\n                content.attachments = [attachment]\n            }\n            \n            self.contentHandler?(content)\n        }\n        task.resume()\n    }\n    \n    override func serviceExtensionTimeWillExpire() {\n        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {\n            contentHandler(bestAttemptContent)\n        }\n    }\n}\n```\n\n---\n\n## 8. Badge Count Management\n\n### Update Badge Count\n\n```swift\n// Set badge count\nUIApplication.shared.applicationIconBadgeNumber = unreadCount\n\n// Clear badge count\nUIApplication.shared.applicationIconBadgeNumber = 0\n```\n\n### Sync with CometChat Unread Count\n\n```swift\nfunc updateBadgeCount() {\n    CometChat.getUnreadMessageCount { userUnread, groupUnread in\n        var totalUnread = 0\n        \n        for (_, count) in userUnread {\n            totalUnread += count as? Int ?? 0\n        }\n        \n        for (_, count) in groupUnread {\n            totalUnread += count as? Int ?? 0\n        }\n        \n        DispatchQueue.main.async {\n            UIApplication.shared.applicationIconBadgeNumber = totalUnread\n        }\n    } onError: { error in\n        print(\"Error getting unread count: \\(error?.errorDescription ?? \"\")\")\n    }\n}\n```\n\n---\n\n## 9. Testing Push Notifications\n\n### Using Terminal\n\n```bash\n# Test APNs push (requires authentication)\ncurl -v \\\n  --header \"apns-topic: com.yourapp.bundleid\" \\\n  --header \"apns-push-type: alert\" \\\n  --header \"authorization: bearer $JWT_TOKEN\" \\\n  --data '{\"aps\":{\"alert\":\"Test message\"}}' \\\n  --http2 \\\n  https://api.push.apple.com/3/device/$DEVICE_TOKEN\n```\n\n### Using CometChat Dashboard\n\n1. Go to CometChat Dashboard\n2. Navigate to **Users**\n3. Select a user\n4. Click **Send Push Notification**\n5. Enter a test message\n6. Send\n\n---\n\n## Troubleshooting\n\n| Issue | Solution |\n|---|---|\n| Token not registering | Ensure device is physical, not simulator |\n| Notifications not received | Check APNs certificate in dashboard |\n| Badge not updating | Check notification permissions |\n| VoIP not working | Ensure VoIP capability is enabled |\n| Notifications delayed | Check APNs environment (dev vs prod) |\n\n---\n\n## Best Practices\n\n1. **Always request permission** before registering for notifications\n2. **Handle token refresh** — tokens can change\n3. **Test on real devices** — simulators don't support push\n4. **Use Notification Service Extension** for rich notifications\n5. **Implement proper deep linking** for notification taps\n6. **Clear badge count** when user opens the app\n7. **Handle both foreground and background** notifications","tags":["cometchat","ios","push","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-ios-push","topic-agent-skills","topic-ai-agent","topic-chat","topic-claude-code","topic-cometchat","topic-cursor","topic-messaging","topic-nextjs","topic-react","topic-react-native","topic-ui-kit"],"categories":["cometchat-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cometchat/cometchat-skills/cometchat-ios-push","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cometchat/cometchat-skills","source_repo":"https://github.com/cometchat/cometchat-skills","install_from":"skills.sh"}},"qualityScore":"0.463","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 27 github stars · SKILL.md body (16,284 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:04:53.454Z","embedding":null,"createdAt":"2026-05-07T13:05:13.501Z","updatedAt":"2026-05-18T19:04:53.454Z","lastSeenAt":"2026-05-18T19:04:53.454Z","tsv":"'/3/device/$device_token':1242 '/account)':96 '0':389,798,1157,1172,1181,1190 '02.2':387,796 '1':43,50,83,88,155,205,943,1246,1315 '2':58,78,97,151,161,211,951,1251,1323 '3':67,104,165,197,215,956,1255,1330 '4':111,171,220,255,1259,1340 '5':119,175,223,723,1264,1348 '6':126,180,227,883,1269,1356 '7':130,188,929,1365 '8':141,193,1140 '9':1204 'access':61 'account':53 'add':224,228,243,1054 'alert':349,1228,1236 'also':890 'alway':1316 'anim':709 'anyhash':455 'ap':1235 'api.push.apple.com':1241 'api.push.apple.com/3/device/$device_token':1240 'apn':13,35,56,79,85,125,392,915,1212,1220,1225,1287,1308 'apns-push-typ':1224 'apns-top':1219 'apnstoken':914 'app':12,33,164,306,568,588,902,1364 'app.cometchat.com':160 'appdeleg':258,271,563,739,779 'appid':304,900 'appl':51,91,121 'applic':275,276,376,377,403,404,450,451,746,747 'application.registerforremotenotifications':294 'attach':1056,1116,1124 'auth':311,907 'authent':1215 'authkey':309,905 'author':1230 'avail':1058 'background':229,1370 'badg':351,595,1141,1145,1149,1154,1291,1358 'banner':593 'bash':1210 'bearer':1231 'best':1313 'bestattemptcont':975,989,995,996,1013,1017,1136,1137,1139 'bodi':1042 'bool':282,753 'build':317,923 'call':240,507,554,558,728,852,857,872,881 'calldata':855,862 'callkit':877 'capabl':204,219,222,1302 'case':325,330,502,506 'center':343,574,601 'center.delegate':345 'center.requestauthorization':347 'certif':57,80,100,1288 'chang':1329 'chat':503 'check':1286,1294,1307 'class':270,638,738,967 'clear':1153,1357 'click':105,127,221,1260 'code':256 'com.yourapp.bundleid':1222 'cometchat':2,10,31,59,116,153,158,284,328,335,399,468,808,1160,1244,1249 'cometchat-ios-push':1 'cometchat.getunreadmessagecount':1166 'cometchat.getuser':678 'cometchat.registertokenforpushnotification':422,809 'cometchatmessagehead':699 'cometchatsdk':268 'cometchatuikit':318,924 'cometchatuikitswift':266 'complet':842,863 'completionhandl':458,480,580,592,607,623 'compos':698,701 'configur':14,36,63,152,196,200 'content':940,1003,1021,1074,1081,1126 'content.attachments':1123 'content.body':1052 'content.title':1039 'contenthandl':971,983,988,998,1016,1133,1134,1138 'continu':128 'convers':536,677 'count':1142,1146,1150,1155,1162,1174,1178,1183,1187,1201,1359 'creat':84,107,941 'curl':1216 'custom':939,1001 'customizenotif':1012,1020 'dashboard':60,154,159,1245,1250,1290 'data':381,485,490,494,505,509,519,528,549,867,1024,1035,1048,1062,1234 'deep':1351 'default':510 'deinit':720 'delay':1306 'deleg':771 'desiredpushtyp':774 'dev':1310 'develop':52,92 'developer.apple.com':95 'developer.apple.com/account)':94 'development/production':192 'devic':70,393,1278,1334 'devicetoken':380,913 'devicetoken.map':384 'didfailtoregisterforremotenotificationswitherror':406 'didfinishlaunchingwithopt':278,749 'didrec':603,979 'didreceiveincomingpushwith':836 'didreceiveremotenotif':453 'didregisterforremotenotificationswithdevicetoken':379 'didupd':785 'dispatchqueue.main.async':537,691,1191 'download':131,138 'downloadandattachimag':1071,1077 'e.g':115,959 'els':361,498,532,671,689,997,1097 'enabl':120,201,232,1304 'ensur':1277,1300 'enter':112,181,1265 'environ':191,1309 'error':333,338,353,364,365,369,370,407,408,416,436,443,712,715,718,823,830,1089,1095,1195,1198,1202 'errordescript':444,719,831,1203 'escap':459,581,608,843,984 'even':586 'extens':562,627,778,932,942,955,962,1344 'extract':522 'fail':337,410,442,829 'failur':331 'fals':427 'fetch':673,716 'fetchcompletionhandl':457 'file':134,179,948 'filemanager.default.moveitem':1109 'filemanager.default.temporarydirectory':1101 'follow':245 'foreground':571,591,1368 'format':386,795 'func':274,298,340,375,402,418,449,483,517,547,572,599,642,660,745,764,781,832,865,978,1019,1076,1129,1164 'get':1199 'go':89,156,216,946,1247 'grant':352,356,360 'groupunread':1168,1185 'guard':491,525,664,685,993,1091 'handl':19,40,446,467,552,565,596,634,850,882,1324,1366 'handlecallnotif':508,548 'handlechatnotif':504,518 'handlecometchatnotif':478,484,621 'handleincomingcal':861,866 'handleopenconvers':653,661 'header':1218,1223,1229 'hhx':388,797 'http2':1239 'id':145,149,184,187,307,903 'identifi':101,1119 'imag':937,1055,1120 'imageurl':1061,1063,1070 'implement':257,961,1349 'import':261,263,265,267,729,732,965 'includ':34 'incom':41,447,553,557,851,871 'info':524 'info.plist':242,248 'init':336 'initi':283,329,894 'initializecometchat':285,299 'int':1180,1189 'io':3,11,32,69,173,880 'ip':237 'issu':1272 'join':390,799 'jpg':1107 'jwt':1232 'key':86,103,110,118,144,183,312,908 'launchopt':279,750 'let':300,332,342,363,382,471,492,526,610,614,630,665,686,692,791,854,896,994,1005,1033,1046,1060,1066,1083,1092,1099,1102,1115,1132,1135 'link':1352 'list':700 'listen':645 'localurl':1088,1093,1094,1111 'main':269,769 'mainviewcontrol':639 'manag':1143 'mark':371,445,560,624,776 'messag':474,617,1008,1044,1238,1268 'messagedata':472,479,615,622,1006,1015 'messagesvc':693,694,708 'messagesvc.set':702 'messagetext':1047,1053 'mode':230 'name':114,539,626,654,957,1031 'navig':98,166,534,636,648,1252 'navigationcontrol':706 'new':109,949 'newdata':481 'nil':542,657,1096 'note':142 'notif':8,18,29,42,49,65,72,123,168,170,203,226,234,253,287,293,358,367,373,415,448,465,469,489,513,555,559,566,577,585,597,625,635,647,662,663,726,930,935,953,1002,1207,1263,1283,1295,1305,1322,1342,1347,1354,1371 'notification.name':628,632 'notification.userinfo':667 'notificationcenter.default.addobserver':649 'notificationcenter.default.post':538 'notificationcenter.default.removeobserver':721 'notificationservic':960,968 'notificationservice.swift':964 'objc':658 'object':541,656 'onerror':435,711,822,1194 'open':206,676,1362 'openconvers':540,631,633,655 'option':348 'overrid':641,977,1128 'p8':133,178 'pars':488 'pass':891 'payload':837 'payload.dictionarypayload':849,856 'permiss':288,359,368,1296,1318 'physic':68,1280 'pkpushcredenti':787 'pkpushpayload':838 'pkpushregistri':744,767,784,835 'pkpushregistrydeleg':777,780 'pkpushtyp':790,841 'portal':93 'practic':1314 'prerequisit':44 'print':327,334,357,366,391,409,430,438,462,511,556,714,800,817,825,845,1197 'privat':297,339,417,482,516,546,659,763,864,1018,1075 'prod':1312 'profil':102 'project':199,208 'proper':879,1350 'purpos':20 'push':4,7,28,48,64,71,117,122,169,202,225,431,439,725,759,848,886,1206,1213,1226,1262,1339 'pushcredenti':786 'pushcredentials.token.map':793 'pushkit':730,733 'pushregistri':782,833 'pushviewcontrol':707 'queue':768 'real':1333 'receiv':463,846,1285 'recommend':87 'refresh':1326 'region':314,910 'regist':129,290,396,412,433,734,756,804,820,1276,1320 'registerforvoippush':760,765 'registerpushtoken':400,419 'registr':16,38,374,441,828 'registri':783,834 'remot':233,252,292,372,414,464 'remote-notif':251 'request':286,980,1317 'request.content':999 'request.content.mutablecopy':990 'request.content.userinfo':1007 'requestnotificationpermiss':289,341 'requir':54,1214 'respons':604 'response.notification.request.content.userinfo':612 'result':321,324,927 'return':295,499,533,672,690,761,1000,1098 'rich':934,1346 'save':194 'select':162,172,189,212,952,1256 'selector':651,652 'self':346,650,682,705,722,772 'self.contenthandler':987,1125 'send':1261,1270 'sender':523,529,1030 'sendernam':1034,1036,1040 'senderuid':527,545 'servic':124,931,954,1343 'serviceextensiontimewillexpir':1130 'set':5,26,46,66,303,308,313,425,812,899,904,909,912,917,1027,1041,1148 'setup':81,259,755 'show':584,870 'sign':218 'simul':77,1282,1335 'skill':22 'skill-cometchat-ios-push' 'solut':1273 'sound':350,594 'source-cometchat' 'static':629 'step':82,150 'string':385,421,476,486,497,520,531,550,619,670,794,859,868,1010,1025,1038,1051,1065,1069 'subscribepresenceforallus':316,922 'success':326,428,434,815,821 'super.viewdidload':644 'support':1338 'swift':260,637,731,737,895,963,1147,1163 'switch':323,500 'sync':1158 'tab':174 'tap':598,1355 'target':214,950 'task':1084 'task.resume':1127 'teach':23 'team':148,186 'tempdir':1100 'tempdir.appendingpathcomponent':1104 'tempfil':1103,1113,1122 'termin':1209 'test':1205,1211,1237,1267,1331 'text':1049 'titl':1028 'token':15,37,383,394,395,397,401,420,423,424,432,440,792,802,803,806,810,811,819,827,887,892,916,921,1233,1274,1325,1327 'topic':1221 'topic-agent-skills' 'topic-ai-agent' 'topic-chat' 'topic-claude-code' 'topic-cometchat' 'topic-cursor' 'topic-messaging' 'topic-nextjs' 'topic-react' 'topic-react-native' 'topic-ui-kit' 'totalunread':1171,1177,1186,1193 'tri':1108,1117 'troubleshoot':1271 'true':296,710,762,814 'type':493,495,501,514,515,789,840,1227 'ui':873 'uiapplic':277,378,405,452,748 'uiapplication.launchoptionskey':280,751 'uiapplication.shared.applicationiconbadgenumber':1151,1156,1192 'uiapplicationdeleg':273,741 'uibackgroundfetchresult':460 'uibackgroundmod':250 'uid':544,666,668,679,680 'uikit':262 'uikitset':301,302,319,320,884,897,898,925,926 'uirespond':272,740 'uiviewcontrol':640 'unknown':512 'unmutablenotificationcont':976,992,1022,1082 'unnotif':578 'unnotificationattach':1118 'unnotificationcont':972,985 'unnotificationpresentationopt':582 'unnotificationrequest':981 'unnotificationrespons':605 'unnotificationserviceextens':969 'unread':1161,1200 'unreadcount':1152 'unusernotificationcent':575,602 'unusernotificationcenter.current':344 'unusernotificationcenterdeleg':561,564 'updat':241,1144,1293 'updatebadgecount':1165 'upload':176 'url':1067,1068,1072,1078,1079,1087,1121 'urlsession.shared.downloadtask':1085 'us':315,911 'use':239,876,1208,1243,1341 'user':674,683,687,688,703,704,717,1254,1258,1361 'userinfo':454,466,473,543,611,616 'usernotif':264,966 'usernotificationcent':573,600 'userunread':1167,1176 'uuid':1105 'uuidstr':1106 'v':1217 'var':742,970,974,1170 'vc':697 'viewdidload':643 'voic':235 'void':461,583,609,844,973,986 'voip':254,426,724,736,758,775,801,805,813,818,826,847,920,1297,1301 'voipregistri':743,766,770,773 'voiptoken':918,919 'vs':1311 'weak':681 'willpres':576 'withcompletionhandl':579,606 'withcontenthandl':982 'work':75,1299 'xcode':198,210,945 'xml':249","prices":[{"id":"fa326e67-e86e-4a70-82a6-00a9c101c2eb","listingId":"6608911c-52e0-4469-9e00-f6703abc1d6b","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cometchat","category":"cometchat-skills","install_from":"skills.sh"},"createdAt":"2026-05-07T13:05:13.501Z"}],"sources":[{"listingId":"6608911c-52e0-4469-9e00-f6703abc1d6b","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-ios-push","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-ios-push","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:13.501Z","lastSeenAt":"2026-05-18T19:04:53.454Z"}],"details":{"listingId":"6608911c-52e0-4469-9e00-f6703abc1d6b","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-ios-push","github":{"repo":"cometchat/cometchat-skills","stars":27,"topics":["agent-skills","ai-agent","chat","claude-code","cometchat","cursor","messaging","nextjs","react","react-native","ui-kit"],"license":null,"html_url":"https://github.com/cometchat/cometchat-skills","pushed_at":"2026-05-18T05:04:24Z","description":"Add CometChat chat to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.","skill_md_sha":"f87a8e04424037e14ac2ec4cf80ba097913e3675","skill_md_path":"skills/cometchat-ios-push/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-ios-push"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-ios-push","license":"MIT","description":"Set up push notifications for CometChat iOS apps — APNs configuration, token registration, and notification handling.","compatibility":"CometChatUIKitSwift ^5; iOS 13+"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-ios-push"},"updatedAt":"2026-05-18T19:04:53.454Z"}}