# Connect your app

Connect the root component, display the running version, then choose when updates activate.

## Connect the root component {#basic}

After [native setup](/docs/getting-started), wrap the root component and use its platform appKey:

```tsx title="Root.tsx"
import { Pakta, UpdateProvider } from 'rn-update';
import App from './App';

const client = new Pakta({
  appKey: 'YOUR_PLATFORM_APP_KEY',
  updateStrategy: 'silentAndLater',
});

export default function Root() {
  return (
    <UpdateProvider client={client}>
      <App />
    </UpdateProvider>
  );
}
```

For a standard RN app, register Root using your existing application name:

```tsx title="index.js"
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import Root from './Root';

AppRegistry.registerComponent(appName, () => Root);
```

For Expo Router, wrap your existing `Stack` or `Slot` in `app/_layout.tsx`. Mount one Provider per process and create the client outside components to avoid repeated initialization.

### Multiple platform keys {#platform-key}

Only add platform selection when shipping multiple platforms. CLI `selectApp` writes each platform's `appId` and `appKey` to `update.json`. Select each application first, then use this in place of the single-platform key:

```tsx title="Read platform configuration"
import { Platform } from 'react-native';
import updateConfig from './update.json';

const platform = Platform.OS;
const configs = updateConfig as Record<string, { appKey: string }>;
const appKey = configs[platform]?.appKey;
if (!appKey) throw new Error(`Missing Pakta appKey for ${platform}`);
```

Imported JSON becomes part of the app bundle. Keep only application identifiers in it, never `PAKTA_API_TOKEN`.

## Display the version {#use-update}

Render this component inside the Provider. An empty `currentHash` indicates the embedded bundle.

```tsx title="UpdateStatus.tsx"
import { Button, Text, View } from 'react-native';
import { useUpdate } from 'rn-update';

export function UpdateStatus() {
  const { packageVersion, currentHash, lastError, checkUpdate } = useUpdate();
  return (
    <View>
      <Text>Pakta demo A</Text>
      <Text>Native: {packageVersion}</Text>
      <Text>Update: {currentHash || 'embedded'}</Text>
      <Button title="Check update" onPress={() => { void checkUpdate(); }} />
      {lastError ? <Text>{lastError.message}</Text> : null}
    </View>
  );
}
```

## Choose when to activate {#update-strategy}

| Strategy | Experience | Use case |
| --- | --- | --- |
| `silentAndLater` | Background download, activation on a later launch | This tutorial and uninterrupted sessions |
| `silentAndNow` | Reload as soon as download completes | Flows where interruption is acceptable |
| `alertUpdateAndIgnoreError` | Prompt for updates, ignore check errors | SDK default |
| `alwaysAlert` | Show updates and errors | Internal diagnosis |

`checkStrategy` defaults to `both` (start and resume). Other values are `onAppStart` and `onAppResume`. `null` disables JS automatic checks; native cold-start checks may still download an update. It does not disable every update capability.

## Manual updates {#manual}

For a custom update button, set `checkStrategy: null` and read these methods inside the Provider:

```tsx
const { client } = useUpdate();

async function onUpdate() {
  if (!client) return;
  const info = await client.checkUpdate();
  if (!info?.update) return;
  const hash = await client.downloadUpdate(info);
  if (hash) await client.switchVersion(hash);
}
```

Disable repeated clicks during the operation and display caught errors. `useUpdateProgress()` returns download progress; progress ranges from 0 to 100 when present.

## Health confirmation and recovery {#health}

The Provider normally confirms health after 1000 ms. If critical initialization takes longer, add these options to the existing client:

```tsx title="Delay health confirmation"
autoMarkSuccessDelayMs: 5000,
healthCheck: () => myCriticalModulesReady(),
```

Implement `myCriticalModulesReady` using your application's readiness conditions. Returning `false` or throwing skips that confirmation. To take full control, use `autoMarkSuccess: false` and call `useUpdate().markSuccess()` once the critical screen is ready.

Native protection can roll back an unconfirmed update after a failed launch. Arbitrary errors after health confirmation do not necessarily trigger rollback. Native recovery still needs network access, valid configuration and an available repair deployment.

## Extensions {#hooks}

- Check, download and reload hooks: [ClientOptions](/docs/api#client-options).
- Test QR codes: `useUpdate().parseTestQrCode(code)`; production builds can set `testChannel: false`. [Test channel](/docs/integration#test-channel).
- Correlate errors with update identity: [Error diagnosis](/docs/errors).

## Test channel {#test-channel}

A test QR code selects a test update; it is separate from the native package's fixed distribution channel. The first tutorial uses a normal default-channel deployment without scanning. Add a scanner only when needed and control which builds permit it.

## Next step {#next}

Keep this Release package and [publish your first update](/docs/publish), changing `Pakta demo A` to `Pakta demo B`.

[Complete button, error and progress example](/docs/api#custom-update).
