# expo-updates-interface

> Native interface for modules that optionally depend on expo-updates, e.g. expo-dev-launcher.

Latest version **57.0.1** (published 2026-07-15) · MIT license · 0 weekly downloads

## Install

```sh
npm install expo-updates-interface
pnpm add expo-updates-interface
yarn add expo-updates-interface
bun add expo-updates-interface
```

## Health

**Score 65/100 (B)** — status: active.

Positive: no vulnerabilities; recently updated; high maintenance score; popular repo; extremely popular.

Warnings: low downloads; no types; no esm support.

## Facts

| | |
|---|---|
| Version | 57.0.1 |
| Published | 2026-07-15 |
| First published | 2021-05-28 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 51851 |
| Author | 650 Industries, Inc. |
| Maintainers | ide, brentvatne, expoadmin, exponent, bycedric, kudochien, alanhughes, tsapeta, expo-bot, philpl, ccheever, wschurman |
| Keywords | react-native, expo, expo-updates-interface |

## Links

- npm: https://www.npmjs.com/package/expo-updates-interface
- Repository: https://github.com/expo/expo
- Homepage: https://docs.expo.dev
- Issues: https://github.com/expo/expo/issues
- npm.io page: https://npm.io/package/expo-updates-interface

## Recent versions

- 57.0.1 (latest) — 2026-07-15
- 57.0.2 (sdk-57) — 2026-09-11
- 58.0.0 (next) — 2026-09-10
- 58.0.0-canary-20260909-ea7a89a (canary) — 2026-09-09
- 56.0.3-canary-20260701-9100865 (canary-sdk-56) — 2026-07-01
- 55.1.4-canary-20260429-a5e59cf (canary-sdk-55) — 2026-04-29
- 0.16.2 (sdk-51) — 2024-05-09
- 0.15.3 (sdk-50) — 2024-01-18
- 58.0.0-canary-20260908-e343e6e — 2026-09-08
- 58.0.0-canary-20260902-26df09e — 2026-09-02
- 58.0.0-canary-20260901-2164f24 — 2026-09-02
- 58.0.0-canary-20260812-27f94d4 — 2026-08-12
- 58.0.0-canary-20260806-8c2d007 — 2026-08-06
- 58.0.0-canary-20260805-ccd18b9 — 2026-08-05
- 57.0.0-canary-20260723-64edab9 — 2026-07-23
- … 197 more at https://npm.io/package/expo-updates-interface/versions

## README

# expo-updates-interface

Native interface for modules that optionally depend on expo-updates. This package provides a unified native API (iOS and Android) for querying the state of the updates system and subscribing to state machine transitions, without requiring a direct dependency on `expo-updates`.

## Overview

`expo-updates-interface` defines two levels of interface:

- **`UpdatesInterface`** -- implemented by all updates controllers (enabled, disabled, and dev-launcher). Provides read-only properties describing the running update and a method to subscribe to state machine changes.
- **`UpdatesDevLauncherInterface`** -- extends `UpdatesInterface` with additional methods used exclusively by `expo-dev-launcher` to fetch updates and manage the update lifecycle.

A singleton **`UpdatesControllerRegistry`** provides access to the active controller that implements one or both of the above interfaces.

## API documentation

### UpdatesControllerRegistry

The registry provides the active updates controller as a weak reference, in the `controller` property. The reference will be null when `expo-updates` is not installed and compiled into the app. If `expo-updates` is present, the property is set automatically at startup.

| Platform    | Access                                                |
| ----------- | ----------------------------------------------------- |
| **iOS**     | `UpdatesControllerRegistry.sharedInstance.controller` |
| **Android** | `UpdatesControllerRegistry.controller?.get()`         |

### UpdatesInterface

All updates controllers implement this interface. It is available whether updates is enabled, disabled, or running under the dev client.

#### Properties

| Property                                  | Type               | Description                                                                                                   |
| ----------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------- |
| `isEnabled`                               | `Bool` / `Boolean` | Whether the updates system is enabled. Defaults to `false` when updates is disabled.                          |
| `runtimeVersion`                          | `String?`          | The runtime version of the running app. Set when updates is enabled or the dev client is running.             |
| `updateURL` (iOS) / `updateUrl` (Android) | `URL?` / `Uri?`    | The update URL configured for this app. Set when updates is enabled or the dev client is running.             |
| `launchedUpdateId`                        | `UUID?`            | The ID of the currently running update. Only set when updates is enabled.                                     |
| `embeddedUpdateId`                        | `UUID?`            | The ID of the update embedded in the app binary. Only set when updates is enabled.                            |
| `launchAssetPath`                         | `String?`          | The local file path of the launch asset (JS bundle) for the running update. Only set when updates is enabled. |

