Skip to content

useOTAUpdates Hook

Access OTA update state and actions from any component within the provider.

Basic Usage

tsx
import { useOTAUpdates } from '@ddedic/expo-fancy-ota-updates';

function MyComponent() {
  const { status, checkForUpdate, downloadUpdate, isUpdateAvailable } = useOTAUpdates();

  return (
    <View>
      <Button
        title={status === 'checking' ? 'Checking...' : 'Check for Updates'}
        onPress={checkForUpdate}
        disabled={status === 'checking'}
      />
      {isUpdateAvailable && (
        <Button title="Download Update" onPress={downloadUpdate} />
      )}
    </View>
  );
}

Return Value

State

PropertyTypeDescription
isUpdateAvailablebooleanUpdate available to download
isDownloadingbooleanCurrently downloading
isDownloadedbooleanDownload complete, ready to apply
statusUpdateStatusCurrent status
checkErrorError | nullCheck error if any
downloadErrorError | nullDownload error if any
lastCheckDate | nullLast check timestamp
lastSkippedReasonstring | nullMost recent skip reason (DEV/simulator/throttle/disabled)
isSimulatingbooleanShowing a simulated update banner (for testing)

expo-updates Metadata

PropertyTypeDescription
currentUpdateIdstring | nullCurrent update ID
channelstring | nullUpdate channel
runtimeVersionstring | nullRuntime version
isEmbeddedUpdatebooleanIs embedded build

Channel Switching

PropertyTypeDescription
isSwitchingChannelbooleanChannel switch in progress
switchChannel(channel: string) => Promise<SwitchChannelResult>Switch update channel at runtime

Version Data

PropertyTypeDescription
otaVersionstringVersion (e.g., "1.0.0-production.29")
otaBuildNumbernumberBuild number
otaReleaseDatestringRelease date (ISO)
otaChangelogstring[]Changelog items

Actions

MethodTypeDescription
checkForUpdate() => Promise<CheckResult>Check for updates
downloadUpdate() => Promise<void>Download update
reloadApp() => Promise<void>Reload app
simulateUpdate() => voidSimulate update (dev)
resetSimulation() => voidReset simulation state

Theming

PropertyTypeDescription
themeOTAThemeCurrent theme
translationsOTATranslationsCurrent translations

Types

UpdateStatus

typescript
type UpdateStatus =
  | 'idle'
  | 'checking'
  | 'available'
  | 'downloading'
  | 'downloaded'
  | 'error';

CheckResult

Returned by checkForUpdate():

typescript
interface CheckResult {
  isAvailable: boolean;
  status: UpdateStatus;
  isSkipped?: boolean;  // true when skipped (DEV, simulator, throttled)
  reason?: string;      // why it was skipped
  error?: Error;
  manifest?: any;
}

SwitchChannelResult

Returned by switchChannel():

typescript
interface SwitchChannelResult {
  success: boolean;
  previousChannel: string | null;
  newChannel: string;
  isSkipped?: boolean;
  reason?: string;
  error?: Error;
}

Examples

Manual Check Button

tsx
function CheckButton() {
  const { checkForUpdate, status } = useOTAUpdates();
  
  return (
    <Button
      title={status === 'checking' ? 'Checking...' : 'Check for Updates'}
      onPress={checkForUpdate}
      disabled={status === 'checking'}
    />
  );
}

Handle Skipped Checks

tsx
function CheckButtonWithSkipInfo() {
  const { checkForUpdate, lastSkippedReason } = useOTAUpdates();

  const onCheck = async () => {
    const result = await checkForUpdate();
    if (result.isSkipped) {
      console.log('Skipped:', result.reason);
    }
  };

  return (
    <View>
      <Button title="Check for Updates" onPress={onCheck} />
      {lastSkippedReason && <Text>Last skipped: {lastSkippedReason}</Text>}
    </View>
  );
}

Download Progress

tsx
function DownloadStatus() {
  const { isDownloading, isDownloaded, downloadUpdate } = useOTAUpdates();
  
  if (isDownloading) {
    return <ActivityIndicator />;
  }
  
  if (isDownloaded) {
    return <Text>Update ready! Restart to apply.</Text>;
  }
  
  return <Button title="Download Update" onPress={downloadUpdate} />;
}

Version Display

tsx
function VersionInfo() {
  const { otaVersion, otaBuildNumber, otaReleaseDate } = useOTAUpdates();
  
  return (
    <View>
      <Text>Version: {otaVersion}</Text>
      <Text>Build: {otaBuildNumber}</Text>
      <Text>Released: {new Date(otaReleaseDate).toLocaleDateString()}</Text>
    </View>
  );
}

Error Handling

tsx
function UpdateWithError() {
  const { checkForUpdate, checkError, downloadError } = useOTAUpdates();
  
  const error = checkError || downloadError;
  
  return (
    <View>
      {error && <Text style={{ color: 'red' }}>{error.message}</Text>}
      <Button title="Check for Updates" onPress={checkForUpdate} />
    </View>
  );
}

Channel Surfing (Runtime Channel Switch)

Switch the update channel at runtime — great for letting QA/stakeholders preview updates from other channels without rebuilding. Requires Expo SDK 54+.

tsx
function ChannelPicker() {
  const { channel, isSwitchingChannel, switchChannel } = useOTAUpdates();

  const handleSwitch = async (name: string) => {
    const result = await switchChannel(name);
    if (result.isSkipped) {
      Alert.alert('Skipped', result.reason ?? 'Unknown');
    } else if (result.success) {
      Alert.alert('Switched', `Now on "${result.newChannel}"`);
    }
  };

  return (
    <View>
      <Text>Channel: {channel ?? 'N/A'}</Text>
      {isSwitchingChannel && <ActivityIndicator />}
      <Button title="Production" onPress={() => handleSwitch('production')} />
      <Button title="Staging" onPress={() => handleSwitch('staging')} />
    </View>
  );
}

The method uses the same guard pattern as checkForUpdate — it skips in DEV mode, simulators, and when updates are disabled. See SwitchChannelResult above for the return type.

Simulate Update (Development)

tsx
function DevTools() {
  const { simulateUpdate } = useOTAUpdates();

  if (!__DEV__) return null;

  return (
    <Button
      title="Simulate Update (Dev Only)"
      onPress={simulateUpdate}
    />
  );
}

Next Steps

Want to feel the package end-to-end first? Try the Expo Showcase Demo.

Released under the MIT License.