# Installation Guide

## Prerequisites

- React Native 0.75.0 or higher. Backward-compatible with both the New
  Architecture (TurboModule) and the classic bridge — `runDiagnostics()`
  reports which one is active.
- iOS 15.0+ (for iOS apps)
- Android minSdkVersion 26+ (for Android apps)
- CocoaPods 1.12+

## NPM/Yarn Installation

```bash
npm install @freshworks/react-native-freshdesk-sdk
# or
yarn add @freshworks/react-native-freshdesk-sdk
```

## iOS Setup

**As of 2.0.0, there is one install path.** The native Freshdesk iOS SDK
ships inside the npm package as a vendored, statically-linked
`FreshdeskSDK.xcframework` — no Swift Package Manager resolution, no
`use_frameworks!`, and no `post_install` hook of its own required:

```ruby
platform :ios, '15.0'
```

```bash
cd ios && pod install
```

CocoaPods links `FreshdeskSDK.xcframework` automatically via
`vendored_frameworks`. Keep `use_frameworks!` in your `Podfile` only if some
*other* dependency needs it — prefer `:linkage => :static` if so.

> **Upgrading from `~1.4.x`?** That version used a Swift Package Manager
> path (`spm_dependency`, forced `use_frameworks! :linkage => :dynamic`,
> and an optional `FRESHDESK_IOS_USE_VENDORED` opt-out). All of that is
> removed in 2.0.0 — see `MIGRATION.md` for the exact Podfile/Gemfile lines
> to delete when upgrading.

### Step 2: iOS Deployment Target

The Freshdesk iOS SDK requires iOS 15.0+. Ensure your deployment target is set accordingly in your `Podfile`:

```ruby
platform :ios, '15.0'
```