#### Methods

##### `subscribeToUpdatesStateChanges`

Registers a listener that will be called on updates state machine transitions. Returns a subscription object that can be used to unsubscribe.

**iOS:**

```swift
func subscribeToUpdatesStateChanges(_ listener: any UpdatesStateChangeListener) -> UpdatesStateChangeSubscription
```

**Android (Kotlin):**

```kotlin
fun subscribeToUpdatesStateChanges(listener: UpdatesStateChangeListener): UpdatesStateChangeSubscription
```

### UpdatesStateChangeListener

A listener protocol/interface that receives state machine transition events.

**iOS:**

```swift
public protocol UpdatesStateChangeListener {
  func updatesStateDidChange(_ event: [String: Any])
}
```

**Android (Kotlin):**

```kotlin
interface UpdatesStateChangeListener {
  fun updatesStateDidChange(event: Map<String, Any>)
}
```

The `event` dictionary contains information about the state transition, matching the structure of the updates state machine events exposed by the `expo-updates` JS API.

### UpdatesStateChangeSubscription

Returned by `subscribeToUpdatesStateChanges`. Provides methods to unsubscribe from state change events and to read the current state machine context.

#### `remove()`

Call to unsubscribe and stop receiving state change events.

#### `getContext()`

Returns a read-only snapshot of the current state machine context as an `UpdatesNativeInterfaceStateContext` instance (returned as `Any?` on iOS for Objective-C compatibility). This allows querying the state of the updates system at any time, including information about events that occurred at startup before any state change listener was registered.

**iOS:**

```swift
public protocol UpdatesStateChangeSubscription {
  func remove()
  func getContext() -> Any?
}
```

**Android (Kotlin):**

```kotlin
interface UpdatesStateChangeSubscription {
  fun remove()
  fun getContext(): Any?
}
```

### UpdatesNativeInterfaceStateContext

A read-only data structure exposing the state machine context through the native interface. Returned by `UpdatesStateChangeSubscription.getContext()`.

| Property                | Type                      | Description                                                                                                        |
| ----------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `isUpdateAvailable`     | `Bool` / `Boolean`        | Whether an update is available for download.                                                                       |
| `isUpdatePending`       | `Bool` / `Boolean`        | Whether a downloaded update is pending (waiting for a restart to launch).                                          |
| `isChecking`            | `Bool` / `Boolean`        | Whether the system is currently checking for an update.                                                            |
| `isDownloading`         | `Bool` / `Boolean`        | Whether the system is currently downloading an update.                                                             |
| `isRestarting`          | `Bool` / `Boolean`        | Whether the app is currently restarting.                                                                           |
| `restartCount`          | `Int`                     | The number of restarts that have occurred.                                                                         |
| `latestManifest`        | `[String: Any]?` / `Map?` | The manifest of the latest available update, if any.                                                               |
| `downloadedManifest`    | `[String: Any]?` / `Map?` | The manifest of the most recently downloaded update, if any.                                                       |
| `rollback`              | `Rollback?`               | If a rollback is available, contains the rollback commit time.                                                     |
| `checkError`            | `[String: String]?` / `Map?` | Error information from the most recent update check, if it failed.                                              |
| `downloadError`         | `[String: String]?` / `Map?` | Error information from the most recent update download, if it failed.                                           |
| `downloadProgress`      | `Double`                  | The download progress of the current update download (0.0 to 1.0).                                                |
| `lastCheckForUpdateTime`| `Date?`                   | The time of the most recent update check.                                                                          |
| `sequenceNumber`        | `Int`                     | A monotonically increasing number tracking state transitions.                                                      |
| `downloadStartTime`     | `Date?`                   | The time when the most recent successful update download started. Only non-null after a `downloadCompleteWithUpdate` event. |
| `downloadFinishTime`    | `Date?`                   | The time when the most recent successful update download finished. Only non-null after a `downloadCompleteWithUpdate` event. |

### UpdatesDevLauncherInterface

