{"id":"c0e25156-8a1a-4bc5-97a1-ded35f94f096","shortId":"CEKRZH","kind":"skill","title":"cometchat-ios-core","tagline":"Shared rules for CometChat iOS UI Kit v5. Always loaded alongside placement skills. Read this first.","description":"## Purpose\n\nThis is the foundational skill for every CometChat iOS UI Kit v5 integration. It teaches HOW CometChat works on iOS — initialization, login, the manager pattern, and anti-patterns — so you can write project-appropriate code instead of relying on templates.\n\n**Read this skill first, before any placement or component skill.**\n\n---\n\n## 1. Installation\n\n### 0. First — confirm a dependency manifest exists (or create one)\n\nA freshly-created Xcode project (`File → New → App` from the GUI) ships **no `Podfile`, no `Package.swift`, and no Swift Package Manager refs in `*.xcodeproj/project.pbxproj`**. Before touching any of the integration code below, you MUST establish a dependency-management mechanism — otherwise `import CometChatUIKitSwift` will hit `Unable to resolve module dependency: 'CometChatSDK'` at the first build attempt and the entire integration is dead on arrival.\n\n**Detection:**\n\n```bash\nls Podfile Package.swift 2>/dev/null\ngrep -l \"XCRemoteSwiftPackageReference\\|repositoryURL.*cometchat\" *.xcodeproj/project.pbxproj 2>/dev/null\n```\n\nIf all three return empty → **fresh Xcode project, no dep manager**. Pick one and set it up before continuing:\n\n**Option A — CocoaPods (most common, easiest to script):**\n\n```bash\ncd <project-root>\ncat > Podfile <<'POD'\nplatform :ios, '13.0'\nuse_frameworks!\n\ntarget 'YourAppTargetName' do\n  pod 'CometChatUIKitSwift', '~> 5.1'\nend\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      config.build_settings['ENABLE_USER_SCRIPT_SANDBOXING'] = 'NO'\n    end\n  end\nend\nPOD\npod install\n```\n\nAfter `pod install`, work from `YourApp.xcworkspace` (NOT `.xcodeproj`) — CocoaPods rewires the workspace to include the Pods project.\n\n**Option B — Swift Package Manager (no Podfile, no `.xcworkspace`):**\n\nThe user must add the package via Xcode's GUI (the SPM dependency lives in `*.xcodeproj/project.pbxproj` and there's no clean CLI tooling to edit that file safely). Print these instructions verbatim:\n\n> 1. Open `<YourApp>.xcodeproj` in Xcode\n> 2. **File → Add Package Dependencies…**\n> 3. Paste URL: `https://github.com/cometchat/cometchat-uikit-ios`\n> 4. **Add Package** → keep \"Up to Next Major Version\" defaults → **Add Package** again\n> 5. Confirm `CometChatUIKitSwift` appears under your app target's *Frameworks, Libraries, and Embedded Content*\n\n**Then verify the package landed:**\n\n```bash\ngrep -E \"cometchat-uikit-ios|CometChatUIKitSwift\" *.xcodeproj/project.pbxproj | head -2\n```\n\nIf grep returns matches, the SPM dep is in. If it doesn't, the user didn't complete step 4 in Xcode — surface that explicitly and stop until they have.\n\n**HARD STOP if neither option is in place.** Do not write `import CometChatUIKitSwift` into any Swift file until either `pod install` completes successfully or the SPM grep above returns matches. Skipping this step produces an integration that compiles only after the user does extra setup work — a worse outcome than asking them up-front.\n\n### CocoaPods (full reference — only if you skipped Option A above)\n\nAdd to your `Podfile`:\n\n```ruby\nplatform :ios, '13.0'\nuse_frameworks!\n\ntarget 'YourApp' do\n  pod 'CometChatUIKitSwift', '~> 5.1'\nend\n```\n\nThen run:\n```bash\npod install\n```\n\n**Important: Disable User Script Sandboxing (Xcode 15+)**\n\nAfter running `pod install`, you must disable user script sandboxing in your project's Build Settings:\n\n1. Open your `.xcworkspace` file\n2. Select your app target\n3. Go to **Build Settings**\n4. Search for \"User Script Sandboxing\"\n5. Set **ENABLE_USER_SCRIPT_SANDBOXING** to **No**\n\nOr add this to your `Podfile` to do it automatically:\n\n```ruby\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      config.build_settings['ENABLE_USER_SCRIPT_SANDBOXING'] = 'NO'\n    end\n  end\nend\n```\n\n### Swift Package Manager\n\nAdd the package URL in Xcode (File → Add Package Dependencies):\n\n**CometChat UI Kit (includes SDK):**\n```\nhttps://github.com/cometchat/cometchat-uikit-ios\n```\n\n**CometChat SDK only (if needed separately):**\n```\nhttps://github.com/cometchat/chat-sdk-ios\n```\n\n**CometChat Calls SDK (for voice/video calls):**\n```\nhttps://github.com/cometchat/cometchat-calls-sdk-ios\n```\n\nOr add to `Package.swift`:\n```swift\ndependencies: [\n    .package(url: \"https://github.com/cometchat/cometchat-uikit-ios\", from: \"5.0.0\"),\n    // Optional: Add calls SDK for voice/video\n    // .package(url: \"https://github.com/cometchat/cometchat-calls-sdk-ios\", from: \"4.0.0\")\n]\n```\n\n### GitHub Repositories\n\n| Package | Repository | Description |\n|---------|------------|-------------|\n| UI Kit | https://github.com/cometchat/cometchat-uikit-ios | Ready-to-use UI components |\n| Chat SDK | https://github.com/cometchat/chat-sdk-ios | Core messaging SDK |\n| Calls SDK | https://github.com/cometchat/cometchat-calls-sdk-ios | Voice & video calling |\n| Sample App | https://github.com/cometchat/cometchat-sample-app-ios | Sample implementation |\n\n---\n\n## 2. Initialization\n\nCometChat must be initialized exactly once before any UI component is used. Initialization is asynchronous and must complete fully before mounting any `CometChat*` view controller.\n\n### UIKitSettings Builder\n\n```swift\nimport CometChatUIKitSwift\n\nlet uiKitSettings = UIKitSettings()\n    .set(appID: \"YOUR_APP_ID\")\n    .set(authKey: \"YOUR_AUTH_KEY\")  // Required for dev mode\n    .set(region: \"us\")               // \"us\", \"eu\", or \"in\"\n    .subscribePresenceForAllUsers()  // Enable online/offline indicators\n    .build()\n```\n\n### Init must happen once\n\nUse a singleton manager to prevent double-init:\n\n```swift\nimport CometChatUIKitSwift\nimport CometChatSDK\n\nfinal class CometChatManager {\n    static let shared = CometChatManager()\n    \n    private var isInitialized = false\n    private var initializationError: Error?\n    \n    private init() {}\n    \n    func initialize(\n        appID: String,\n        authKey: String,\n        region: String,\n        completion: @escaping (Result<Bool, Error>) -> Void\n    ) {\n        guard !isInitialized else {\n            completion(.success(true))\n            return\n        }\n        \n        let uiKitSettings = UIKitSettings()\n            .set(appID: appID)\n            .set(authKey: authKey)\n            .set(region: region)\n            .subscribePresenceForAllUsers()\n            .build()\n        \n        CometChatUIKit(uiKitSettings: uiKitSettings) { result in\n            switch result {\n            case .success(let success):\n                self.isInitialized = success\n                completion(.success(success))\n            case .failure(let error):\n                self.initializationError = error\n                completion(.failure(error))\n            }\n        }\n    }\n}\n```\n\n### Init in AppDelegate (UIKit apps)\n\n```swift\nimport UIKit\nimport CometChatUIKitSwift\n\n@main\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    \n    func application(\n        _ application: UIApplication,\n        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n    ) -> Bool {\n        \n        CometChatManager.shared.initialize(\n            appID: \"YOUR_APP_ID\",\n            authKey: \"YOUR_AUTH_KEY\",\n            region: \"us\"\n        ) { result in\n            switch result {\n            case .success:\n                print(\"CometChat initialized successfully\")\n            case .failure(let error):\n                print(\"CometChat initialization failed: \\(error)\")\n            }\n        }\n        \n        return true\n    }\n}\n```\n\n### Init in App struct (SwiftUI apps)\n\n```swift\nimport SwiftUI\nimport CometChatUIKitSwift\n\n@main\nstruct YourApp: App {\n    \n    init() {\n        CometChatManager.shared.initialize(\n            appID: \"YOUR_APP_ID\",\n            authKey: \"YOUR_AUTH_KEY\",\n            region: \"us\"\n        ) { result in\n            switch result {\n            case .success:\n                print(\"CometChat initialized successfully\")\n            case .failure(let error):\n                print(\"CometChat initialization failed: \\(error)\")\n            }\n        }\n    }\n    \n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n```\n\n---\n\n## 3. Login\n\n### Development mode\n\nUse `CometChatUIKit.login(uid:)` with a test UID. Every new CometChat app comes with five pre-created test users: `cometchat-uid-1` through `cometchat-uid-5`.\n\n**Important:** The login callback uses `.success` and `.onError` cases, NOT Swift's standard `Result` type.\n\n```swift\nCometChatUIKit.login(uid: \"cometchat-uid-1\") { result in\n    switch result {\n    case .success(let user):\n        print(\"Logged in as: \\(user.name ?? \"\")\")\n        // Proceed to chat UI\n    case .onError(let error):\n        print(\"Login failed: \\(error.errorDescription)\")\n    @unknown default:\n        break\n    }\n}\n```\n\n### Production mode\n\nUse `CometChatUIKit.login(authToken:)` with a token obtained from your backend:\n\n```swift\nCometChatUIKit.login(authToken: authToken) { result in\n    switch result {\n    case .success(let user):\n        print(\"Logged in as: \\(user.name ?? \"\")\")\n    case .onError(let error):\n        print(\"Login failed: \\(error.errorDescription)\")\n    @unknown default:\n        break\n    }\n}\n```\n\n### Getting the current logged-in user\n\n```swift\n// Synchronous — use when you know init is complete\nif let currentUser = CometChatUIKit.getLoggedInUser() {\n    print(\"Logged in as: \\(currentUser.name ?? \"\")\")\n}\n```\n\n### Logout\n\n```swift\nif let currentUser = CometChat.getLoggedInUser() {\n    CometChatUIKit.logout(user: currentUser) { result in\n        switch result {\n        case .success:\n            print(\"Logged out successfully\")\n        case .onError(let error):\n            print(\"Logout failed: \\(error.errorDescription)\")\n        @unknown default:\n            break\n        }\n    }\n}\n```\n\n---\n\n## 3.1 Error Handling\n\nCometChat uses `CometChatException` for errors. **Important:** Use `errorDescription` property, NOT `localizedDescription`.\n\n### CometChatException Properties\n\n```swift\n// CometChatException has these properties:\nerror.errorCode        // String - error code like \"ERR_UID_NOT_FOUND\"\nerror.errorDescription // String - human-readable description\nerror.details          // [String: Any]? - additional details\n```\n\n### Correct Error Handling\n\n```swift\nCometChatUIKit.login(uid: \"user-123\") { result in\n    switch result {\n    case .success(let user):\n        print(\"Logged in: \\(user.name ?? \"\")\")\n    case .onError(let error):\n        print(\"Error: \\(error.errorDescription)\")\n        print(\"Code: \\(error.errorCode)\")\n    }\n}\n```\n\n### Error Handling in Closures\n\n```swift\n// For onError closures where error might be optional:\nCometChat.getUser(UID: \"user-123\") { user in\n    print(\"User: \\(user?.name ?? \"\")\")\n} onError: { error in\n    // error is CometChatException? (optional)\n    print(\"Error: \\(error?.errorDescription ?? \"Unknown error\")\")\n}\n\n// For ApiStatus enum results:\nCometChatUIKit.create(user: newUser) { result in\n    switch result {\n    case .success(let user):\n        print(\"Created: \\(user.name ?? \"\")\")\n    case .onError(let error):\n        // error is CometChatException (non-optional)\n        print(\"Error: \\(error.errorDescription)\")\n    }\n}\n```\n\n### Common Error Codes\n\n| Code | Description |\n|---|---|\n| `ERR_UID_NOT_FOUND` | User doesn't exist |\n| `ERR_ALREADY_LOGGED_IN` | User already logged in |\n| `ERR_NOT_LOGGED_IN` | No active session |\n| `AUTH_ERR_AUTH_TOKEN_NOT_FOUND` | Invalid auth token |\n| `ERR_INVALID_APP_ID` | Wrong App ID |\n| `ERR_INVALID_API_KEY` | Wrong API/Auth Key |\n\n---\n\n## 4. Credentials Management\n\n### Using a Constants file (Development)\n\n```swift\n// Constants.swift\nstruct CometChatConstants {\n    static let appID = \"YOUR_APP_ID\"\n    static let authKey = \"YOUR_AUTH_KEY\"\n    static let region = \"us\"\n}\n```\n\n**Important:** Add `Constants.swift` to `.gitignore` for production apps.\n\n### Using Info.plist\n\nAdd keys to your `Info.plist`:\n```xml\n<key>CometChatAppID</key>\n<string>YOUR_APP_ID</string>\n<key>CometChatAuthKey</key>\n<string>YOUR_AUTH_KEY</string>\n<key>CometChatRegion</key>\n<string>us</string>\n```\n\nRead them in code:\n```swift\nguard let appID = Bundle.main.object(forInfoDictionaryKey: \"CometChatAppID\") as? String,\n      let authKey = Bundle.main.object(forInfoDictionaryKey: \"CometChatAuthKey\") as? String,\n      let region = Bundle.main.object(forInfoDictionaryKey: \"CometChatRegion\") as? String else {\n    fatalError(\"CometChat credentials not found in Info.plist\")\n}\n```\n\n### Using xcconfig files (Recommended for production)\n\nCreate `Debug.xcconfig` and `Release.xcconfig`:\n```\n// Debug.xcconfig\nCOMETCHAT_APP_ID = your_app_id\nCOMETCHAT_AUTH_KEY = your_auth_key\nCOMETCHAT_REGION = us\n```\n\nReference in `Info.plist`:\n```xml\n<key>CometChatAppID</key>\n<string>$(COMETCHAT_APP_ID)</string>\n```\n\n---\n\n## 5. The Manager Pattern\n\nThe recommended pattern for iOS is a singleton manager that handles initialization, login state, and provides a clean API for the rest of the app.\n\n### Complete CometChatManager\n\n**Important:** `CometChatException` does NOT conform to Swift's `Error` protocol. Use `CometChatException` directly in your callbacks, not `Result<T, Error>`.\n\n```swift\nimport Foundation\nimport CometChatUIKitSwift\nimport CometChatSDK\n\nfinal class CometChatManager {\n    \n    // MARK: - Singleton\n    static let shared = CometChatManager()\n    \n    // MARK: - State\n    private(set) var isInitialized = false\n    private(set) var currentUser: User?\n    \n    // MARK: - Callbacks\n    var onLoginStateChanged: ((User?) -> Void)?\n    \n    private init() {}\n    \n    // MARK: - Initialization\n    func initialize(\n        appID: String,\n        authKey: String,\n        region: String,\n        completion: @escaping (Bool, CometChatException?) -> Void\n    ) {\n        guard !isInitialized else {\n            completion(true, nil)\n            return\n        }\n        \n        let uiKitSettings = UIKitSettings()\n            .set(appID: appID)\n            .set(authKey: authKey)\n            .set(region: region)\n            .subscribePresenceForAllUsers()\n            .build()\n        \n        CometChatUIKit.init(uiKitSettings: uiKitSettings) { [weak self] result in\n            DispatchQueue.main.async {\n                switch result {\n                case .success(let success):\n                    self?.isInitialized = success\n                    self?.currentUser = CometChatUIKit.getLoggedInUser()\n                    completion(success, nil)\n                case .failure(let error):\n                    completion(false, error as? CometChatException)\n                }\n            }\n        }\n    }\n    \n    // MARK: - Login with UID (Development)\n    func login(uid: String, completion: @escaping (User?, CometChatException?) -> Void) {\n        guard isInitialized else {\n            print(\"CometChat not initialized\")\n            completion(nil, nil)\n            return\n        }\n        \n        if let user = currentUser {\n            completion(user, nil)\n            return\n        }\n        \n        CometChatUIKit.login(uid: uid) { [weak self] result in\n            DispatchQueue.main.async {\n                switch result {\n                case .success(let user):\n                    self?.currentUser = user\n                    self?.onLoginStateChanged?(user)\n                    completion(user, nil)\n                case .onError(let error):\n                    completion(nil, error)\n                @unknown default:\n                    completion(nil, nil)\n                }\n            }\n        }\n    }\n    \n    // MARK: - Login with Auth Token (Production)\n    func loginWithToken(_ authToken: String, completion: @escaping (User?, CometChatException?) -> Void) {\n        guard isInitialized else {\n            print(\"CometChat not initialized\")\n            completion(nil, nil)\n            return\n        }\n        \n        CometChatUIKit.login(authToken: authToken) { [weak self] result in\n            DispatchQueue.main.async {\n                switch result {\n                case .success(let user):\n                    self?.currentUser = user\n                    self?.onLoginStateChanged?(user)\n                    completion(user, nil)\n                case .onError(let error):\n                    completion(nil, error)\n                @unknown default:\n                    completion(nil, nil)\n                }\n            }\n        }\n    }\n    \n    // MARK: - Logout\n    func logout(completion: @escaping (Bool, CometChatException?) -> Void) {\n        guard let user = currentUser else {\n            completion(true, nil)\n            return\n        }\n        \n        CometChatUIKit.logout(user: user) { [weak self] result in\n            DispatchQueue.main.async {\n                switch result {\n                case .success:\n                    self?.currentUser = nil\n                    self?.onLoginStateChanged?(nil)\n                    completion(true, nil)\n                case .onError(let error):\n                    completion(false, error)\n                @unknown default:\n                    completion(false, nil)\n                }\n            }\n        }\n    }\n}\n```\n\n### Usage Example\n\n```swift\n// Initialize\nCometChatManager.shared.initialize(\n    appID: \"YOUR_APP_ID\",\n    authKey: \"YOUR_AUTH_KEY\",\n    region: \"us\"\n) { success, error in\n    if success {\n        print(\"Initialized successfully\")\n    } else if let error = error {\n        print(\"Init failed: \\(error.errorDescription)\")\n    }\n}\n\n// Login\nCometChatManager.shared.login(uid: \"cometchat-uid-1\") { user, error in\n    if let user = user {\n        print(\"Logged in as: \\(user.name ?? \"\")\")\n        // Show chat UI\n    } else if let error = error {\n        print(\"Login failed: \\(error.errorDescription)\")\n    }\n}\n\n// Logout\nCometChatManager.shared.logout { success, error in\n    if success {\n        print(\"Logged out\")\n    } else if let error = error {\n        print(\"Logout failed: \\(error.errorDescription)\")\n    }\n}\n```\n\n---\n\n## 6. Theming\n\n### Global Theme Configuration\n\nCometChat iOS UI Kit uses `CometChatTheme` for styling. Configure it before showing any UI:\n\n```swift\n// Set primary color\nCometChatTheme.primaryColor = UIColor.systemBlue\n\n// Set background colors\nCometChatTheme.backgroundColor01 = UIColor.systemBackground\nCometChatTheme.backgroundColor02 = UIColor.secondarySystemBackground\n\n// Set text colors\nCometChatTheme.textColorPrimary = UIColor.label\nCometChatTheme.textColorSecondary = UIColor.secondaryLabel\n```\n\n### Component-Level Styling\n\nEach component has a static `style` property:\n\n```swift\n// Conversations list style\nCometChatConversations.style.backgroundColor = .systemBackground\nCometChatConversations.style.titleColor = .label\n\n// Message list style\nCometChatMessageList.style.backgroundColor = .systemBackground\n\n// Avatar style — cornerRadius is a CGFloat on a CometChatCornerStyle,\n// NOT a `.circle` enum case. Use a value larger than half the avatar\n// dimension for a circular look.\nCometChatAvatar.style.backgroundColor = .systemGray5\nCometChatAvatar.style.cornerRadius = CometChatCornerStyle(cornerRadius: 100)\n```\n\n### Dark Mode Support\n\nCometChat automatically supports dark mode when using system colors:\n\n```swift\nCometChatTheme.primaryColor = UIColor { traitCollection in\n    traitCollection.userInterfaceStyle == .dark \n        ? UIColor.systemBlue \n        : UIColor.blue\n}\n```\n\n---\n\n## 7. Localization\n\nCometChat iOS UI Kit supports 20+ languages out of the box. The language is automatically detected from the device settings.\n\n### Supported Languages\n\nArabic, Chinese (Simplified), Chinese (Traditional), Dutch, English, French, German, Hindi, Hungarian, Japanese, Korean, Lithuanian, Malay, Portuguese, Russian, Spanish, Swedish, Turkish\n\n### Setting locale\n\n`CometChatLocalize` is a `Bundle` subclass that swaps the kit's `.lproj` lookup at runtime. The public API is locale-only:\n\n```swift\nCometChatLocalize.set(locale: .english)        // enum value\nCometChatLocalize.set(locale: \"fr\")            // raw string\n```\n\nThere is no `CometChatLocalize.set(key:value:)` for ad-hoc key overrides — to customize specific strings, override them in your app's `Localizable.strings` file (the kit reads through the standard bundle lookup chain).\n\n---\n\n## 8. Anti-patterns\n\nThese are specific things NOT to do. Each one causes real bugs.\n\n1. **Do NOT call `CometChatUIKit.init()` multiple times.** Init should happen once in AppDelegate or App init. Multiple init calls cause undefined behavior.\n\n2. **Do NOT show CometChat UI before init completes.** Components assume the SDK is initialized. Showing UI before init finishes causes crashes.\n\n3. **Do NOT hardcode Auth Key in production code.** The auth key is a secret. Use environment variables or xcconfig files. Use auth tokens in production.\n\n4. **Do NOT ignore the completion handler.** Init and login are async. Always handle the completion to know when it's safe to proceed.\n\n5. **Do NOT create multiple instances of CometChatManager.** Use the singleton pattern. Multiple managers cause state inconsistencies.\n\n6. **Do NOT call login while another login is in progress.** Check `currentUser` first. Concurrent login calls cause errors.\n\n7. **Do NOT forget to handle logout.** When your app's user logs out, call `CometChatManager.shared.logout()` to clear the CometChat session.\n\n8. **Do NOT ignore memory management.** CometChat view controllers should be properly deallocated. Avoid retain cycles with closures.\n\n9. **Do NOT block the main thread.** All CometChat callbacks are on the main thread. Don't do heavy work in callbacks.\n\n10. **Do NOT invent component names.** CometChat exports specific components with specific names. Check the `cometchat-ios-components` skill before writing any code.\n\n---\n\n## 9. SDK Types Reference\n\nCommon types from `CometChatSDK`:\n\n```swift\nimport CometChatSDK\n\n// User — represents a chat user\nlet user: User\n\n// Group — represents a chat group\nlet group: Group\n\n// Conversation — wraps User or Group\nlet conversation: Conversation\n\n// BaseMessage — base class for all messages\nlet message: BaseMessage\n\n// TextMessage — a text message\nlet textMessage: TextMessage\n\n// MediaMessage — image, video, audio, file\nlet mediaMessage: MediaMessage\n\n// CustomMessage — custom data message\nlet customMessage: CustomMessage\n```\n\n### Getting entities\n\n```swift\n// Get a user by UID\nCometChat.getUser(UID: \"user-uid\") { user in\n    print(\"User: \\(user?.name ?? \"\")\")\n} onError: { error in\n    print(\"Error: \\(error?.errorDescription ?? \"\")\")\n}\n\n// Get a group by GUID\nCometChat.getGroup(GUID: \"group-guid\") { group in\n    print(\"Group: \\(group?.name ?? \"\")\")\n} onError: { error in\n    print(\"Error: \\(error?.errorDescription ?? \"\")\")\n}\n```\n\n---\n\n## 10. Package Dependencies\n\nEvery CometChat iOS integration requires:\n\n```ruby\n# Podfile\npod 'CometChatUIKitSwift', '~> 5.1'\n```\n\nThis automatically includes:\n- `CometChatSDK` — Core SDK with types and methods\n- UI components and views\n- Localization resources\n- Asset bundles\n\n### Optional: Calling SDK\n\nFor voice/video calls, add:\n\n```ruby\npod 'CometChatCallsSDK', '~> 4.0'\n```\n\nThe UI Kit automatically detects and enables calling features when the Calls SDK is present.","tags":["cometchat","ios","core","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-ios-core","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-core","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 (23,233 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:52.953Z","embedding":null,"createdAt":"2026-05-07T13:05:12.719Z","updatedAt":"2026-05-18T19:04:52.953Z","lastSeenAt":"2026-05-18T19:04:52.953Z","tsv":"'-123':1143,1182 '-2':349 '/cometchat/chat-sdk-ios':579,635 '/cometchat/cometchat-calls-sdk-ios':588,612,643 '/cometchat/cometchat-sample-app-ios':651 '/cometchat/cometchat-uikit-ios':306,570,599,624 '/dev/null':157,165 '0':76 '1':74,291,490,944,971,1780,2068 '10':2259,2398 '100':1919 '13.0':200,452 '15':473 '2':156,164,296,495,654,2090 '20':1948 '3':301,500,918,2112 '3.1':1095 '4':307,369,505,1284,2138 '4.0':2439 '4.0.0':614 '5':320,511,949,1407,2162 '5.0.0':601 '5.1':208,460,2410 '6':1824,2179 '7':1941,2198 '8':2052,2219 '9':2237,2283 'activ':1259 'ad':2027 'ad-hoc':2026 'add':262,298,308,317,445,520,553,560,590,603,1313,1322,2435 'addit':1134 'alongsid':15 'alreadi':1247,1251 'alway':13,2150 'anoth':2185 'anti':49,2054 'anti-pattern':48,2053 'api':1279,1429,2003 'api/auth':1282 'apistatus':1203 'app':94,326,498,648,692,814,837,868,871,880,885,932,1272,1275,1300,1319,1330,1385,1388,1405,1435,1749,2039,2082,2207 'appdeleg':812,822,2080 'appear':323 'appid':690,752,775,776,835,883,1298,1345,1498,1520,1521,1747 'applic':826,827 'appropri':57 'arab':1965 'arriv':150 'ask':430 'asset':2427 'assum':2100 'async':2149 'asynchron':670 'attempt':142 'audio':2337 'auth':697,841,889,1261,1263,1268,1306,1334,1391,1394,1633,1753,2116,2122,2134 'authkey':695,754,778,779,839,887,1304,1352,1500,1523,1524,1751 'authtoken':1004,1014,1015,1638,1657,1658 'automat':528,1924,1957,2412,2443 'avatar':1887,1908 'avoid':2232 'b':251 'backend':1011 'background':1850 'base':2319 'basemessag':2318,2326 'bash':152,193,339,464 'behavior':2089 'block':2240 'bodi':913 'bool':761,833,1506,1697 'box':1953 'break':999,1039,1094 'bug':2067 'build':141,488,503,714,784,1529 'builder':682 'bundl':1990,2049,2428 'bundle.main.object':1346,1353,1360 'call':581,585,604,639,646,2071,2086,2182,2195,2212,2430,2434,2447,2451 'callback':953,1453,1487,2246,2258 'case':792,801,849,855,897,903,958,976,989,1020,1029,1078,1084,1148,1156,1213,1220,1540,1553,1605,1618,1666,1679,1719,1730,1900 'cat':195 'caus':2065,2087,2110,2176,2196 'cd':194 'cgfloat':1892 'chain':2051 'chat':631,987,1794,2297,2305 'check':2190,2272 'chines':1966,1968 'circl':1898 'circular':1912 'class':734,821,1466,2320 'clean':279,1428 'clear':2215 'cli':280 'closur':1169,1173,2236 'cocoapod':187,241,435 'code':58,117,1119,1164,1235,1236,1341,2120,2282 'color':1846,1851,1858,1931 'come':933 'cometchat':2,8,29,38,162,343,563,571,580,656,678,852,860,900,908,931,942,947,969,1098,1367,1384,1390,1396,1404,1580,1649,1778,1829,1923,1943,2094,2217,2225,2245,2265,2275,2402 'cometchat-ios-compon':2274 'cometchat-ios-cor':1 'cometchat-uid':941,946,968,1777 'cometchat-uikit-io':342 'cometchat.getgroup':2380 'cometchat.getloggedinuser':1070 'cometchat.getuser':1179,2357 'cometchatappid':1328,1348,1403 'cometchatauthkey':1332,1355 'cometchatavatar.style.backgroundcolor':1914 'cometchatavatar.style.cornerradius':1916 'cometchatcallssdk':2438 'cometchatconst':1295 'cometchatconversations.style.backgroundcolor':1878 'cometchatconversations.style.titlecolor':1880 'cometchatcornerstyl':1895,1917 'cometchatexcept':1100,1109,1112,1194,1226,1439,1449,1507,1561,1574,1643,1698 'cometchatloc':1987 'cometchatlocalize.set':2009,2014,2022 'cometchatmanag':735,739,1437,1467,1473,2169 'cometchatmanager.shared.initialize':834,882,1746 'cometchatmanager.shared.login':1775 'cometchatmanager.shared.logout':1806,2213 'cometchatmessagelist.style.backgroundcolor':1885 'cometchatregion':1336,1362 'cometchatsdk':137,732,1464,2290,2293,2414 'cometchatthem':1834 'cometchattheme.backgroundcolor01':1852 'cometchattheme.backgroundcolor02':1854 'cometchattheme.primarycolor':1847,1933 'cometchattheme.textcolorprimary':1859 'cometchattheme.textcolorsecondary':1861 'cometchatuikit':785 'cometchatuikit.create':1206 'cometchatuikit.getloggedinuser':1059,1549 'cometchatuikit.init':1530,2072 'cometchatuikit.login':923,966,1003,1013,1140,1595,1656 'cometchatuikit.logout':1071,1709 'cometchatuikitswift':129,207,322,346,392,459,685,730,819,876,1462,2409 'common':189,1233,2287 'compil':417 'complet':367,401,673,758,767,798,807,1055,1436,1504,1512,1550,1557,1571,1583,1591,1615,1622,1627,1640,1652,1676,1683,1688,1695,1705,1727,1734,1739,2098,2143,2153 'compon':72,630,665,1864,1868,2099,2263,2268,2277,2422 'component-level':1863 'concurr':2193 'config':219,539 'config.build':220,540 'configur':1828,1837 'confirm':78,321 'conform':1442 'constant':1289 'constants.swift':1293,1314 'content':333 'contentview':917 'continu':184 'control':680,2227 'convers':1875,2310,2316,2317 'core':4,636,2415 'cornerradius':1889,1918 'correct':1136 'crash':2111 'creat':84,89,938,1218,1379,2165 'credenti':1285,1368 'current':1042 'currentus':1058,1069,1073,1484,1548,1590,1610,1671,1703,1722,2191 'currentuser.name':1064 'custom':2032,2343 'custommessag':2342,2347,2348 'cycl':2234 'dark':1920,1926,1938 'data':2344 'dead':148 'dealloc':2231 'debug.xcconfig':1380,1383 'default':316,998,1038,1093,1626,1687,1738 'dep':175,356 'depend':80,124,136,271,300,562,594,2400 'dependency-manag':123 'descript':619,1130,1237 'detail':1135 'detect':151,1958,2444 'dev':701 'develop':920,1291,1566 'devic':1961 'didfinishlaunchingwithopt':829 'didn':365 'dimens':1909 'direct':1450 'disabl':468,480 'dispatchqueue.main.async':1537,1602,1663,1716 'doesn':361,1243 'doubl':726 'double-init':725 'dutch':1970 'e':341 'easiest':190 'edit':283 'either':398 'els':766,1365,1511,1578,1647,1704,1765,1796,1815 'embed':332 'empti':170 'enabl':222,513,542,711,2446 'end':209,227,228,229,461,547,548,549 'english':1971,2011 'entir':145 'entiti':2350 'enum':1204,1899,2012 'environ':2128 'err':1121,1238,1246,1254,1262,1270,1277 'error':747,762,804,806,809,858,863,906,911,992,1032,1087,1096,1102,1118,1137,1159,1161,1166,1175,1190,1192,1197,1198,1201,1223,1224,1231,1234,1446,1457,1556,1559,1621,1624,1682,1685,1733,1736,1758,1768,1769,1782,1799,1800,1808,1818,1819,2197,2369,2372,2373,2392,2395,2396 'error.details':1131 'error.errorcode':1116,1165 'error.errordescription':996,1036,1091,1125,1162,1232,1773,1804,1823 'errordescript':1105,1199,2374,2397 'escap':759,1505,1572,1641,1696 'establish':121 'eu':707 'everi':28,929,2401 'exact':660 'exampl':1743 'exist':82,1245 'explicit':374 'export':2266 'extra':423 'fail':862,910,995,1035,1090,1772,1803,1822 'failur':802,808,856,904,1554 'fals':743,1480,1558,1735,1740 'fatalerror':1366 'featur':2448 'file':92,285,297,396,494,559,1290,1375,2042,2132,2338 'final':733,1465 'finish':2109 'first':20,67,77,140,2192 'five':935 'forget':2201 'forinfodictionarykey':1347,1354,1361 'found':1124,1241,1266,1370 'foundat':25,1460 'fr':2016 'framework':202,329,454 'french':1972 'fresh':88,171 'freshly-cr':87 'front':434 'full':436 'fulli':674 'func':750,825,1496,1567,1636,1693 'german':1973 'get':1040,2349,2352,2375 'github':615 'github.com':305,569,578,587,598,611,623,634,642,650 'github.com/cometchat/chat-sdk-ios':577,633 'github.com/cometchat/cometchat-calls-sdk-ios':586,610,641 'github.com/cometchat/cometchat-sample-app-ios':649 'github.com/cometchat/cometchat-uikit-ios':304,568,597,622 'gitignor':1316 'global':1826 'go':501 'grep':158,340,351,406 'group':2302,2306,2308,2309,2314,2377,2383,2385,2388,2389 'group-guid':2382 'guard':764,1343,1509,1576,1645,1700 'gui':97,268 'guid':2379,2381,2384 'half':1906 'handl':1097,1138,1167,1421,2151,2203 'handler':2144 'happen':717,2077 'hard':380 'hardcod':2115 'head':348 'heavi':2255 'hindi':1974 'hit':131 'hoc':2028 'human':1128 'human-read':1127 'hungarian':1975 'id':693,838,886,1273,1276,1301,1331,1386,1389,1406,1750 'ignor':2141,2222 'imag':2335 'implement':653 'import':128,391,467,684,729,731,816,818,873,875,950,1103,1312,1438,1459,1461,1463,2292 'includ':246,566,2413 'inconsist':2178 'indic':713 'info.plist':1321,1326,1372,1401 'init':715,727,749,810,866,881,1053,1493,1771,2075,2083,2085,2097,2108,2145 'initi':42,655,659,668,751,853,861,901,909,1422,1495,1497,1582,1651,1745,1763,2104 'initializationerror':746 'instal':75,211,213,232,235,400,466,477,531,533 'installer.pods_project.targets.each':214,534 'instanc':2167 'instead':59 'instruct':289 'integr':34,116,146,415,2404 'invalid':1267,1271,1278 'invent':2262 'io':3,9,30,41,199,345,451,1415,1830,1944,2276,2403 'isiniti':742,765,1479,1510,1545,1577,1646 'japanes':1976 'keep':310 'key':698,842,890,1280,1283,1307,1323,1335,1392,1395,1754,2023,2029,2117,2123 'kit':11,32,565,621,1832,1946,1995,2044,2442 'know':1052,2155 'korean':1977 'l':159 'label':1881 'land':338 'languag':1949,1955,1964 'larger':1904 'launchopt':830 'let':686,737,771,794,803,857,905,978,991,1022,1031,1057,1068,1086,1150,1158,1215,1222,1297,1303,1309,1344,1351,1358,1471,1516,1542,1555,1588,1607,1620,1668,1681,1701,1732,1767,1785,1798,1817,2299,2307,2315,2324,2331,2339,2346 'level':1865 'librari':330 'like':1120 'list':1876,1883 'lithuanian':1978 'live':272 'load':14 'local':1942,1986,2006,2010,2015,2425 'locale-on':2005 'localizable.strings':2041 'localizeddescript':1108 'log':981,1025,1044,1061,1081,1153,1248,1252,1256,1789,1813,2210 'logged-in':1043 'login':43,919,952,994,1034,1423,1563,1568,1631,1774,1802,2147,2183,2186,2194 'loginwithtoken':1637 'logout':1065,1089,1692,1694,1805,1821,2204 'look':1913 'lookup':1998,2050 'lproj':1997 'ls':153 'main':820,877,2242,2250 'major':314 'malay':1979 'manag':45,107,125,176,254,552,722,1286,1409,1419,2175,2224 'manifest':81 'mark':1468,1474,1486,1494,1562,1630,1691 'match':353,409 'mechan':126 'mediamessag':2334,2340,2341 'memori':2223 'messag':637,1882,2323,2325,2330,2345 'method':2420 'might':1176 'mode':702,921,1001,1921,1927 'modul':135 'mount':676 'multipl':2073,2084,2166,2174 'must':120,261,479,657,672,716 'name':1188,2264,2271,2367,2390 'need':575 'neither':383 'new':93,930 'newus':1208 'next':313 'nil':1514,1552,1584,1585,1593,1617,1623,1628,1629,1653,1654,1678,1684,1689,1690,1707,1723,1726,1729,1741 'non':1228 'non-opt':1227 'obtain':1008 'one':85,178,2064 'onerror':957,990,1030,1085,1157,1172,1189,1221,1619,1680,1731,2368,2391 'online/offline':712 'onloginstatechang':1489,1613,1674,1725 'open':292,491 'option':185,250,384,442,602,1178,1195,1229,2429 'otherwis':127 'outcom':428 'overrid':2030,2035 'packag':106,253,264,299,309,318,337,551,555,561,595,608,617,2399 'package.swift':102,155,592 'past':302 'pattern':46,50,1410,1413,2055,2173 'pick':177 'place':387 'placement':16,70 'platform':198,450 'pod':197,206,230,231,234,248,399,458,465,476,2408,2437 'podfil':100,154,196,256,448,524,2407 'portugues':1980 'post':210,530 'pre':937 'pre-creat':936 'present':2454 'prevent':724 'primari':1845 'print':287,851,859,899,907,980,993,1024,1033,1060,1080,1088,1152,1160,1163,1185,1196,1217,1230,1579,1648,1762,1770,1788,1801,1812,1820,2364,2371,2387,2394 'privat':740,744,748,1476,1481,1492 'proceed':985,2161 'produc':413 'product':1000,1318,1378,1635,2119,2137 'progress':2189 'project':56,91,173,249,486 'project-appropri':55 'proper':2230 'properti':1106,1110,1115,1873 'protocol':1447 'provid':1426 'public':2002 'purpos':21 'raw':2017 'read':18,64,1338,2045 'readabl':1129 'readi':626 'ready-to-us':625 'real':2066 'recommend':1376,1412 'ref':108 'refer':437,1399,2286 'region':704,756,781,782,843,891,1310,1359,1397,1502,1526,1527,1755 'release.xcconfig':1382 'reli':61 'repositori':616,618 'repositoryurl':161 'repres':2295,2303 'requir':699,2405 'resolv':134 'resourc':2426 'rest':1432 'result':760,788,791,845,848,893,896,963,972,975,1016,1019,1074,1077,1144,1147,1205,1209,1212,1455,1535,1539,1600,1604,1661,1665,1714,1718 'retain':2233 'return':169,352,408,770,864,1515,1586,1594,1655,1708 'rewir':242 'rubi':449,529,2406,2436 'rule':6 'run':463,475 'runtim':2000 'russian':1981 'safe':286,2159 'sampl':647,652 'sandbox':225,471,483,510,516,545 'scene':915 'script':192,224,470,482,509,515,544 'sdk':567,572,582,605,632,638,640,2102,2284,2416,2431,2452 'search':506 'secret':2126 'select':496 'self':1534,1544,1547,1599,1609,1612,1660,1670,1673,1713,1721,1724 'self.initializationerror':805 'self.isinitialized':796 'separ':576 'session':1260,2218 'set':180,221,489,504,512,541,689,694,703,774,777,780,1477,1482,1519,1522,1525,1844,1849,1856,1962,1985 'setup':424 'share':5,738,1472 'ship':98 'show':1793,1840,2093,2105 'simplifi':1967 'singleton':721,1418,1469,2172 'skill':17,26,66,73,2278 'skill-cometchat-ios-core' 'skip':410,441 'source-cometchat' 'spanish':1982 'specif':2033,2058,2267,2270 'spm':270,355,405 'standard':962,2048 'state':1424,1475,2177 'static':736,1296,1302,1308,1470,1871 'step':368,412 'stop':376,381 'string':753,755,757,1117,1126,1132,1350,1357,1364,1499,1501,1503,1570,1639,2018,2034 'struct':869,878,1294 'style':1836,1866,1872,1877,1884,1888 'subclass':1991 'subscribepresenceforallus':710,783,1528 'success':402,768,793,795,797,799,800,850,854,898,902,955,977,1021,1079,1083,1149,1214,1541,1543,1546,1551,1606,1667,1720,1757,1761,1764,1807,1811 'support':1922,1925,1947,1963 'surfac':372 'swap':1993 'swedish':1983 'swift':105,252,395,550,593,683,728,815,872,960,965,1012,1047,1066,1111,1139,1170,1292,1342,1444,1458,1744,1843,1874,1932,2008,2291,2351 'swiftui':870,874 'switch':790,847,895,974,1018,1076,1146,1211,1538,1603,1664,1717 'synchron':1048 'system':1930 'systembackground':1879,1886 'systemgray5':1915 'target':203,216,327,455,499,536 'target.build_configurations.each':217,537 'teach':36 'templat':63 'test':927,939 'text':1857,2329 'textmessag':2327,2332,2333 'theme':1825,1827 'thing':2059 'thread':2243,2251 'three':168 'time':2074 'token':1007,1264,1269,1634,2135 'tool':281 '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' 'touch':112 'tradit':1969 'traitcollect':1935 'traitcollection.userinterfacestyle':1937 'true':769,865,1513,1706,1728 'turkish':1984 'type':964,2285,2288,2418 'ui':10,31,564,620,629,664,988,1795,1831,1842,1945,2095,2106,2421,2441 'uiapplic':828 'uiapplication.launchoptionskey':831 'uiapplicationdeleg':824 'uicolor':1934 'uicolor.blue':1940 'uicolor.label':1860 'uicolor.secondarylabel':1862 'uicolor.secondarysystembackground':1855 'uicolor.systembackground':1853 'uicolor.systemblue':1848,1939 'uid':924,928,943,948,967,970,1122,1141,1180,1239,1565,1569,1596,1597,1776,1779,2356,2358,2361 'uikit':344,813,817 'uikitset':681,687,688,772,773,786,787,1517,1518,1531,1532 'uirespond':823 'unabl':132 'undefin':2088 'unknown':997,1037,1092,1200,1625,1686,1737 'up-front':432 'url':303,556,596,609 'us':705,706,844,892,1311,1337,1398,1756 'usag':1742 'use':201,453,628,667,719,922,954,1002,1049,1099,1104,1287,1320,1373,1448,1833,1901,1929,2127,2133,2170 'user':223,260,364,421,469,481,508,514,543,940,979,1023,1046,1072,1142,1151,1181,1183,1186,1187,1207,1216,1242,1250,1485,1490,1573,1589,1592,1608,1611,1614,1616,1642,1669,1672,1675,1677,1702,1710,1711,1781,1786,1787,2209,2294,2298,2300,2301,2312,2354,2360,2362,2365,2366 'user-uid':2359 'user.name':984,1028,1155,1219,1792 'v5':12,33 'valu':1903,2013,2024 'var':741,745,912,1478,1483,1488 'variabl':2129 'verbatim':290 'verifi':335 'version':315 'via':265 'video':645,2336 'view':679,2226,2424 'voic':644 'voice/video':584,607,2433 'void':763,1491,1508,1575,1644,1699 'weak':1533,1598,1659,1712 'windowgroup':916 'work':39,236,425,2256 'workspac':244 'wors':427 'wrap':2311 'write':54,390,2280 'wrong':1274,1281 'xcconfig':1374,2131 'xcode':90,172,266,295,371,472,558 'xcodeproj':240,293 'xcodeproj/project.pbxproj':110,163,274,347 'xcremoteswiftpackagerefer':160 'xcworkspac':258,493 'xml':1327,1402 'yourapp':456,879 'yourapp.xcworkspace':238 'yourapptargetnam':204","prices":[{"id":"cf7b4f06-bb84-492c-9017-375744c2bf51","listingId":"c0e25156-8a1a-4bc5-97a1-ded35f94f096","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:12.719Z"}],"sources":[{"listingId":"c0e25156-8a1a-4bc5-97a1-ded35f94f096","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-ios-core","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-ios-core","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:12.719Z","lastSeenAt":"2026-05-18T19:04:52.953Z"}],"details":{"listingId":"c0e25156-8a1a-4bc5-97a1-ded35f94f096","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-ios-core","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":"4c6859278f62e0c46d47c6a108635d96c631c384","skill_md_path":"skills/cometchat-ios-core/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-ios-core"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-ios-core","license":"MIT","description":"Shared rules for CometChat iOS UI Kit v5. Always loaded alongside placement skills. Read this first.","compatibility":"iOS 13+; Swift 5.0+; CometChatUIKitSwift ^5; CometChatSDK ^4"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-ios-core"},"updatedAt":"2026-05-18T19:04:52.953Z"}}