# App shell and providers

Canonical page: https://docs.ovok.com/native-sdk/guide/how-to/app-shell

The app shell creates one native `Ovok` client and makes it available to routes that use the
SDK. Provider ownership is explicit: `@ovok/core/next/react` supplies the client context,
`@ovok/native` supplies the mobile UI theme and feature components, and your app
supplies navigation and any app-wide services.

Use this page after [installation and native setup](/native-sdk/guide/how-to/installation). For a minimal
working sign-in app, follow the [quick start](/native-sdk/guide/getting-started); this guide explains
where each provider belongs as the app grows.

## Provider tree [#provider-tree]

For an Expo Router app, a typical root looks like this:

```text
KeyboardProvider
└── GestureHandlerRootView
    └── OvokProvider                 @ovok/core/next/react
        └── ThemeProvider            @ovok/native
            └── BottomSheetModalProvider  optional peer provider
                └── Navigation ThemeProvider
                    └── App routes
```

Add optional app providers, such as query-cache persistence or localization, where
their context is needed. Keep feature providers close to the routes that use them;
Bluetooth scans and health authorization should not start just because the app shell
mounted.

## Initialize the client outside React renders [#initialize-the-client-outside-react-renders]

Initialize the runtime from the entry module before importing this layout, as shown
in [Polyfills and runtime setup](/native-sdk/guide/components/polyfills/). This example assumes
that bootstrap has already run. Keep the client at module scope so a route render
does not recreate its identity or secure session storage.

Put the initializer in a module such as `ovok-client.ts`; have the root layout and
other app services import that same client instance.

```tsx
import { Ovok } from "@ovok/native/next";
import * as SecureStore from "expo-secure-store";

const baseUrl = process.env.EXPO_PUBLIC_OVOK_BASE_URL;
const tenantCode = process.env.EXPO_PUBLIC_TENANT_CODE;
if (!baseUrl || !tenantCode) {
  throw new Error("Set EXPO_PUBLIC_OVOK_BASE_URL and EXPO_PUBLIC_TENANT_CODE");
}

export const ovokClient = new Ovok({
  baseUrl,
  tenantCode,
  secureStore: SecureStore,
});
```

Use your app's environment setup for `baseUrl` and optional client configuration.
Expo embeds `EXPO_PUBLIC_` values in the app bundle, so they are suitable for public
configuration only. See [Installation](/native-sdk/guide/how-to/installation) for native dependencies and
[Authentication](/native-sdk/guide/modules/auth) for session behavior.

## Compose the Expo Router root [#compose-the-expo-router-root]

This example follows the provider boundaries used by the reference app. The SDK
theme is separate from the navigation theme, even when both use the same brand
palette.

```tsx
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import { OvokProvider } from "@ovok/core/next/react";
import {
  DEFAULT_COLORS,
  DEFAULT_MULTIPLIERS,
  ThemeProvider as OvokThemeProvider,
} from "@ovok/native";
import {
  DefaultTheme,
  Stack,
  ThemeProvider as NavigationThemeProvider,
} from "expo-router";
import type { PropsWithChildren } from "react";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { KeyboardProvider } from "react-native-keyboard-controller";

import { ovokClient } from "./ovok-client";

function SdkProviders({ children }: PropsWithChildren) {
  return (
    <OvokProvider client={ovokClient}>
      <OvokThemeProvider
        theme={{
          colors: DEFAULT_COLORS,
          dark: false,
          spacingMultiplier: DEFAULT_MULTIPLIERS.spacing,
          borderRadiusMultiplier: DEFAULT_MULTIPLIERS.borderRadius,
        }}
      >
        <BottomSheetModalProvider>
          <NavigationThemeProvider value={DefaultTheme}>
            {children}
          </NavigationThemeProvider>
        </BottomSheetModalProvider>
      </OvokThemeProvider>
    </OvokProvider>
  );
}

export default function RootLayout() {
  return (
    <KeyboardProvider>
      <GestureHandlerRootView style={{ flex: 1 }}>
        <SdkProviders>
          <Stack />
        </SdkProviders>
      </GestureHandlerRootView>
    </KeyboardProvider>
  );
}
```

