{"id":"65125bca-cdf9-4fa7-acaf-a27043c0c824","shortId":"RFjDkm","kind":"skill","title":"cometchat-flutter-v5-production","tagline":"Use when preparing a CometChat Flutter UIKit v5 app for production. Covers auth tokens, ProGuard, environment config, security hardening.","description":"# CometChat Flutter UIKit v5 — Production\n\nHardening a CometChat Flutter app for production deployment.\n\n## Auth Tokens vs Auth Key\n\n**Development:** `CometChatUIKit.login(uid)` uses `authKey` from `UIKitSettingsBuilder`. This is convenient but insecure — the authKey is embedded in the app binary.\n\n**Production:** Use server-minted auth tokens via `CometChatUIKit.loginWithAuthToken(authToken)`:\n\n```dart\n// 1. Your backend generates an auth token via CometChat REST API\n// POST https://{appId}.api-{region}.cometchat.io/v3/users/{uid}/auth_tokens\n// Header: apiKey: YOUR_API_KEY\n\n// 2. Your Flutter app receives the token and logs in\nCometChatUIKit.loginWithAuthToken(authToken,\n  onSuccess: (user) { ... },\n  onError: (e) { ... },\n);\n```\n\nThis keeps the API key on your server, never in the client.\n\n## Environment Configuration\n\nStore credentials outside source code:\n\n```dart\nclass AppCredentials {\n  static String _appId = '';\n  static String _authKey = '';\n  static String _region = '';\n\n  // Load from SharedPreferences, environment, or remote config\n  static String get appId => _appId.isEmpty\n      ? SharedPreferencesClass.getString('appId')\n      : _appId;\n\n  static Future<void> setAppId(String value) async {\n    await SharedPreferencesClass.setString('appId', value);\n    _appId = value;\n  }\n}\n```\n\nThe master app supports QR code scanning to load credentials dynamically (`CometChatQRScreen`).\n\n## Android Build Requirements\n\n### gradle.properties\n\n```properties\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n```\n\n### minSdk 26\n\n```groovy\n// android/app/build.gradle\ndefaultConfig {\n    minSdk 26  // Required by cometchat_calls_sdk\n}\n```\n\n### ProGuard / R8 Keep Rules\n\nCreate `android/app/proguard-rules.pro`:\n\n```\n-keep class com.cometchat.** { *; }\n-keep interface com.cometchat.** { *; }\n-dontwarn com.cometchat.calls.**\n```\n\nReference in `build.gradle`:\n\n```groovy\nbuildTypes {\n    release {\n        minifyEnabled true\n        shrinkResources true\n        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n}\n```\n\n### Signing\n\n```groovy\nsigningConfigs {\n    release {\n        storeFile file('your_keystore.jks')\n        storePassword 'STORE_PASSWORD'\n        keyAlias 'KEY_ALIAS'\n        keyPassword 'KEY_PASSWORD'\n    }\n}\n```\n\n## iOS Build Requirements\n\n### Info.plist Permissions\n\n```xml\n<key>NSCameraUsageDescription</key>\n<string>Camera access for video calls and photo sharing</string>\n<key>NSMicrophoneUsageDescription</key>\n<string>Microphone access for voice and video calls</string>\n<key>NSPhotoLibraryUsageDescription</key>\n<string>Photo library access for sharing images</string>\n```\n\n### Background Modes (for VoIP)\n\nEnable in Xcode: Background Modes → Voice over IP, Remote notifications, Background fetch.\n\n### Podfile\n\nEnsure minimum iOS deployment target matches CometChat requirements.\n\n## Firebase Setup\n\n```dart\n// In main(), before runApp:\nawait Firebase.initializeApp(\n  options: DefaultFirebaseOptions.currentPlatform,\n);\n```\n\n### Crashlytics\n\n```dart\nFlutterError.onError = (errorDetails) {\n  FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);\n};\nPlatformDispatcher.instance.onError = (error, stack) {\n  FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);\n  return true;\n};\n```\n\n## Push Notification Provider IDs\n\nConfigure provider IDs for FCM and APNs in the CometChat dashboard:\n\n```dart\nstatic String get fcmProviderId => 'your-fcm-provider-id';\nstatic String get apnProviderId => 'your-apn-provider-id';\n```\n\nThese must match what's configured in the CometChat dashboard under Notifications → Push Notifications.\n\n## Demo Meta Info\n\nFor internal tracking (optional):\n\n```dart\nCometChat.setDemoMetaInfo(jsonObject: {\n  \"name\": \"flutter-sample-app\",\n  \"type\": \"sample\",\n  \"version\": \"5.2.11\",\n  \"platform\": \"flutter\",\n});\n```\n\n## Logout Flow\n\n```dart\n// 1. Unregister push tokens\nPNRegistry.unregisterPNService();\n\n// 2. Sign out from Firebase/Google (if applicable)\nawait FirebaseAuth.instance.signOut();\nawait GoogleSignIn().signOut();\n\n// 3. Logout from CometChat\nawait CometChatUIKit.logout(\n  onSuccess: (_) { /* navigate to login */ },\n  onError: (e) { /* show error */ },\n);\n```\n\n## Checklist — Production\n\n- [ ] Auth tokens minted server-side, not authKey in client\n- [ ] Credentials not hardcoded in source (use SharedPreferences or remote config)\n- [ ] ProGuard rules added for release builds\n- [ ] minSdk 26 set\n- [ ] iOS permissions in Info.plist\n- [ ] Firebase Crashlytics configured\n- [ ] Push notification provider IDs match CometChat dashboard\n- [ ] Logout unregisters push tokens before CometChat logout\n- [ ] Signing config set for release builds","tags":["cometchat","flutter","production","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-flutter-v5-production","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-flutter-v5-production","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 (4,700 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:50.305Z","embedding":null,"createdAt":"2026-05-07T13:05:09.817Z","updatedAt":"2026-05-18T19:04:50.305Z","lastSeenAt":"2026-05-18T19:04:50.305Z","tsv":"'/auth_tokens':93 '/v3/users/':91 '1':74,404 '2':99,409 '26':195,200,464 '3':421 '5.2.11':398 'access':258,267,276 'ad':459 'alia':246 'android':185 'android.enablejetifier':192 'android.useandroidx':190 'android/app/build.gradle':197 'android/app/proguard-rules.pro':211 'api':84,87,97,118 'apikey':95 'apn':342,363 'apnproviderid':360 'app':14,34,61,102,175,394 'appcredenti':136 'appid':86,139,156,159,160,169,171 'appid.isempty':157 'applic':415 'async':166 'auth':18,38,41,68,79,437 'authkey':47,56,142,444 'authtoken':72,110 'await':167,312,416,418,425 'backend':76 'background':280,287,294 'binari':62 'build':186,251,462,492 'build.gradle':222 'buildtyp':224 'call':204,261,272 'camera':257 'checklist':435 'class':135,213 'client':126,446 'code':133,178 'com.cometchat':214,217 'com.cometchat.calls':219 'cometchat':2,10,25,32,82,203,303,345,374,424,478,485 'cometchat-flutter-v5-production':1 'cometchat.io':90 'cometchat.io/v3/users/':89 'cometchat.setdemometainfo':388 'cometchatqrscreen':184 'cometchatuikit.login':44 'cometchatuikit.loginwithauthtoken':71,109 'cometchatuikit.logout':426 'config':22,152,456,488 'configur':128,336,371,472 'conveni':52 'cover':17 'crashlyt':316,471 'creat':210 'credenti':130,182,447 'dart':73,134,307,317,347,387,403 'dashboard':346,375,479 'defaultconfig':198 'defaultfirebaseoptions.currentplatform':315 'demo':380 'deploy':37,300 'develop':43 'dontwarn':218 'dynam':183 'e':114,432 'embed':58 'enabl':284 'ensur':297 'environ':21,127,149 'error':323,326,434 'errordetail':319,321 'fatal':328 'fcm':340,354 'fcmproviderid':351 'fetch':295 'file':239 'firebas':305,470 'firebase.initializeapp':313 'firebase/google':413 'firebaseauth.instance.signout':417 'firebasecrashlytics.instance.recorderror':325 'firebasecrashlytics.instance.recordflutterfatalerror':320 'flow':402 'flutter':3,11,26,33,101,392,400 'flutter-sample-app':391 'fluttererror.onerror':318 'futur':162 'generat':77 'get':155,350,359 'getdefaultproguardfil':231 'googlesignin':419 'gradle.properties':188 'groovi':196,223,235 'hardcod':449 'harden':24,30 'header':94 'id':335,338,356,365,476 'imag':279 'info':382 'info.plist':253,469 'insecur':54 'interfac':216 'intern':384 'io':250,299,466 'ip':291 'jsonobject':389 'keep':116,208,212,215 'key':42,98,119,245,248 'keyalia':244 'keypassword':247 'librari':275 'load':146,181 'log':107 'login':430 'logout':401,422,480,486 'main':309 'master':174 'match':302,368,477 'meta':381 'microphon':266 'minifyen':226 'minimum':298 'minsdk':194,199,463 'mint':67,439 'mode':281,288 'must':367 'name':390 'navig':428 'never':123 'notif':293,333,377,379,474 'nscamerausagedescript':256 'nsmicrophoneusagedescript':265 'nsphotolibraryusagedescript':273 'onerror':113,431 'onsuccess':111,427 'option':314,386 'outsid':131 'password':243,249 'permiss':254,467 'photo':263,274 'platform':399 'platformdispatcher.instance.onerror':322 'pnregistry.unregisterpnservice':408 'podfil':296 'post':85 'prepar':8 'product':5,16,29,36,63,436 'proguard':20,206,457 'proguard-android-optimize.txt':232 'proguard-rules.pro':233 'proguardfil':230 'properti':189 'provid':334,337,355,364,475 'push':332,378,406,473,482 'qr':177 'r8':207 'receiv':103 'refer':220 'region':88,145 'releas':225,237,461,491 'remot':151,292,455 'requir':187,201,252,304 'rest':83 'return':330 'rule':209,458 'runapp':311 'sampl':393,396 'scan':179 'sdk':205 'secur':23 'server':66,122,441 'server-mint':65 'server-sid':440 'set':465,489 'setappid':163 'setup':306 'share':264,278 'sharedprefer':148,453 'sharedpreferencesclass.getstring':158 'sharedpreferencesclass.setstring':168 'show':433 'shrinkresourc':228 'side':442 'sign':234,410,487 'signingconfig':236 'signout':420 'skill' 'skill-cometchat-flutter-v5-production' 'sourc':132,451 'source-cometchat' 'stack':324,327 'static':137,140,143,153,161,348,357 'store':129,242 'storefil':238 'storepassword':241 'string':138,141,144,154,164,349,358 'support':176 'target':301 'token':19,39,69,80,105,407,438,483 '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' 'track':385 'true':191,193,227,229,329,331 'type':395 'uid':45,92 'uikit':12,27 'uikitsettingsbuild':49 'unregist':405,481 'use':6,46,64,452 'user':112 'v5':4,13,28 'valu':165,170,172 'version':397 'via':70,81 'video':260,271 'voic':269,289 'voip':283 'vs':40 'xcode':286 'xml':255 'your-apn-provider-id':361 'your-fcm-provider-id':352 'your_keystore.jks':240","prices":[{"id":"d8d03823-f3da-465f-b6d8-3cc68209bc84","listingId":"65125bca-cdf9-4fa7-acaf-a27043c0c824","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:09.817Z"}],"sources":[{"listingId":"65125bca-cdf9-4fa7-acaf-a27043c0c824","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-flutter-v5-production","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-flutter-v5-production","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:09.817Z","lastSeenAt":"2026-05-18T19:04:50.305Z"}],"details":{"listingId":"65125bca-cdf9-4fa7-acaf-a27043c0c824","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-flutter-v5-production","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":"d91307e210fa8924661452b3bd4949eeb893d61a","skill_md_path":"skills/cometchat-flutter-v5-production/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-flutter-v5-production"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-flutter-v5-production","license":"MIT","description":"Use when preparing a CometChat Flutter UIKit v5 app for production. Covers auth tokens, ProGuard, environment config, security hardening.","compatibility":"cometchat_chat_uikit ^5.2.14; cometchat_calls_uikit ^5.0.15"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-flutter-v5-production"},"updatedAt":"2026-05-18T19:04:50.305Z"}}