UNPKG

@freshworks/react-native-freshdesk-sdk

Version:
563 lines (397 loc) 21.9 kB
# Freshdesk React Native SDK — Integration Knowledge Base Use this document to **answer customer integration questions** directly — like a support knowledge base. Search by topic or symptom before writing code. **Related references:** [integration-faq.md](integration-faq.md) · [platform-apis.md](platform-apis.md) · [examples.md](examples.md) · [SKILL.md](SKILL.md) --- ## Quick answers — most asked | Question | Answer | |----------|--------| | How do I install? | `npm install @freshworks/react-native-freshdesk-sdk`, then `cd ios && pod install`. Autolinking handles native linking. | | Where do I get credentials? | Freshdesk portal → **Admin Settings → Mobile Chat SDK** → your SDK → App Keys (`token`, `host`, `sdkId`). | | What goes in `.env`? | `FRESHDESK_TOKEN`, `FRESHDESK_HOST`, `FRESHDESK_SDK_ID`, optional `FRESHDESK_LOCALE`, `FRESHDESK_JWT`. Never commit `.env`. | | Host with or without `https://`? | **Both work.** `yourcompany.freshdesk.com` and `https://yourcompany.freshdesk.com` — SDK auto-prefixes `https://` (1.2.2+). | | Minimum React Native version? | **0.75.0+**. Backward-compatible with both the New Architecture (TurboModule) and the classic bridge. | | Minimum iOS / Android? | iOS **15.0+**, Android **minSdk 26**, `compileSdk 35` (wrapper's fallback if the app doesn't set its own), AGP **8.6+**. | | Do I need push for chat/support? | **No.** In-app support, chat, and KB work with JS init only. Push is optional. | | How do I open support? | `await FreshdeskSDK.openSupport()` after `initialize()`. | | How do I open FAQ/KB? | `await FreshdeskSDK.openKnowledgeBase()`. | | How do I verify integration? | `await FreshdeskSDK.runDiagnostics()` — apply each check's `fixHint`. | | How do I use the AI kit? | Copy from `node_modules/.../ai-integration-kit/.` into app root; prompt your AI tool to use the skill. | | `pod install` fails — `native-versions.json`? | Upgrade to SDK **1.2.2+** (file must be in npm tarball). | | Widget spinner forever on Android? | Check double init (MainApplication + JS), host format, JWT. See [Spinner / blank widget](#spinner--blank-widget-android). | | `openSupport`/`trackEvent`/`setUserProperties` silently no-op on iOS right after `initialize()`? | Native SDK's own async load isn't done yet — the wrapper's `initialize()` settle delay fixes this. See [Support widget or trackEvent/setUserProperties silently fail (iOS)](#support-widget-or-trackeventsetuserproperties-silently-fail-ios). | --- ## Getting started ### Q: What is `@freshworks/react-native-freshdesk-sdk`? A React Native wrapper around the native Freshdesk Android and iOS SDKs. It exposes JavaScript APIs for in-app support chat, knowledge base, user identity (JWT or properties), content customization, and diagnostics. Push is wired **natively** — there is no JS push API. ### Q: What are the install steps? ```bash npm install @freshworks/react-native-freshdesk-sdk cd ios && pod install # iOS only ``` **iOS Podfile (2.0.0+):** ```ruby platform :ios, '15.0' ``` Nothing else Freshdesk-specific — the native SDK is a vendored, statically linked xcframework, so it never forces `use_frameworks!` and needs no `post_install` hook of its own. (Apps still pinned to `~1.4.x` need the old SPM setup instead — see [troubleshooting.md](troubleshooting.md); upgrading is simpler.) **Android:** Ensure `mavenCentral()` in repositories, `minSdkVersion 26`. `compileSdkVersion`/`targetSdkVersion` are inherited from your app's own `ext` block; the wrapper falls back to **35** (AGP 8.6+) if your app doesn't set them. ### Q: How do I use the AI Integration Kit? After npm install: ```bash cp -R node_modules/@freshworks/react-native-freshdesk-sdk/ai-integration-kit/. . ``` Then ask your AI tool: *"Use the freshdesk-react-native-integration skill."* The kit teaches agents greenfield integration, Q&A (this document), and diagnostics-driven debugging. ### Q: What is the sample app? The SDK repo includes `sample_app/` — reference wiring for init, push, JWT, content config, and diagnostics. Point customers to it for copy-paste patterns. --- ## Credentials & configuration ### Q: Which credentials are required? | Field | Required | Source | |-------|----------|--------| | `token` | Yes | Portal → Mobile Chat SDK → App Keys | | `host` | Yes | Your Freshdesk instance URL | | `sdkId` | Yes | Portal → Mobile Chat SDK | | `locale` | No | Default `en` — widget language | | `jwt` | Only if JWT enforced | Server-generated per user | ### Q: Where should credentials live? | Layer | File | Keys | |-------|------|------| | JavaScript | `.env` (gitignored) | `FRESHDESK_TOKEN`, `FRESHDESK_HOST`, `FRESHDESK_SDK_ID`, `FRESHDESK_LOCALE`, `FRESHDESK_JWT` | | Android push (native) | `android/app/build.gradle``buildConfigField` | Same names as BuildConfig | | iOS push (native) | `ios/<App>/Info.plist` | `FreshdeskToken`, `FreshdeskHost`, `FreshdeskSdkId`, `FreshdeskLocale`, `FreshdeskJwt` | **Never ask customers to paste secrets in chat.** Point them to these files. ### Q: What host format should I use? Either format works (1.2.2+): ```bash FRESHDESK_HOST=yourcompany.freshdesk.com # or FRESHDESK_HOST=https://yourcompany.freshdesk.com ``` The SDK normalizes bare domains to `https://` automatically in JS, Android, and iOS. ### Q: How do I wire `.env` to JavaScript? Use `react-native-dotenv` (or equivalent): 1. `babel.config.js` — include the plugin 2. `src/types/env.d.ts` — declare `FRESHDESK_*` keys 3. Import: `import { FRESHDESK_TOKEN } from '@env'` 4. **Restart Metro** after changing `.env` --- ## Initialization ### Q: How do I initialize the SDK? Call once, early (root component or provider): ```typescript import FreshdeskSDK from '@freshworks/react-native-freshdesk-sdk'; await FreshdeskSDK.initialize({ token: FRESHDESK_TOKEN, host: FRESHDESK_HOST, // bare or https:// — both OK sdkId: FRESHDESK_SDK_ID, locale: FRESHDESK_LOCALE || 'en', jwt: FRESHDESK_JWT, // only if JWT enforced debugMode: __DEV__, // Android Logcat only }); ``` ### Q: Can I call `initialize()` more than once? **No** — once per app session. For credential changes, call `resetUser()` then re-init, or use `authenticateAndUpdate(jwt)` for JWT refresh. ### Q: What errors can `initialize()` throw? | Code | Meaning | Fix | |------|---------|-----| | `FRESHDESK_INVALID_CONFIG` | Missing token, host, or sdkId | Fill `.env`, restart Metro | | `FRESHDESK_INIT_ERROR` | Native bootstrap failed | Check credentials, network, portal SDK config | | `FRESHDESK_INIT_TIMEOUT` | **Android only** — init did not complete in 20s | Verify token/host/sdkId; check JWT if enforced; check network reachability to the host | iOS has no equivalent timeout-based rejection — its `initialize()` has no failure signal from the native SDK at all, so it only rejects on a programmer error (missing config, or a call before it resolves). If iOS `initialize()` genuinely never resolves, that points at a network/credential problem the native SDK isn't surfacing — try Android with the same credentials to get a clearer error, or check reachability to the host directly. ### Q: Why does `initialize()` always take a couple of seconds on iOS? By design. The native iOS SDK gives no signal for when it's actually finished its own internal async loading, so the wrapper holds `initialize()`'s promise for a fixed ~2s settle delay past the native call returning before resolving — otherwise a call made right after `await initialize()` (completely normal usage) could race the SDK's real load and silently fail. See [platform-apis.md](platform-apis.md) for the full explanation and `CHANGELOG.md` for which version added it. Do not treat this delay itself as a bug; do treat a `openSupport()`/`trackEvent()`/etc. call that fails or no-ops **after** `initialize()` has resolved as a real issue. ### Q: JS-only init vs native init — when do I need native? | Scenario | Init location | |----------|---------------| | In-app support / chat / KB only | **JS only**`FreshdeskSDK.initialize()` in app | | Push while app is open | JS init + register FCM/APNs token after init | | Push when app killed/background (Android) | Native init **inside `FirebaseMessagingService` only** — not `MainApplication.onCreate` | | Push when app killed/background (iOS) | Native init in `AppDelegate` (APNs token arrives before JS) | > **Android critical:** Do **not** call native `FreshdeskSDK.initialize()` in `MainApplication.onCreate()` **and** JS `initialize()` — this double-init breaks `openSupport()` (spinner forever). Use JS for in-app; FCM service for headless push. --- ## Opening support & knowledge base ### Q: How do I open the support widget? ```typescript await FreshdeskSDK.openSupport(); ``` Wire to a button, settings item, or tab. Guard until init completes. ### Q: How do I open the knowledge base / FAQ directly? ```typescript await FreshdeskSDK.openKnowledgeBase(); ``` ### Q: How do I open a specific topic? ```typescript await FreshdeskSDK.openTopic({ topicName: 'Billing' }); // optional: await FreshdeskSDK.openTopic({ topicName: 'Billing', topicId: '123' }); ``` ### Q: How do I dismiss the widget? ```typescript await FreshdeskSDK.dismiss(); ``` ### Q: How do I show unread message count? ```typescript const count = await FreshdeskSDK.getUnreadCount(); FreshdeskSDK.addUnreadCountListener((event) => { console.log(event.count); }); // cleanup: subscription?.remove() ``` --- ## JWT authentication ### Q: How do I know if JWT is required? Check Freshdesk portal widget settings, or run iOS diagnostics — look for `remoteConfig.jwtEnforced`. Symptoms without JWT: spinner after open, user state `jwtNotPresent` or `notAuthenticated`. ### Q: How do I wire JWT? ```typescript await FreshdeskSDK.initialize({ ..., jwt: userJwt }); FreshdeskSDK.addUserStateListener(({ state }) => { if (state === 'authExpired') { // fetch new JWT from your server FreshdeskSDK.authenticateAndUpdate(newJwt); } }); // on logout: await FreshdeskSDK.resetUser(); ``` ### Q: Can I use `setUserProperties` with JWT? **No** — when JWT is enforced, user identity comes from the JWT payload. Use `setUserProperties` only for non-JWT SDKs. ### Q: Where is JWT generated? Server-side, signed with the encryption key from Admin → Mobile Chat SDK → JWT settings. See [Freshdesk JWT docs](https://support.freshdesk.com/en/support/solutions/articles/50000011580-enable-jwt-authentication). --- ## Push notifications ### Q: Is there a JavaScript push API? **No.** Push is native-only. Forward FCM/APNs tokens and messages in native code. ### Q: Android push setup summary 1. Firebase project + `google-services.json` in `android/app/` 2. Google Services Gradle plugin 3. `FirebaseMessagingService` — forward token + messages: ```kotlin FreshdeskSDK.setPushRegistrationToken(token) if (FreshdeskSDK.isFreshdeskSDKNotification(remoteMessage)) { FreshdeskSDK.handleFCMNotification(remoteMessage) } ``` 4. For **headless/killed** delivery: initialize natively inside the messaging service (see sample app `FreshdeskInitializer`), **not** in `MainApplication.onCreate` 5. Upload FCM credentials to Freshdesk portal 6. `POST_NOTIFICATIONS` permission (Android 13+) ### Q: iOS push setup summary 1. Push Notifications + Background Modes capabilities in Xcode 2. APNs `.p8` key uploaded to Freshdesk portal 3. Native init in `AppDelegate` (token arrives before JS) 4. Forward all three delivery paths: foreground, tap, background/killed 5. Test on a **real device** (Simulator cannot receive remote pushes) ### Q: Push works in foreground but not background? **iOS:** Missing `application:didReceiveRemoteNotification:fetchCompletionHandler:` or Background Modes → Remote notifications. **Android:** SDK not initialized before `handleFCMNotification` in headless process — init in FCM service, wait for ready before handling. --- ## Content configuration & locale ### Q: How do I change widget text / labels? ```typescript await FreshdeskSDK.setContentConfiguration({ headers: { chat: 'Talk to us', faq: 'Help Centre' }, placeholders: { replyField: 'Type here...', searchField: 'Search...' }, actions: { tabChat: 'Chat' }, }); ``` Pass `{}` to reset to widget defaults. Changes persist immediately. ### Q: How do I set the widget language? Pass `locale` at init: `locale: 'fr'`, `locale: 'de'`, etc. Also set `FRESHDESK_LOCALE` in `.env` and native credential files if using push. --- ## Events & listeners | Event | API | Platform | |-------|-----|----------| | Unread count changed | `addUnreadCountListener(cb)` | Both | | User auth state changed | `addUserStateListener(cb)` | Both | | New user created | `addUserCreatedListener(cb)` | **iOS only** | | Link pressed in widget | `setLinkHandler(cb)` | Both | Always clean up: `subscription?.remove()` and `FreshdeskSDK.removeAllListeners()` on unmount. **User states:** `authenticated`, `authExpired`, `notAuthenticated`, `identifierUpdated`, `jwtNotPresent`, `undefined` --- ## User management ### Q: How do I set user info (non-JWT)? ```typescript await FreshdeskSDK.setUserProperties({ name: 'Jane Doe', email: 'jane@example.com', phone: '+1234567890', }); ``` On iOS, only call this **after `initialize()` has actually resolved** — see the [settle-delay Q&A](#q-why-does-initialize-always-take-a-couple-of-seconds-on-ios) above. It won't error, it will just silently not take effect if called too early on an SDK version without the fix. ### Q: How do I set ticket defaults? ```typescript await FreshdeskSDK.setTicketProperties({ subject: 'App support', priority: 3 }); ``` ### Q: What happens on logout? ```typescript const result = await FreshdeskSDK.resetUser(); // result.success === true when cleared ``` **iOS caveat:** the native SDK has no failure callback for `resetUser()` — the promise always resolves `{ success: true }` once the SDK is initialized, even if the reset didn't actually succeed server-side. It only **rejects** for the programmer-error case (called before `initialize()` resolved). Don't rely on `result.success === false` as a cross-platform failure signal — see `PLATFORM_DIFFERENCES.md`. --- ## Analytics ### Q: How do I track a custom event? ```typescript await FreshdeskSDK.trackEvent('purchase_completed', { amount: 42, currency: 'USD' }); ``` **Platform difference:** Android passes property values through with their original type (`string | number | boolean`); iOS coerces every value to a string before handing it to the native SDK. The same call above reaches Android's analytics backend with a numeric `amount` and iOS's with the string `"42"`. If your backend does numeric aggregation on a property, be aware iOS always reports it as text. See `PLATFORM_DIFFERENCES.md`. On iOS, only call after `initialize()` has actually resolved (same settle-delay caveat as `openSupport()`/`setUserProperties()`). --- ## Diagnostics & debugging ### Q: How do I run diagnostics? ```typescript await FreshdeskSDK.enableDebugLogs(true); const report = await FreshdeskSDK.runDiagnostics(); console.log(report.prettyPrinted); ``` Each check has `id`, `status` (`pass|warn|fail|skipped`), `details`, and `fixHint`. **Apply `fixHint` verbatim.** ### Q: iOS vs Android diagnostics? | | iOS | Android | |---|-----|---------| | Depth | Full native report | Wrapper checks + `runtime.diagnostics: skipped` | | Extra signal | Native logs via `enableDebugLogs` | `debugMode: true` in init + Logcat | ### Q: Key diagnostic checks | Check | Meaning | |-------|---------| | `runtime.sdkInitialized` | Init completed | | `runtime.nativeModule` | RN bridge linked | | `config.token` / `config.host` / `config.sdkId` | Credentials present | | `network.configEndpoint` | Portal reachable with credentials | | `runtime.doubleInit` (Android) | Native + JS double init — remove MainApplication init | | `config.hostScheme` (Android) | Bare host — auto-normalized on 1.2.2+ | | `push.*` | Push wiring status | --- ## Troubleshooting by symptom ### Native module not found 1. `npm install @freshworks/react-native-freshdesk-sdk` 2. iOS: `cd ios && pod install` (2.0.0+ needs nothing else — no `use_frameworks!` to confirm) 3. Android: `./gradlew clean`, rebuild 4. Restart Metro; **rebuild native app** (not just JS reload) ### Spinner / blank widget (Android) 1. **Double init** — remove native init from `MainApplication.onCreate`; use JS init only for in-app 2. **Host** — ensure valid host; both bare and `https://` work on 1.2.2+ 3. **JWT** — if enforced, pass valid `jwt` at init 4. Run diagnostics; check `runtime.doubleInit`, `config.hostScheme` ### Support widget or `trackEvent`/`setUserProperties` silently fail (iOS) **Symptom:** `initialize()` resolves fine, but `openSupport()` / `trackEvent()` / `setUserProperties()` / `setTicketProperties()` called right after do nothing — no UI, no error, no data on the dashboard. Intermittent, or "it worked the second time." The native SDK may log `"Tasks will be executed once the SDK is loaded"`. 1. **Root cause:** the native SDK has no readiness signal of its own and keeps loading asynchronously after `initialize()` returns; a call issued too early is silently dropped by the native SDK itself, not by this wrapper. 2. **Fix:** confirm the SDK version includes the `initialize()` settle-delay fix (`CHANGELOG.md`) — it makes plain `await initialize()` usage safe. 3. **If still on an older version:** add a short delay (1–2s) after `initialize()` resolves before the first other call, or upgrade. 4. See [platform-apis.md](platform-apis.md) for the full explanation. ### `FRESHDESK_INVALID_CONFIG` Empty `token`, `host`, or `sdkId`. Check `.env`, `@env` babel plugin, Metro restart. ### `FRESHDESK_NOT_INITIALIZED` / `FRESHDESK_NOT_READY` Called SDK method before `initialize()` resolved. Await init in provider; guard UI buttons. `FRESHDESK_NOT_READY` (Android) additionally means `initialize()` resolved but the native SDK's own readiness check hasn't confirmed yet — retry after a short wait, it self-resolves. ### Android build — `FreshdeskModule.kt` "Argument type mismatch … `HashMap<String, Any?>` … `Map<String, Any>`" RN 0.79+ with Kotlin 2.1.x, failing at lines 253 / 268 / 283 of the wrapper's `FreshdeskModule.kt`. RN ≥ 0.79 made `ReadableMap.toHashMap()` return `HashMap<String, Any?>`; wrapper ≤ 2.0.0 passed it into the native SDK's `Map<String, Any>` and Kotlin 2.1 rejects it. Wrapper bug — upgrade to `@freshworks/react-native-freshdesk-sdk@2.0.1+`, then `./gradlew clean`. No app-side change; do not edit files under `node_modules/`. Different from the Kotlin *metadata* mismatch (that one needs `freshdesk-consumer.gradle`). ### iOS crash — Library not loaded FreshdeskSDK.framework **`~1.4.x` only.** Missing Embed Frameworks step in Podfile `post_install` for the old SPM path. On **2.0.0+** this cannot happen — the native SDK is a vendored static xcframework with nothing to embed via SPM. Upgrade instead of chasing the `post_install` fix. See troubleshooting doc. ### iOS `pod install` — native-versions.json missing Upgrade to `@freshworks/react-native-freshdesk-sdk@1.2.2+`. ### Push not received 1. Run diagnostics — check `push.*` checks 2. iOS: real device, capabilities, `.p8` in portal, all three notification paths 3. Android: `google-services.json`, FCM in portal, messaging service registered, headless init in FCM service ### Metro ECONNREFUSED Start Metro; for USB Android: `adb reverse tcp:8081 tcp:8081` --- ## API quick reference ```typescript // Core FreshdeskSDK.initialize(config) FreshdeskSDK.openSupport() FreshdeskSDK.openKnowledgeBase() FreshdeskSDK.openTopic({ topicName, topicId? }) FreshdeskSDK.dismiss() FreshdeskSDK.getUnreadCount() // User FreshdeskSDK.setUserProperties(props) // non-JWT only FreshdeskSDK.setTicketProperties(props) FreshdeskSDK.authenticateAndUpdate(jwt) FreshdeskSDK.resetUser() FreshdeskSDK.getUser() // Customization FreshdeskSDK.setContentConfiguration(config) // Analytics FreshdeskSDK.trackEvent(name, props?) // Diagnostics FreshdeskSDK.enableDebugLogs(true) FreshdeskSDK.runDiagnostics() // Events FreshdeskSDK.addUnreadCountListener(cb) FreshdeskSDK.addUserStateListener(cb) FreshdeskSDK.addUserCreatedListener(cb) // iOS only FreshdeskSDK.setLinkHandler(cb) FreshdeskSDK.removeAllListeners() // Info FreshdeskSDK.getSDKVersion() // Error codes (typed enum — match on these instead of string literals) import { FreshdeskErrorCode } from '@freshworks/react-native-freshdesk-sdk'; // e.g. FreshdeskErrorCode.NOT_INITIALIZED, FreshdeskErrorCode.INIT_TIMEOUT ``` Not every `FreshdeskErrorCode` member is emitted on both platforms — Android has several method-specific codes iOS doesn't (and vice versa for two iOS ones). Check each member's JSDoc, or [platform-apis.md](platform-apis.md), for which platform(s) can throw it. Full types: see `docs/integration/api_reference.md` in the SDK repo. --- ## Agent instructions — answering questions When a customer asks an integration question (not a full greenfield request): 1. **Search this knowledge base** for the topic or symptom. 2. **Answer directly** with the relevant section — include code snippets when helpful. 3. **Cite platform differences** from [platform-apis.md](platform-apis.md) when Android vs iOS differ. 4. If the question implies a bug, switch to **Mode B** — run or ask for `runDiagnostics()` output. 5. If they want full integration, switch to **Mode A** — phased workflow in [SKILL.md](SKILL.md). 6. Never invent credentials. Point to portal and file paths. 7. If unsure, say what you know and what to verify (diagnostics, Logcat, portal settings).