@freshworks/react-native-freshdesk-sdk
Version:
React Native wrapper for Freshdesk Android and iOS SDKs
705 lines (530 loc) • 31.9 kB
Markdown
# Troubleshooting
## Diagnostics-first workflow
When Freshdesk integration issues are unclear, run diagnostics before changing code:
```typescript
import FreshdeskSDK from '@freshworks/react-native-freshdesk-sdk';
await FreshdeskSDK.enableDebugLogs(true);
const report = await FreshdeskSDK.runDiagnostics();
console.log(report.prettyPrinted);
```
Process checks in order: any `fail` first, then `warn`, then `skipped`. Apply each check's
`fixHint` verbatim. Re-run diagnostics after every fix until `overallStatus` is `pass` and
the symptom is resolved.
On **iOS**, diagnostics cover config, network, remote config, JWT, push, widget, and runtime
checks (requires FreshdeskSDK 1.3+). On **Android**, the wrapper returns
integration checks plus `runtime.diagnostics: skipped` — use `debugMode: true` on
`initialize()` and inspect Logcat for native SDK logs.
For AI-assisted integration and debugging, copy the **AI Integration Kit** from
`node_modules/@freshworks/react-native-freshdesk-sdk/ai-integration-kit/` into your app repo.
See [ai-integration-kit/README.md](../../ai-integration-kit/README.md).
### Android `openSupport()` Spinner / Blank Widget
**Problem:** Diagnostics show `runtime.sdkInitialized: pass`, but the widget opens with an endless
loading spinner or blank content.
**Common causes:**
1. **Host missing scheme** — Host was `yourcompany.freshdesk.com` instead of
`https://yourcompany.freshdesk.com`. The SDK auto-prefixes `https://` from wrapper **1.2.2+**;
on older versions, update `.env` manually.
2. **Double initialization on Android** — Native `FreshdeskSDK.initialize()` in
`MainApplication.onCreate()` **and** JS `FreshdeskSDK.initialize()` conflict. Diagnostics may
show `runtime.doubleInit: warn`.
3. **JWT enforced but no token** — User state stays `jwtNotPresent`; widget cannot load content.
**Solutions:**
1. Prefer `FRESHDESK_HOST=https://yourcompany.freshdesk.com` in `.env` (bare domains also work on 1.2.2+).
2. **Remove** native init from `MainApplication.onCreate()`. Use JS init for in-app support. For
headless FCM only, initialize natively inside `FirebaseMessagingService` (see sample app).
3. Pass a valid `jwt` at init when the widget enforces JWT.
### iOS `pod install` Fails — `native-versions.json` Not Found
**Problem:**
```text
No such file or directory @ rb_sysopen - .../native-versions.json
```
**Cause:** Published npm tarball before **1.2.2** omitted `native-versions.json`, which the
podspec reads for the iOS SPM pin.
**Solution:** Upgrade to `@freshworks/react-native-freshdesk-sdk@1.2.2` or later, then
`cd ios && pod install`.
## Common Issues
### "Native module not found" Error
**Problem:** The app throws "Freshdesk native module not found" error.
**Solutions:**
1. Ensure the library is installed:
```bash
npm install @freshworks/react-native-freshdesk-sdk
```
2. iOS - Reinstall pods:
```bash
cd ios && pod install
```
3. Clean and rebuild:
- iOS: `rm -rf ios/build ios/Pods && cd ios && pod install`
- Android: `cd android && ./gradlew clean`
4. Restart the Metro bundler and rebuild the app.
### App Shows "Could not connect to development server"
**Problem:** The app builds and installs, then shows a red error screen with:
```
Could not connect to development server.
URL: http://localhost:8081/index.bundle?platform=android...
java.net.ConnectException: Failed to connect to localhost/127.0.0.1:8081 ... ECONNREFUSED
```
**Cause:** This is a runtime (not build) issue — the native app installed fine, but it can't
reach the Metro JS bundler. Either Metro isn't running on port 8081, or the device can't route
`localhost:8081` to your machine.
**Solutions:**
1. Start Metro and leave it running in its own terminal:
```bash
cd sample_app && npm start
```
`npm run android` only builds/installs the app; it expects Metro to be running separately.
2. For a USB-connected Android device/emulator, forward the port so `localhost` resolves to your
machine:
```bash
adb reverse tcp:8081 tcp:8081
```
Confirm the device is attached first with `adb devices`.
3. For a physical device on the same Wi-Fi, set **Dev Settings → Debug server host & port** to
your machine's IP and port (e.g. `10.0.1.5:8081`).
4. Once Metro serves the bundle (`BUNDLE ./index.js ... 100.0%`), reload the app: press `r` in the
Metro terminal, or shake the device and tap **Reload**.
**Problem:** `pod install` fails, or the app fails to compile/link against the Freshdesk SDK.
**Solutions (2.0.0+):**
1. Ensure your app's `Podfile` uses `platform :ios, '15.0'`. The native SDK
requires iOS 15.0; a lower deployment target causes a CocoaPods
"deployment target" error.
2. Nothing else Freshdesk-specific should be needed — the native SDK is a
vendored, statically-linked xcframework, no `use_frameworks!`/SPM
required. If you see linker errors or `no such module 'Expo'`, that's
almost always leftover `~1.4.x` Podfile lines — see
[iOS Linkage / Expo](#ios-linkage--expo-no-such-module-expo-mixed-staticdynamic-frameworks)
below.
3. Ensure CocoaPods is recent:
```bash
pod --version # 1.12+
```
4. Clean and reinstall:
```bash
rm -rf ios/build ios/Pods ios/Podfile.lock
rm -rf ~/Library/Developer/Xcode/DerivedData
cd ios && pod install
```
> **Still on `~1.4.x`?** That version consumed the native iOS SDK as a
> **Swift Package** via the podspec's `spm_dependency` helper (RN 0.75+,
> default), pinned in `native-versions.json`, requiring
> `use_frameworks! :linkage => :dynamic` (or `FRESHDESK_IOS_USE_VENDORED=1`
> as an opt-out). If you're on RN 0.75+ with that SPM path and see
> resolution errors, verify network access to
> `github.com/freshworks-oss/freshdesk-ios-sdk` and that the pinned version
> tag exists — or upgrade to 2.0.0+, which removes the SPM path (and this
> whole class of problem) entirely.
### iOS Linkage / Expo (`no such module 'Expo'`, mixed static/dynamic frameworks)
**Applies to 2.0.0+.** The native SDK now ships as a vendored
`FreshdeskSDK.xcframework` and the podspec builds it as a **static** framework.
`use_frameworks!` / `cocoapods-spm` / `spm_dependency` are **no longer required**
and their presence (left over from a 1.4.x integration) is now the usual cause of
iOS build breakage.
**`no such module 'Expo'`** — caused by forcing dynamic-framework linkage in an
Expo app. Fix:
1. Remove `use_frameworks!` and the Freshdesk SPM lines from the `Podfile` /
config plugin.
2. `npx expo prebuild --clean && cd ios && pod install`
Expo returns to its default static linkage and the error is gone.
**Bare React Native** — remove from the `Podfile` / `Gemfile` the lines that only
existed for the 1.4.x SPM path:
| Remove | Why |
|---|---|
| `use_frameworks! :linkage => :dynamic` | not required by Freshdesk 2.0.0 |
| `gem "cocoapods-spm"` / `plugin 'cocoapods-spm'` | SDK no longer uses `spm_dependency` |
| `spm_dependency` lines added for Freshdesk | same |
| `ENV['FRESHDESK_IOS_USE_VENDORED'] = '1'` | vendored is the only path; the env gate was removed |
| `post_install` overrides added for mixed static/dynamic linkage | cause removed |
Then `cd ios && rm -rf Pods Podfile.lock && pod install`.
**If you still need `use_frameworks!`** for other SDKs (Firebase, Google Maps,
etc.), keep it but prefer `:linkage => :static`. The Freshdesk podspec sets
`s.static_framework = true`, so a static build is the expected configuration.
### iOS Build Fails with `'FreshdeskReactNative-Swift.h' file not found`
**(1.4.x only — see the 2.0.0+ section above for current guidance)**
**Problem:** The build fails compiling `FreshdeskNativeModule.mm` with
`'FreshdeskReactNative-Swift.h' file not found`, even though the Swift sources compile fine.
**Cause:** With `use_frameworks! :linkage => :dynamic`, the module builds as a framework and the
auto-generated Swift→ObjC header lives **inside** it, so it must be imported as
`<FreshdeskReactNative/FreshdeskReactNative-Swift.h>`. Importing it without the module prefix
(`<FreshdeskReactNative-Swift.h>`) or as a quoted header only resolves for static linkage.
**Solution:** Update to a release that imports the header with the framework-qualified path
(the bridging file tries `<FreshdeskReactNative/FreshdeskReactNative-Swift.h>` first, then falls
back for static linkage). A clean rebuild does **not** fix it on its own, since the cause is the
import path, not stale artifacts.
### iOS Build Fails with `SDK does not contain 'libarclite'`
**Problem:** The build fails with
`SDK does not contain 'libarclite' at the path '.../usr/lib/arc/libarclite_iphoneos.a'; try increasing the minimum deployment target`.
**Cause:** Recent Xcode versions removed the legacy `libarclite` archive. A pod whose deployment
target is older than iOS 13 still tries to link it.
**Solution:** Pin every pod target's deployment target in your `Podfile`'s `post_install`, then
re-run `pod install`:
```ruby
post_install do |installer|
# ... existing react_native_post_install(...) call ...
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
end
```
### App Crashes at Launch: `Library not loaded: @rpath/FreshdeskSDK.framework/FreshdeskSDK`
**(1.4.x only.)** On **2.0.0+** the native SDK is a vendored, statically-linked
xcframework embedded by CocoaPods' standard `[CP] Embed Pods Frameworks`
phase — there is no separate SPM product that can fail to embed, so this
cannot happen. Upgrade instead of chasing the fix below.
**Problem:** The app builds and installs, then crashes immediately on launch with
`dyld: Library not loaded: @rpath/FreshdeskSDK.framework/FreshdeskSDK ... (no such file)`.
**Cause:** The native SDK is pulled in as a Swift Package via the podspec's `spm_dependency`.
That helper links `FreshdeskSDK.framework` into the `FreshdeskReactNative` pod, but it does **not**
embed `FreshdeskSDK.framework` into the app bundle. CocoaPods' "Embed Pods Frameworks" phase only
copies pod frameworks, not SPM products — so the dynamic framework is missing at runtime.
**Solution:** Require the helper shipped in the npm package (SDK **1.2.3+**) and call it from
`post_install`:
```ruby
require_relative '../node_modules/@freshworks/react-native-freshdesk-sdk/ios/freshdesk_post_install'
post_install do |installer|
# ... existing react_native_post_install(...) call ...
freshdesk_post_install(installer)
end
```
After updating the `Podfile`, run `pod install` and rebuild. Verify the framework is embedded:
`ls <app>.app/Frameworks/` should list both `FreshdeskReactNative.framework` and
`FreshdeskSDK.framework`.
### iOS Icons / Custom Fonts Render as "?" (Missing Glyphs)
**Problem:** On iOS, `react-native-vector-icons` (or any bundled custom font) renders as `?`
placeholder boxes, even though `UIAppFonts` lists the `.ttf` in `Info.plist`. Android renders
the same icons correctly.
**Cause:** This happens whenever the app's `Podfile` enables
`use_frameworks! :linkage => :dynamic` for its own reasons (Freshdesk 2.0.0+
does not require or enable it itself). With dynamic frameworks, a pod's font
resources (e.g. `react-native-vector-icons`' `s.resources = "Fonts/*.ttf"`)
are bundled **inside that pod's framework** (`RNVectorIcons.framework`) instead of the main app
bundle. iOS only loads fonts declared in `UIAppFonts` from the **main app bundle**, so the lookup
fails and glyphs fall back to `?`. The CocoaPods "[CP] Copy Pods Resources" phase does not copy
the font into the app bundle under `use_frameworks!`.
**Solution:** Bundle the font into the **app target** directly so it lands in the main bundle:
1. Copy the font(s) you use into your iOS project, e.g.
`ios/<app>/Fonts/MaterialCommunityIcons.ttf`
(source: `node_modules/react-native-vector-icons/Fonts/`).
2. Add the font to the app target's **Copy Bundle Resources** build phase (drag it into the
target in Xcode, or add it to the target's `Resources` phase in `project.pbxproj`).
3. Declare it in the app's `Info.plist` under `UIAppFonts`:
```xml
<key>UIAppFonts</key>
<array>
<string>MaterialCommunityIcons.ttf</string>
</array>
```
4. Rebuild. Confirm the font is in the bundle: `ls <app>.app/MaterialCommunityIcons.ttf`.
> Tip: `npx react-native-asset` (with a `react-native.config.js` `assets` entry) automates
> steps 1–3. Only bundle the specific font files your app actually imports to keep the app size down.
### Android Build Fails: Kotlin Metadata Version Mismatch
**Problem:** `:app:compileDebugKotlin` fails with:
```text
Module was compiled with an incompatible version of Kotlin.
The binary version of its metadata is 2.1.0, expected version is 1.9.0.
```
**Cause:** Freshdesk Android native SDK 2.2.x uses Kotlin 2.1 metadata. React Native 0.75 uses
Kotlin 1.9.x. The host `:app` module compiles against Freshdesk without
`-Xskip-metadata-version-check`.
**Solution:** Apply the consumer Gradle snippet from the npm package (SDK **1.2.3+**) in root
`android/build.gradle`:
```gradle
apply from: file("../../node_modules/@freshworks/react-native-freshdesk-sdk/android/freshdesk-consumer.gradle")
```
Also set `kotlinOptions` on the app module (see [installation.md](installation.md)). Do **not**
bump `kotlinVersion` to 2.1 on RN 0.75 — it breaks the React Native Gradle plugin.
### Android Build Fails with `26.0.1`
**Problem:** `./gradlew` fails immediately with `What went wrong: 26.0.1` and no other context.
**Cause:** Gradle 8.8 (and the embedded Kotlin compiler) does not support running on JDK 26. This happens when `JAVA_HOME` points to a JDK newer than 21.
**Solutions:**
1. Build with JDK 17 (recommended for React Native Android):
```bash
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
cd sample_app/android && ./gradlew clean
cd .. && npx react-native run-android
```
2. Pin JDK 17 for Gradle only by adding this to `sample_app/android/gradle.properties` (use your local JDK 17 path):
```properties
org.gradle.java.home=/Users/you/Library/Java/JavaVirtualMachines/ms-17.0.19/Contents/Home
```
3. Make JDK 17 the default in your shell profile so Android builds always use it:
```bash
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
```
### Android Build Fails with Kotlin "Type mismatch" in `react-native-screens` / `react-native-gesture-handler`
**Problem:** `compileDebugKotlin` fails for `:react-native-screens` and/or
`:react-native-gesture-handler` with errors like:
```
ScreenViewManager.kt: Type mismatch: inferred type is StateWrapper? but StateWrapper was expected
RNGestureHandlerTouchEvent.kt: Type mismatch: inferred type is View? but View was expected
```
**Cause:** These libraries were compiled against an older React Native API surface. React Native
0.75 tightened nullability annotations on core APIs (`ViewManager.updateState`'s `StateWrapper`
parameter and `UIManagerHelper.getSurfaceId(View)`), so versions of these libraries released
before RN 0.75 no longer compile. This is a **library-version mismatch**, not a Kotlin toolchain
issue (RN 0.75 already uses the correct Kotlin 1.9.24).
**Solution:** Upgrade both navigation libraries to RN 0.75-compatible versions in your app's
`package.json`, then reinstall:
```jsonc
{
"dependencies": {
"react-native-screens": "3.34.0", // first release with RN 0.75 support
"react-native-gesture-handler": "2.20.2" // RN 0.75 supported (>= 2.18.0)
},
"overrides": {
"react-native-gesture-handler": "2.20.2"
}
}
```
```bash
npm install
cd android && ./gradlew clean
```
The `sample_app` is pinned to these versions for RN 0.75.4.
### Android "Could not resolve" Dependency Error
**Problem:** Gradle fails to resolve `com.freshworks.sdk:freshdesk`.
**Solutions:**
1. Verify `mavenCentral()` is in repositories:
```gradle
allprojects {
repositories {
google()
mavenCentral()
}
}
```
2. Sync project with Gradle files in Android Studio.
3. Check network connectivity to Maven Central.
### SDK Initialization Fails
**Problem:** `initialize()` throws an error or never completes.
**Cause:** Initialization requires only `token`, `host`, and `sdkId`. Missing push notification
configuration (Firebase, APNs, portal push keys) does **not** block initialization — in-app support
works without push. If `initialize()` rejects with `FRESHDESK_INIT_ERROR`, check network
connectivity and that credentials are valid. On Android, the promise now rejects explicitly when
remote config fetch fails instead of hanging indefinitely.
**Solution:**
1. Verify `token`, `host`, and `sdkId` from Admin Settings → Mobile Chat SDK.
2. Confirm network access from the device/emulator.
3. For JWT-enforced widgets, pass a valid `jwt` at init.
4. Do not treat missing Firebase/`google-services.json` or APNs setup as an init blocker — add
push wiring only when you need tray notifications.
5. Check console for specific error messages:
- `FRESHDESK_INVALID_CONFIG` - Missing parameters
- `FRESHDESK_INIT_ERROR` - Server/connection issue or remote config fetch failure
### Events Not Firing
**Problem:** Event listeners not receiving events.
**Solutions:**
1. Ensure SDK is initialized before setting listeners.
2. Check listener is properly set up:
```typescript
const subscription = FreshdeskSDK.addUnreadCountListener((event) => {
console.log(event);
});
```
3. Clean up and re-add listeners after app state changes.
4. On Android, verify `LocalBroadcastManager` is working.
5. On iOS, ensure you are on a release where the native module registers itself as the
`RCTEventEmitter` (the Objective-C `FreshdeskNativeModule` sets the emitter on the Swift
bridge in `-init`). On older builds the emitter was never wired up, so native notifications
(`unreadCountChanged`, `userStateChanged`, `userCreated`, `onLinkPressed`) were silently
dropped. A common symptom is the **initial unread count showing correctly** (it comes from the
direct `getUnreadCount()` call) while **real-time updates never arrive** and **User State stays
`unknown`** (both rely on events). Update to a fixed release and rebuild.
### openSupport() Shows Blank Screen
**Problem:** Support screen opens but is blank.
**Solutions:**
1. Ensure SDK is initialized successfully before calling `openSupport()`.
2. Check iOS deployment target is 15.0+.
3. Verify network connectivity.
4. Check Freshdesk credentials are valid.
### openSupport() / trackEvent() / setUserProperties() Silently Do Nothing Right After initialize() (iOS)
**Problem:** `initialize()` resolves without throwing, but the very next
call — `openSupport()`, `trackEvent()`, `setUserProperties()`, or
`setTicketProperties()` — appears to do nothing: no UI opens, no error is
thrown, no data reaches the Freshdesk dashboard. Often intermittent — it
works on a retry a moment later, or more reliably on a fast network. The
native SDK may log:
```
⚠️ [Freshdesk Warning] Tasks will be executed once the SDK is loaded, Check
whether the SDK is initialised with proper configuration.
```
**Cause:** The native iOS SDK's `Freshdesk.initialize(with:)` has no
completion callback, `async` variant, or any readiness signal of its own —
it does its own async internal loading after `initialize()` returns, and
any call made before that finishes is silently queued/dropped by the native
SDK itself (not by this wrapper). On SDK versions before the fix noted
below, the wrapper resolved `initialize()`'s JS promise the instant the
native call *returned*, not when the SDK was actually ready, so a call
issued right after `await initialize()` — completely normal usage — could
race the real load and lose.
**Solution:** Upgrade to an SDK version with the `initialize()` settle-delay
fix (see `CHANGELOG.md`'s "iOS `initialize()` settle delay" entry) —
`initialize()` now resolves only once the SDK has had time to actually
finish loading, so plain `await initialize()` usage becomes safe on its own;
no app code change needed. **Expect `initialize()` to take at least ~2
seconds on iOS as a result** — that is expected, not a regression.
On a version without the fix, or as a belt-and-braces measure: add a short
delay (1–2s) after `initialize()` resolves before making the first other
SDK call.
### JWT Authentication Issues
**Problem:** User state stuck in `notAuthenticated` or `authExpired`.
**Solutions:**
1. Verify JWT is correctly formatted and signed.
2. Check JWT is not expired.
3. For JWT-enforced SDKs, ensure widget settings match:
- Go to Admin Settings -> Mobile Chat SDK
- Verify "Enforce JWT" is enabled/disabled as expected
4. Listen for `userStateChanged` events to debug.
### Push Notifications Not Working
**Problem:** Not receiving push notifications from Freshdesk.
**Solutions (iOS):**
1. Confirm the **Push Notifications** capability + **Background Modes → Remote notifications** are
enabled on the app target in Xcode. The Push Notifications capability links
`quickbasket/quickbasket.entitlements` (`aps-environment`); without it,
`didFailToRegisterForRemoteNotificationsWithError` fires.
2. Ensure the SDK is **initialized natively** in `AppDelegate didFinishLaunchingWithOptions`
(via `FreshdeskPush.initialize`). The APNs token is registered at launch, before the JS layer
runs `initialize()`; `setPushRegistrationToken` is a no-op until the SDK is initialized, so
JS-only init drops the token. Verify the `Freshdesk*` keys exist in `Info.plist`.
3. Upload the APNs **`.p8`** auth key (with Key ID + Team ID) in the Freshdesk portal.
4. Test on a **real device** — the Simulator never receives remote pushes.
5. Verify the device token reaches the SDK: `AppDelegate` →
`didRegisterForRemoteNotificationsWithDeviceToken` → `FreshdeskPush.registerToken(...)`. If
`didFailToRegisterForRemoteNotificationsWithError` fires, the capability/provisioning is missing.
### Push Received in Foreground but Not in Background / Killed State (iOS)
**Problem:** Freshdesk notifications appear while the app is open (foreground), but nothing
arrives when the app is backgrounded or killed.
**Cause:** `AppDelegate` only forwards pushes from `willPresentNotification:` (foreground) and
`didReceiveNotificationResponse:` (notification tapped). When the app is backgrounded or
relaunched in the background, iOS delivers the payload through
`application:didReceiveRemoteNotification:fetchCompletionHandler:`. If that method is not
implemented (or it does not call `FreshdeskPush.handleRemoteNotification`), the SDK never sees the
background payload and no notification is processed/displayed.
**Solution:**
1. Implement the background delivery handler in `AppDelegate` and forward Freshdesk payloads to
the SDK (the `sample_app` includes this):
```objc
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
if ([FreshdeskPush isFreshdeskNotification:userInfo]) {
[FreshdeskPush handleRemoteNotification:userInfo
applicationState:application.applicationState];
completionHandler(UIBackgroundFetchResultNewData);
return;
}
completionHandler(UIBackgroundFetchResultNoData);
}
```
2. Confirm `UIBackgroundModes` includes `remote-notification` in `Info.plist` and that
**Background Modes → Remote notifications** is enabled on the app target. iOS only wakes a
backgrounded/terminated app for the handler above when this mode is set.
3. The push payload must include `content-available: 1` in its `aps` dictionary for iOS to wake
the app in the background. Freshdesk sends this for its data pushes; if you have a custom push
proxy, make sure it is preserved.
4. Note the user-force-quit caveat: if the user **manually swipes the app away** from the app
switcher, iOS suppresses background `content-available` wakeups until the app is launched again.
A visible alert push still appears (rendered by the system), and tapping it launches the app and
routes through `didReceiveNotificationResponse:`. This is expected iOS behavior, not an SDK bug.
**Solutions (Android):**
1. Ensure **`google-services.json`** is in `android/app/` and the **Google Services plugin** is
enabled (uncomment the classpath in `android/build.gradle` and `apply plugin` in
`android/app/build.gradle`).
2. Upload your **FCM credentials** in the Freshdesk portal.
3. Confirm `FreshdeskMessagingService` is registered in `AndroidManifest.xml` and that the device
has Google Play services.
4. On Android 13+, grant the `POST_NOTIFICATIONS` runtime permission.
5. Verify the token reaches the SDK in `FreshdeskMessagingService.onNewToken` →
`FreshdeskSDK.setPushRegistrationToken(token)`.
6. Ensure the SDK is **initialized natively** in `MainApplication.onCreate()`. Push methods are
no-ops until the SDK is initialized; initializing only from JavaScript (`FreshdeskContext`)
means the token is registered before init completes (and dropped), and background/killed
pushes are ignored because the JS layer never runs in a headless FCM delivery. Check Logcat for
`FreshdeskPush: Freshdesk SDK initialized natively (push-ready)`; if you instead see
`SDK is not initialized`, native init did not run (verify `.env` credentials are present and
surfaced via `BuildConfig`).
### Push Shown In-App but Not in the Notification Tray (iOS)
**Problem:** Freshdesk notifications appear while the app is open (foreground / in-app), but
nothing shows in the system notification tray when the app is in the background or killed.
**Cause:** The Freshdesk SDK's push methods (`handleRemoteNotification`) only post a tray
notification once the SDK is initialized. When the app is **cold-launched in the background by a
push**, iOS calls `application:didReceiveRemoteNotification:fetchCompletionHandler:` right after
`didFinishLaunchingWithOptions` returns. If native init is dispatched asynchronously, that handler
can run **before** init finishes, so the payload is dropped and no tray notification is posted. The
same push works in the foreground because the SDK is already initialized.
**Solution:** Initialize the SDK **synchronously** at launch so it is push-ready before the
background delivery handler runs. The SDK's native entry point
(`FreshdeskNativeModuleBridge.initializeSDK`, driven by `FreshdeskPush.initializeSDK` from
`AppDelegate didFinishLaunchingWithOptions`) initializes synchronously on the main thread for
exactly this reason. If you wire init yourself, do not defer it to a later run-loop turn
(`DispatchQueue.main.async`) — run it inline in `didFinishLaunchingWithOptions` so it completes
before iOS delivers the launching push.
### Push Shown In-App but Not in the Notification Tray (Android)
**Problem:** Freshdesk notifications appear while the app is open (foreground / in-app), but
nothing shows in the system notification tray when the app is in the background or killed.
**Cause:** `FreshdeskSDK.initialize(...)` is **asynchronous** — its completion callback fires only
after the SDK is fully set up, and `handleFCMNotification` / `setPushRegistrationToken` are
**no-ops until then**. On a headless FCM delivery (app killed/background), Android starts the
process to run only `FreshdeskMessagingService`. `MainApplication.onCreate()` merely *starts*
the async init, so `onMessageReceived` can run and call `handleFCMNotification` **before init
finishes** — the message is dropped and no tray notification is posted. The same push works while
the app is already running because the SDK is already initialized.
**Solution:** Have the FCM service **wait for initialization to complete** before forwarding the
message. The `sample_app` routes init through a shared, idempotent `FreshdeskInitializer` that
both `MainApplication.onCreate()` and `FreshdeskMessagingService` use; the service calls
`FreshdeskInitializer.ensureInitializedBlocking(applicationContext)` before
`FreshdeskSDK.handleFCMNotification(data)` (and before `setPushRegistrationToken` in
`onNewToken`). `onMessageReceived` runs on a background thread, so the short, bounded wait is
safe. If you wire push yourself, guarantee the SDK is initialized before calling any push method
in the service.
## Error Codes Reference
Import the typed enum and compare against it instead of matching the string
literal directly:
```typescript
import { FreshdeskErrorCode } from '@freshworks/react-native-freshdesk-sdk';
try {
await FreshdeskSDK.openSupport();
} catch (error) {
if (error.code === FreshdeskErrorCode.NOT_INITIALIZED) { /* ... */ }
}
```
Coverage is **not identical on both platforms** — a code marked (Android) or
(iOS) is only ever rejected on that platform; unmarked codes can occur on
either.
| Error Code | Platform | Description | Solution |
|------------|----------|-------------|----------|
| `FRESHDESK_INVALID_CONFIG` | Both | `initialize()`'s config was missing a required key or malformed | Check token, host, sdkId are provided |
| `FRESHDESK_NOT_INITIALIZED` | Both | A method other than `initialize()` was called before `initialize()` resolved | Call `initialize()` first, await it |
| `FRESHDESK_INIT_TIMEOUT` | Android | `initialize()` timed out (20s) waiting for the native SDK to report ready | Verify token/host/sdkId, network reachability, JWT settings |
| `FRESHDESK_INIT_ERROR` | Android | `initialize()` threw before it could start | Check credentials and network |
| `FRESHDESK_NOT_READY` | Android | `initialize()` resolved but the native SDK isn't ready yet | Retry shortly — self-resolves |
| `FRESHDESK_NO_ACTIVITY` | Android | `openSupport()`/`openKnowledgeBase()`/`openTopic()` had no foreground Activity to attach to | Ensure app is foregrounded |
| `FRESHDESK_NO_VIEW_CONTROLLER` | iOS | `openSupport()`/`openKnowledgeBase()`/`openTopic()` had no view controller to present from | Ensure app is foregrounded |
| `FRESHDESK_OPEN_ERROR` | Android | `openSupport()`/`openKnowledgeBase()`/`openTopic()` failed to present the native UI | Check SDK is initialized; on iOS, see the [silent-failure section above](#opensupport--trackevent--setuserproperties-silently-do-nothing-right-after-initialize-ios) |
| `FRESHDESK_TRACK_ERROR` | Android | `trackEvent()` failed | Check SDK is initialized |
| `FRESHDESK_USER_PROPERTIES_ERROR` | Both | `setUserProperties()` failed | Check SDK is initialized |
| `FRESHDESK_TICKET_PROPERTIES_ERROR` | Android | `setTicketProperties()` failed | Check SDK is initialized |
| `FRESHDESK_AUTH_ERROR` | Android | `authenticateAndUpdate()` failed | Verify JWT is valid |
| `FRESHDESK_DISMISS_ERROR` | Android | `dismiss()` failed | Check SDK is initialized |
| `FRESHDESK_USER_ERROR` | Both | `getUser()` failed, or its response could not be parsed | Check SDK is initialized and network |
| `FRESHDESK_USER_PARSE_ERROR` | iOS | `getUser()`'s response could not be parsed | Report with SDK version — likely a native response-shape issue |
| `FRESHDESK_CONFIG_PARSE_ERROR` | Both | `setContentConfiguration()`'s JSON payload could not be parsed | Check the config object shape |
## Debug Mode
Enable debug logging on Android:
```typescript
await FreshdeskSDK.initialize({
// ... config
debugMode: true,
});
```
Check native logs:
- iOS: Xcode console or `Console.app`
- Android: Android Studio Logcat or `adb logcat`
## Getting Help
If issues persist:
1. Check [GitHub Issues](https://github.com/freshworks/freshdesk_react_native_sdk/issues)
2. Contact Freshdesk support: support@freshdesk.com
3. Include error logs and SDK version in your report