Recent Xcode versions removed the legacy `libarclite` archive. If any pod is left with a
deployment target older than iOS 13, the build fails with
`SDK does not contain 'libarclite' ... try increasing the minimum deployment target`. Pin every
pod target in your `Podfile`'s `post_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
```

### Step 3: Framework embedding — nothing extra needed (2.0.0+)

CocoaPods embeds vendored frameworks (`vendored_frameworks`) into your app
bundle automatically via its standard `[CP] Embed Pods Frameworks` build
phase — there is no separate step to run. After building, you can confirm
`FreshdeskSDK.framework` appears in `<app>.app/Frameworks/` if you want to
double-check.

(The `Library not loaded: @rpath/FreshdeskSDK.framework/FreshdeskSDK` crash
this step used to guard against was specific to the old SPM path, where
Swift Package products aren't auto-embedded by CocoaPods. It cannot occur
on 2.0.0+'s vendored setup. If you're still on `~1.4.x` and hit it, see
[troubleshooting.md](troubleshooting.md).)

## Android Setup

### Step 1: Ensure Maven Central is Available

Verify your `android/build.gradle` includes Maven Central:

```gradle
allprojects {
    repositories {
        google()
        mavenCentral()
    }
}
```

### Step 2: Minimum SDK Version

Ensure your `minSdkVersion` is **26** or higher in `android/build.gradle` (required by
`com.freshworks.sdk:freshdesk` 2.2.4+).

The wrapper's own Gradle module reads `compileSdkVersion`/`targetSdkVersion` from your app's root
`build.gradle` `ext` block, so it always builds against whatever your app already targets. If your
app does **not** set these explicitly, the wrapper falls back to `compileSdkVersion`/
`targetSdkVersion` **35** as of this version — which requires Android Gradle Plugin **8.6+**. To
avoid depending on that fallback, or to target the newer **36** (Android 16, requires AGP
**8.9.1+**, 9.x recommended), set your own values explicitly:

```gradle
buildscript {
    ext {
        minSdkVersion = 26
        compileSdkVersion = 35
        targetSdkVersion = 35
        // ... other settings
    }
    dependencies {
        classpath("com.android.tools.build:gradle:8.6.0")
    }
}
```

The Android SDK dependency (`com.freshworks.sdk:freshdesk`) is automatically included.

### Step 3: Kotlin metadata compatibility (RN 0.75)

Freshdesk Android native SDK 2.2.x is compiled with Kotlin 2.1 metadata while React Native 0.75
uses Kotlin 1.9.x. Apply the consumer Gradle snippet from the npm package in your root
`android/build.gradle` (after `apply plugin: "com.facebook.react.rootproject"`):

```gradle
apply from: file("../../node_modules/@freshworks/react-native-freshdesk-sdk/android/freshdesk-consumer.gradle")
```

Also set JDK 17 and `kotlinOptions` on the **app** module in `android/app/build.gradle`:

```gradle
android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
        freeCompilerArgs += ["-Xskip-metadata-version-check"]
    }
}
```

Keep `kotlinVersion = "1.9.24"` in root `build.gradle` (match React Native 0.75). Do **not** bump
to Kotlin 2.1 — it breaks the React Native Gradle plugin. See
[troubleshooting.md](troubleshooting.md) for details.

## Initialize the SDK

Call `FreshdeskSDK.initialize()` once with your portal credentials (`token`, `host`, `sdkId`).
Optional fields: `locale`, `jwt` (required only for JWT-enforced widgets), `debugMode` (Android).

**Push notifications are not required for initialization.** In-app support, chat, and knowledge
base work without Firebase, APNs, or portal push configuration. Push is optional and wired
natively in the host app after init — see [Push Notifications](#push-notifications) below.

## Push Notifications

Freshdesk push is handled **natively** (there is no JavaScript push API). The sample app
(`sample_app`) is already wired; the steps below summarize what's required to make pushes arrive.

### iOS

Wiring (already done in `sample_app`):
- `FreshdeskNativeModuleBridge` exposes `registerPushToken`, `isFreshdeskNotification`, and
  `handleRemoteNotification` (see `sdk_src/ios/FreshdeskNativeModule.swift`).
- `AppDelegate` requests notification permission, registers for remote notifications, and forwards
  the token / incoming pushes via the `FreshdeskPush` Swift shim. It forwards pushes in **all three**
  delivery paths so notifications work in every app state:
  - `willPresentNotification:` — foreground.
  - `didReceiveNotificationResponse:` — user taps a notification.
  - `application:didReceiveRemoteNotification:fetchCompletionHandler:` — **background / killed
    state**. Omitting this handler is the common cause of pushes only appearing in the foreground.
    It requires `UIBackgroundModes → remote-notification` (set in `Info.plist`) and a payload with
    `content-available: 1`.
- `AppDelegate` **initializes the SDK natively** in `didFinishLaunchingWithOptions` (via
  `FreshdeskPush.initialize`) using credentials read from `Info.plist`. This is required for push:
  the APNs device token arrives at launch — before the React Native/JS layer runs
  `initialize()` — and `setPushRegistrationToken` is a no-op until the SDK is initialized, so the
  token would be dropped with JS-only init. The native init runs **synchronously** so the SDK is
  push-ready before `didFinishLaunchingWithOptions` returns; otherwise a push that cold-launches the
  app in the background can reach `didReceiveRemoteNotification:` before init completes and be
  dropped (the notification then only ever shows in the foreground, never in the system tray).

You must additionally:
1. Have a paid **Apple Developer account**.
2. In Xcode, on the app target's **Signing & Capabilities**, add the **Push Notifications**
   capability and **Background Modes → Remote notifications**. The Push Notifications capability
   wires the bundled `quickbasket/quickbasket.entitlements` (`aps-environment`); without it,
   `registerForRemoteNotifications` fails via `didFailToRegisterForRemoteNotificationsWithError`.
3. Create an **APNs Auth Key (`.p8`)** in the Apple Developer portal (note the Key ID + Team ID).
4. Upload the `.p8` (with Key ID, Team ID, bundle id) in Freshdesk: Admin Settings → Mobile Chat SDK
   → your SDK → Push Notification.
5. Keep the `Freshdesk*` keys in `Info.plist` in sync with `.env` (token, host, sdkId, locale).
6. Test on a **real device** (the iOS Simulator cannot receive remote pushes).

### Android

Push uses **Firebase Cloud Messaging (FCM)**. Wiring (already done in `sample_app`):
- `FreshdeskMessagingService` forwards the FCM token and Freshdesk messages to the SDK.
- The service is registered in `AndroidManifest.xml`; `firebase-messaging` is in `app/build.gradle`.
- The SDK is **initialized natively in `MainApplication.onCreate()`**, not only from JavaScript.
  This is required for push: the SDK's push methods (`setPushRegistrationToken`,
  `handleFCMNotification`, `isFreshdeskSDKNotification`) are no-ops until the SDK is initialized,
  and FCM can start the app **headlessly** (running only `FreshdeskMessagingService`, with no
  React Native/JS runtime) to deliver a message. The native init reads the same credentials from
  `.env` via generated `BuildConfig` fields, so there is a single source of truth.

> **Why native init?** If the SDK is initialized only from JS (`FreshdeskContext`), the FCM token
> is registered before JS init finishes (and is dropped), and background/killed pushes are ignored
> because the JS layer never runs. Initializing in `MainApplication.onCreate()` guarantees the SDK
> is ready in every process-start scenario.

You must additionally:
1. Create a **Firebase project**, add an Android app with your app's package name (the sample app
   uses `com.freshdesk.southwest`), and download **`google-services.json`** into `android/app/`.
2. Enable the Google Services plugin:
   - In `android/build.gradle`: uncomment `classpath("com.google.gms:google-services:4.4.4")`
   - In `android/app/build.gradle`: uncomment `apply plugin: "com.google.gms.google-services"`
3. Upload your FCM credentials (service account / key) in Freshdesk: Admin Settings → Mobile Chat SDK
   → your SDK → Push Notification.
4. Request the `POST_NOTIFICATIONS` runtime permission on Android 13+ (the permission is already in
   the manifest).

## Environment Configuration

Create a `.env` file in your project root (do not commit this file):

```bash
FRESHDESK_TOKEN=your_account_token
FRESHDESK_HOST=your_host.freshdesk.com
FRESHDESK_SDK_ID=your_sdk_id
FRESHDESK_LOCALE=en
FRESHDESK_JWT=optional_jwt_token
```

You can find your credentials in your Freshdesk portal:
- Go to Admin Settings -> Mobile Chat SDK

## Linking (React Native 0.60+)

The library uses autolinking. No manual linking is required for React Native 0.60+.

## Troubleshooting

### iOS Build Issues

If you encounter build issues:

1. Clean build: `rm -rf ios/build ios/Pods ios/Podfile.lock`
2. Reinstall pods: `cd ios && pod install`
3. Confirm your app's `Podfile` deployment target is `platform :ios, '15.0'`
4. Confirm you're on `@freshworks/react-native-freshdesk-sdk@2.0.0+` — nothing else is required for
   iOS on this version. Still on `~1.4.x`? That version needed `use_frameworks!` or
   `FRESHDESK_IOS_USE_VENDORED` depending on path — upgrading is simpler than chasing that setup;
   see `MIGRATION.md`.

### Android Build Issues

If dependencies fail to resolve:

1. Clean gradle: `cd android && ./gradlew clean`
2. Ensure `mavenCentral()` is in your repositories
3. Sync project with gradle files

### "Native module not found" Error

1. Ensure the library is properly installed: `npm install`
2. iOS: Run `pod install` in the ios directory
3. Android: Run gradle sync
4. Rebuild the app

## Next Steps

- [Initialization](initialization.md) - Initialize the SDK
- [API Reference](api_reference.md) - Available methods and events