Extends `UpdatesInterface` with methods used by `expo-dev-launcher` to fetch and manage updates. This interface is only implemented by the dev-launcher updates controller.

See the source files for the full method signatures:

- **iOS:** [`UpdatesInterface.swift`](ios/EXUpdatesInterface/UpdatesInterface.swift)
- **Android:** [`UpdatesInterface.kt`](android/src/main/java/expo/modules/updatesinterface/UpdatesInterface.kt)

## Usage example

### Reading update information (Kotlin)

```kotlin
import expo.modules.updatesinterface.UpdatesControllerRegistry

val controller = UpdatesControllerRegistry.controller?.get()
if (controller != null && controller.isEnabled) {
  val updateId = controller.launchedUpdateId
  val runtimeVersion = controller.runtimeVersion
  // ...
}
```

### Reading update information (Swift)

```swift
import EXUpdatesInterface

if let controller = UpdatesControllerRegistry.sharedInstance.controller,
   controller.isEnabled {
  let updateId = controller.launchedUpdateId
  let runtimeVersion = controller.runtimeVersion
  // ...
}
```

### Subscribing to state changes (Kotlin)

```kotlin
import expo.modules.updatesinterface.UpdatesControllerRegistry
import expo.modules.updatesinterface.UpdatesStateChangeListener
import expo.modules.updatesinterface.UpdatesStateChangeSubscription
import expo.modules.updatesinterface.UpdatesNativeInterfaceStateContext

val controller = UpdatesControllerRegistry.controller?.get() ?: return

val subscription = controller.subscribeToUpdatesStateChanges(object : UpdatesStateChangeListener {
  override fun updatesStateDidChange(event: Map<String, Any>) {
    // Handle state change event
  }
})

// Read the current state context at any time:
val context = subscription.getContext() as? UpdatesNativeInterfaceStateContext
if (context != null) {
  val isDownloading = context.isDownloading
  val downloadStart = context.downloadStartTime
  val downloadFinish = context.downloadFinishTime
  // ...
}

// Later, to unsubscribe:
subscription.remove()
```

### Subscribing to state changes (Swift)

```swift
import EXUpdatesInterface

class MyListener: NSObject, UpdatesStateChangeListener {
  func updatesStateDidChange(_ event: [String: Any]) {
    // Handle state change event
  }
}

let listener = MyListener()
if let controller = UpdatesControllerRegistry.sharedInstance.controller {
  let subscription = controller.subscribeToUpdatesStateChanges(listener)

  // Read the current state context at any time:
  if let context = subscription.getContext() as? UpdatesNativeInterfaceStateContext {
    let isDownloading = context.isDownloading
    let downloadStart = context.downloadStartTime
    let downloadFinish = context.downloadFinishTime
    // ...
  }

  // Later, to unsubscribe:
  subscription.remove()
}
```

## Installation in an Expo native module

- The `expo-updates-interface` package should be added to the module's NPM dependencies. (The `expo-updates` package does not need to be added.)
- The module's iOS podspec should have "EXUpdatesInterface" added to the pod dependencies, as in this example:

```ruby
Pod::Spec.new do |s|
  s.name           = 'InterfaceDemo'
  s.version        = '1.0.0'
  s.platforms      = {
    :ios => '15.1',
    :tvos => '15.1'
  }
  s.static_framework = true

  s.dependency 'ExpoModulesCore'
  s.dependency 'EXUpdatesInterface'

  # Swift/Objective-C compatibility
  s.pod_target_xcconfig = {
    'DEFINES_MODULE' => 'YES',
  }

  s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
end
```

- The module's Android `build.gradle` should have this package added as a dependency, as in this example:

```gradle
android {
  namespace "expo.modules.interfacedemo"
  defaultConfig {
    versionCode 1
    versionName "0.7.6"
  }
  lintOptions {
    abortOnError false
  }
}

dependencies {
  implementation project(':expo-updates-interface')
}
```

## Installation in managed Expo projects

This package is included as a dependency of `expo-updates` and `expo-dev-client`. No separate installation is needed.

## Installation in bare React Native projects

This package is included as a dependency of `expo-updates` and `expo-dev-client`. If you need to install it separately:

```sh
npx expo install expo-updates-interface
```

## Contributing

Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).

---
_Source: https://npm.io/package/expo-updates-interface · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
