# Keeping The Call Alive In Background

Keep calls alive when the app goes to the background. Users continue hearing remote audio streams while the app is backgrounded. On Android, this is achieved using a [foreground service](https://developer.android.com/guide/components/foreground-services). On iOS, the SDK uses [CallKit](https://developer.apple.com/documentation/callkit) integration to report ongoing calls to the system.

## Install Dependencies

The `@stream-io/react-native-callingx` package is required for registering ongoing calls in [iOS CallKit](https://developer.apple.com/documentation/callkit). This is what allows the system to keep the call alive in the background.

```bash title=Terminal
yarn add @stream-io/react-native-callingx@beta

npx pod-install
```

>
> **Info:** If you already have `@stream-io/react-native-callingx` installed as part of the [ringing setup](https://getstream.io/video/docs/react-native/v2/advanced/incoming-calls/ringing-setup/react-native/), no additional installation is needed.
>

## Android Setup

In Android, we use a [foreground service](https://developer.android.com/guide/components/foreground-services) to keep the call alive. The SDK will automatically create and manage the foreground service.

**Expo**

In order to be able to use the foreground service, some declarations need to be added to the `AndroidManifest.xml`. In **app.json**, in the `plugins` field, add `true` to the `androidKeepCallAlive` property in the `@stream-io/video-react-native-sdk` plugin. This will add the declarations automatically.

```js title="app.json" {6}
{
 "plugins": [
      [
        "@stream-io/video-react-native-sdk",
        {
           "androidKeepCallAlive": true
        }
      ],
      // your other plugins
  ]
}
```

>
> **Tip:** If Expo EAS build is not used, please do `npx expo prebuild --clean` to edit the `AndroidManifest.xml` again after adding the config plugin property.
>

**React Native**

In order to be able to use the foreground service, some declarations need to be added in the `AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- We declare the permissions needed for using foreground service to keep call alive -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
```

>
> **Info:** When uploading the app to the Play Store, it is essential to declare the permissions for foreground services in the Play Console and provide an explanation for their use. This includes adding a link to a video that demonstrates how the foreground service is utilized during video and audio calls. This procedure is required only once. For more details, click [here](https://support.google.com/googleplay/android-developer/answer/13392821). The added permissions are:
>
> - `android.permission.FOREGROUND_SERVICE_CAMERA` - To access camera when app goes to background
> - `android.permission.FOREGROUND_SERVICE_MICROPHONE` - To access microphone when app goes to background
> - `android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK` - To play video and audio tracks when the app goes to background
>

### Request notification permissions

At an appropriate place in your app, request notification permissions from the user.
Below is an example of how to request notification permissions using the [`react-native-permissions`](https://github.com/zoontek/react-native-permissions) library:

```ts
import { requestNotifications } from "react-native-permissions";

// This will request POST_NOTIFICATION runtime permission for Anroid 13+
await requestNotifications(["alert", "sound"]);
```

>
> **Tip:** For a comprehensive guide on requesting all required permissions (camera, microphone, bluetooth, and notifications), see [Manage Native Permissions](https://getstream.io/video/docs/react-native/v2/guides/native-permissions/).
>

### Optional: override the default configuration of the foreground service notifications

```ts
import { StreamVideoRN } from "@stream-io/video-react-native-sdk";

StreamVideoRN.updateConfig({
  foregroundService: {
    android: {
      channel: {
        id: "stream_call_foreground_service",
        name: "Service to keep call alive",
      },
      // you can edit the title and body of the notification here
      notificationTexts: {
        title: "Video call is in progress",
        body: "Tap to return to the call",
      },
      // you can optionally add a promise to run in the foreground service
      taskToRun: (call) =>
        new Promise(() => {
          console.log(
            "jumping to foreground service foreground service with call-cid",
            call.cid,
          );
        }),
    },
  },
});
```

## iOS Setup

Enable the `audio` and `voip` background modes to keep the call alive when users lock their device or switch apps.

**Expo**

The Expo config plugin automatically adds the `audio` background mode. To also enable the `voip` background mode, set `iosKeepCallAlive` to `true` in the plugin configuration:

```js title="app.json" {6}
{
 "plugins": [
      [
        "@stream-io/video-react-native-sdk",
        {
           "iosKeepCallAlive": true
        }
      ],
      // your other plugins
  ]
}
```

>
> **Tip:** If Expo EAS build is not used, please do `npx expo prebuild --clean` to regenerate the native project after adding the config plugin property.
>

**React Native**

In Xcode, add both `audio` and `voip` to `UIBackgroundModes` in `Info.plist`:

```xml
<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
  <string>voip</string>
</array>
```

- `audio` — allows audio playback to continue in the background.
- `voip` — allows the SDK to manage call lifecycle and report ongoing calls to the system via CallKit.

### Enable ongoing calls

To enable keeping calls alive in the background, set `enableOngoingCalls: true` in `setPushConfig` and pass `createStreamVideoClient` so the SDK can create a `StreamVideoClient` when needed from the background. This lets the SDK manage events from CallKit.

```ts
import {
  StreamVideoClient,
  StreamVideoRN,
  User,
} from "@stream-io/video-react-native-sdk";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { STREAM_API_KEY } from "../constants"; // adjust import to your project

const createStreamVideoClient = async () => {
  const userId = await AsyncStorage.getItem("@userId");
  const userName = await AsyncStorage.getItem("@userName");
  if (!userId) return undefined;

  const tokenProvider = async (): Promise<string> =>
    yourServerAPI.getTokenForUser(userId).then((auth) => auth.token);

  const user: User = { id: userId, name: userName };
  return StreamVideoClient.getOrCreateInstance({
    apiKey: STREAM_API_KEY,
    user,
    tokenProvider,
  });
};

StreamVideoRN.setPushConfig({
  ios: {
    enableOngoingCalls: true,
  },
  createStreamVideoClient,
});
```

>
> **Warning:** Always use `StreamVideoClient.getOrCreateInstance(..)` instead of `new StreamVideoClient(..)`. Reusing the client instance preserves call accept/decline states changed while the app was in the background. The `getOrCreateInstance` method ensures the same user reuses the existing instance.
>

---

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react-native/v2/guides/keeping-call-alive/](https://getstream.io/video/docs/react-native/v2/guides/keeping-call-alive/).