`OvokProvider` is exported by `@ovok/core/next/react`; the SDK `ThemeProvider` is exported by
`@ovok/native`. Rename the latter on import when using another provider with the same
name. `BottomSheetModalProvider` is imported directly from `@gorhom/bottom-sheet`;
mount it once when a screen uses SDK bottom sheets such as `PickerSheet` or
`DataSync.ManuallyRequestSheet`.

If you use `SafeAreaProvider`, a persisted query client, localization, error
reporting, or app configuration context, add those providers where their hooks and
components need them. The reference app places `GestureHandlerRootView` around
navigation and uses the keyboard provider above it.

## Configure the SDK theme [#configure-the-sdk-theme]

`ThemeProvider` applies the React Native Paper theme, loads the bundled DM Sans
fonts, and provides device-list context used by the supported-device UI. Its `theme`
prop contains:

| Property | Purpose |
| --- | --- |
| `colors` | Paper colors plus the SDK's semantic and indexed color palette; start with `DEFAULT_COLORS` and override values your app uses. |
| `dark` | Whether the SDK theme is in dark mode. |
| `spacingMultiplier` | Spacing scale; `DEFAULT_MULTIPLIERS.spacing` is the baseline. |
| `borderRadiusMultiplier` | Corner-radius scale; `DEFAULT_MULTIPLIERS.borderRadius` is the baseline. |

Read the active theme with `useAppTheme`. Navigation has its own color shape and
must receive a navigation theme separately; map the brand colors to navigation's
`primary`, `background`, `card`, `text`, `border`, and `notification` values rather
than passing the SDK color object directly.

The SDK theme provider returns `null` while its fonts load. Account for that initial
render in the app's launch experience; the provider does not accept a loading
fallback prop.

## Place feature providers near their screens [#place-feature-providers-near-their-screens]

Mount these providers only for flows that use them:

| Provider | Place it | What to keep in mind |
| --- | --- | --- |
| `BTProvider` | Around the Bluetooth screen or flow | Pass a long-lived `BleManager` and the accepted device declarations. Unmounting stops the provider-owned scan and tears down its managed devices. |
| `DataSync.AppleHealthAuthorizationProvider` | Around the iOS Health import screen | Request only the HealthKit identifiers the feature reads or writes. |
| `DataSync.AndroidHealthConnectAuthorizationProvider` | Around the Android Health Connect screen | Declare platform record permissions in native app configuration as well as in the authorization flow. |
| `SocketProvider` | Around screens that use socket context | Keep the URL, authentication policy, subscriptions, and reconnect UX app-owned. |

Do not mount Bluetooth or health import providers globally unless the product
intentionally keeps that workflow active across every route. See the [Bluetooth
guide](/native-sdk/guide/modules/bt-management), [Health data guide](/native-sdk/guide/modules/data-sync), and [Background sync](/native-sdk/guide/modules/background-sync)
for lifecycle and platform details.

## Context requirements [#context-requirements]

Render SDK features below the providers they use:

- `OvokProvider`: authentication forms and account controls, patient and observation
  features that use the active client or patient, data-sync components, socket
  context, questionnaire submission helpers, and result handlers that use the
  client.
- `ThemeProvider`: components that call `useAppTheme`, the device catalog list, and
  themed SDK UI.
- `BottomSheetModalProvider`: SDK components that open a Gorhom bottom-sheet modal.
- `KeyboardProvider`: keyboard-aware forms that use `react-native-keyboard-controller`.

When a component renders without expected data, check its provider ancestry and the
current authentication or patient state before changing its props. See
[Architecture and lifecycle](/native-sdk/guide/architecture) for the responsibilities of each
boundary.
