# Background fetch

> Run a task periodically in the background (the older fetch-style API), on every SymbioteNative adapter.

Refresh data on a rough schedule while the app is not open. `@symbiote-native/background-fetch`
wraps [`expo-background-fetch`](https://github.com/expo/expo/tree/main/packages/expo-background-fetch)
so every SymbioteNative adapter can register a task that fires periodically in the background. It
does not define what the task does: define it first with
[`@symbiote-native/task-manager`](/docs/packages/task-manager/)'s `defineTask`, then register it
here for periodic execution.

<Aside type="caution" title="Upstream deprecated this API">
  Apple and Google are both moving from periodic-fetch-style scheduling
  toward task-scheduling APIs (`BGTaskScheduler` / `WorkManager`). This
  package is ported because Expo still ships both simultaneously, and an app
  already built against the old API needs a path onto SymbioteNative. Prefer
  [`@symbiote-native/background-task`](/docs/packages/background-task/) for
  new code.
</Aside>

Every export is a plain async function — no hook/composable/service to wrap, so every adapter's
entry point is a plain re-export of the same core.

| OS platform | Support |
| ----------- | ------- |
| iOS         | ✅ live |
| Android     | ✅ live |

| Framework adapter | Support |
| ------------------ | ------- |
| React              | ✅ live |
| Vue                | ✅ live |
| Angular            | ✅ live |
| Svelte             | ✅ live |
| Solid              | ✅ live |

## Installation

```sh
npm install @symbiote-native/background-fetch @symbiote-native/task-manager
```

Scaffolding or extending a SymbioteNative app? `npx @symbiote-native/cli new --background-fetch`
(or `add --background-fetch` in an existing app) installs and wires this for you — see
[`@symbiote-native/cli`](https://github.com/OneEyed1366/symbiote-native/tree/master/packages/cli).

`expo-background-fetch` and `expo-modules-core` come along as regular dependencies, pinned to
exact versions — never install them yourself, and never add the `expo` meta-package to your
project.

<Aside type="danger" title="Native setup is required before first use">
  Follow [How to: wire up an Expo native
  module](/docs/howtos/expo-native-module-setup/) once per app first. iOS
  additionally needs `UIBackgroundModes: fetch` in `Info.plist`, wired
  automatically by the same postinstall step. Android needs no manual step —
  `RECEIVE_BOOT_COMPLETED` and `WAKE_LOCK` ship in `expo-background-fetch`'s
  own manifest and merge in automatically.
</Aside>

## Usage

```ts
// index.ts, alongside AppRegistry.registerComponent — identical on every adapter
import { defineTask } from '@symbiote-native/task-manager';
import { registerTaskAsync, BackgroundFetchResult } from '@symbiote-native/background-fetch';

const SYNC_TASK = 'background-sync';

defineTask(SYNC_TASK, async ({ data, error }) => {
  if (error) {
    console.error('background-sync failed:', error);
    return BackgroundFetchResult.Failed;
  }
  const receivedNewData = await runSync(data);
  return receivedNewData ? BackgroundFetchResult.NewData : BackgroundFetchResult.NoData;
});

// Somewhere after the task is defined (a settings screen, app bootstrap, …):
await registerTaskAsync(SYNC_TASK, { minimumInterval: 900 });
```

```ts
import { getStatusAsync, unregisterTaskAsync } from '@symbiote-native/background-fetch';

const status = await getStatusAsync();
await unregisterTaskAsync(SYNC_TASK); // stop receiving background-fetch callbacks for it
```

Identical import surface on every adapter — `@symbiote-native/background-fetch/react`, `/vue`,
`/svelte`, `/solid`, `/angular` all re-export the same functions.

## API

### Functions

| Signature                                                  | Description                                                                         |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `registerTaskAsync(taskName, options?): Promise<void>`     | Registers a defined task to fire periodically. Throws if the task is not defined    |
| `unregisterTaskAsync(taskName): Promise<void>`             | Stops background-fetch callbacks for the task                                       |
| `getStatusAsync(): Promise<BackgroundFetchStatus \| null>` | Whether the app can receive background fetches right now                            |
| `setMinimumIntervalAsync(minimumInterval): Promise<void>`  | Sets the minimum interval in seconds. A no-op on Android                            |

### `IBackgroundFetchOptions`

| Field             | Type                  | Description                                                                                     |
| ----------------- | --------------------- | ----------------------------------------------------------------------------------------------- |
| `minimumInterval` | `number \| undefined` | Inexact interval in seconds between fetches. The OS may stretch it to save battery. Android defaults to 10 minutes; iOS uses its smallest supported interval (10 to 15 minutes) |
| `stopOnTerminate` | `boolean \| undefined` | Android only. Stop receiving events once the user terminates the app. Defaults to `true`        |
| `startOnBoot`     | `boolean \| undefined` | Android only. Restart events after the device finishes booting. Defaults to `false`             |

### Enums

| Enum                    | Values                                                                                                            |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `BackgroundFetchResult` | What the task executor returns, used by iOS to schedule future fetches: `NoData`, `NewData`, `Failed`. Android ignores it |
| `BackgroundFetchStatus` | `Denied` (user disabled background behavior), `Restricted` (unavailable, for example parental controls), `Available` |

## Notes

- **`registerTaskAsync` requires the task to already be defined** — it throws if the task named
  isn't defined yet with `@symbiote-native/task-manager`'s `defineTask`.
- **`getStatusAsync` resolves `Available` on Android without calling native at all** — Android has
  no status concept of its own; the native call exists only on iOS.
- **`setMinimumIntervalAsync` silently no-ops on Android** rather than throwing — there is no
  native equivalent call there.
- **Every function warns once, on first call, that this API is deprecated.** It still works; the
  warning is a nudge toward `@symbiote-native/background-task`, not a functional restriction.

## Common questions

**The task never fires.** The `minimumInterval` is a hint, not a promise. iOS decides when to run it
from usage patterns and may run it every half hour, every few hours, or not at all on a given day.
Also check that `defineTask` runs at module scope, outside any component, and that it ran before
`registerTaskAsync`.

**`registerTaskAsync` is rejected on Android in a release build.** This is reported upstream for
release builds only. Test a release build, and register after the task is defined.

**Does it run when the user kills the app?** On Android `stopOnTerminate` defaults to `true`, so it
stops. Set `stopOnTerminate: false` and `startOnBoot: true` to keep it going. iOS stops when the user
force-quits the app.

**What should the task return?** On iOS return `BackgroundFetchResult.NewData`, `NoData` or `Failed`,
so the system can schedule future fetches. Android ignores the value.

**Should I use this for new code?** No. Use
[background task](/docs/packages/background-task/), the modern replacement.

**iOS needs a background mode.** `UIBackgroundModes: fetch` is added for you through the task
manager's link manifest.

Sources: [Expo docs: BackgroundFetch](https://docs.expo.dev/versions/latest/sdk/background-fetch/),
[expo/expo#35551 registerTaskAsync rejected on Android, release build only](https://github.com/expo/expo/issues/35551),
[expo/expo#33596 background fetch does not execute the task on Android](https://github.com/expo/expo/issues/33596),
[expo/expo#36492 background task never executing](https://github.com/expo/expo/issues/36492).
