Ground truth:
@cometchat/chat-uikit-react-native@5+ catalogrn-v5.json. Docs:/ui-kit/react-native/react-native-cli-integration·react-native-conversation·react-native-tab-based-chat.
Companion skills (read first)
cometchat-react-native-core— install, provider chain, init→login→render. Assumed, not repeated here.cometchat-react-native-expo-patterns— the Expo equivalent. Use that one for an Expo project.
Use this skill when
- the project has real
ios/andandroid/directories and noexpokey inapp.json - "add chat to my React Native CLI app" · "Android build fails after installing CometChat"
Prerequisites & install
bashnpm install @cometchat/chat-uikit-react-native@5 @cometchat/chat-sdk-react-native@4 npm install @react-native-clipboard/clipboard \ react-native-svg react-native-video react-native-localize react-native-gesture-handler \ react-native-safe-area-context @react-native-async-storage/async-storage@^2.1.2 dayjs cd ios && pod install && cd ..
You own ios/ and android/, so native config is edited directly — the opposite of Expo, where
those directories are generated and hand-edits get overwritten.
The four native steps that are not optional
1. react-native-gesture-handler must be the FIRST import of your entry file
jsimport 'react-native-gesture-handler'; // …every other import after this
Not at the top of a screen — the very top of index.js, before anything else. Getting this wrong
often works in debug and crashes in release, which is the worst possible failure shape: it passes
local testing and breaks for users.
2. iOS Podfile needs modular headers for two transitive pods
@cometchat/chat-uikit-react-native is a Swift pod that depends on SPTPersistentCache
and DVAssetLoaderDelegate, neither of which defines a module. On a static-library build —
the React Native default — pod install fails outright:
The Swift pod
react-native-cometchat-ui-kitdepends uponSPTPersistentCacheandDVAssetLoaderDelegate, which do not define modules.
Add these inside your target in ios/Podfile, then re-run pod install:
rubytarget 'YourApp' do pod 'SPTPersistentCache', :modular_headers => true pod 'DVAssetLoaderDelegate', :modular_headers => true # … end
Both official CometChat sample apps carry exactly these two lines. The integration docs do
not mention them (RN-G14), so a first pod install fails with an error that names two
pods the developer has never heard of.
3. Android permissions in the manifest
android/app/src/main/AndroidManifest.xml — INTERNET at minimum; the camera/audio set only if you
add calling. Fetch the exact list from the integration page rather than copying a partial set.
Calling on bare RN
bashnpm install @cometchat/calls-sdk-react-native@5 # 6 REQUIRED peer deps — the calls SDK's declared peerDependencies. Pinned; do NOT float them. npm install @react-native-async-storage/async-storage@^2.1.2 react-native-background-timer@^2.4.1 \ react-native-performance@^5.1.2 react-native-svg@^15.12.0 react-native-url-polyfill@2.0.0 \ react-native-webrtc@124.0.7 cd ios && pod install && cd ..
⚠️ react-native-url-polyfill + react-native-performance are bundle-critical (the UIKit
module-scope require()s the calls SDK, so Metro resolves its peers even in a chat-only build). Keep
react-native-performance on 5.x (a floated ^6 breaks later npm install with ERESOLVE).
@react-native-community/netinfo / react-native-callstats are NOT declared peers — do not add them.
iOS permissions go in ios/<YourApp>/Info.plist:
xml<key>NSCameraUsageDescription</key> <string>Camera access for video calls</string> <key>NSMicrophoneUsageDescription</key> <string>Microphone access for voice/video calls</string>
Simulators cannot capture camera or microphone — verify calls on a real device.
After any native change — rebuild, don't reload
Metro reload only refreshes JavaScript. A new native module, a Gradle edit or a plist change needs a
full rebuild (npx react-native run-ios / run-android). "I installed it and nothing changed" is
almost always a missed rebuild.
What is the same as Expo
Everything above the native layer: providers, init → login → render, components, theming,
navigation. Only install and native config differ.
Common pitfalls
gesture-handlerimported late — works in debug, crashes in release.- Missing the Podfile modular-headers lines —
pod installfails, naming two unfamiliar transitive pods. - Skipping
pod installafter adding a package — iOS fails to link. - Reloading instead of rebuilding after a native change.
- Copying Expo's
app.jsonpermission block into a bare app — it does nothing there.
Verify it works
index.jsstarts with the gesture-handler import.- iOS and Android both build clean from scratch.
npm run verify:fences:rn-v5is green.- On device: chat renders, gestures respond, the composer survives the keyboard. Test a release build too — the gesture-handler ordering bug only shows there.

