---
title: Module API Reference
---

import { CodeBlocksTable } from '~/components/plugins/CodeBlocksTable';
import { APIBox } from '~/components/plugins/APIBox';
import { PlatformTags } from '~/ui/components/Tag';
import { APIMethod } from '~/components/plugins/api/APISectionMethods';

The native modules API is an abstraction layer on top of [JSI](https://reactnative.dev/architecture/glossary#javascript-interfaces-jsi) and other low-level primitives that React Native is built upon. It is built with modern languages (Swift and Kotlin) and provides an easy to use and convenient API that is consistent across platforms where possible.

## Definition Components

As you might have noticed in the snippets on the [Get Started](./get-started.mdx) page, each module class must implement the `definition` function.
The module definition consists of the DSL components that describe the module's functionality and behavior.

<APIBox header="Name">

Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument. Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.

```swift Swift / Kotlin
Name("MyModuleName")
```

</APIBox>
<APIBox header="Constants">

Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.

<CodeBlocksTable>

```swift
// Created from the dictionary
Constants([
  "PI": Double.pi
])

// or returned by the closure
Constants {
  return [
    "PI": Double.pi
  ]
}
```

```kotlin
// Passed as arguments
Constants(
  "PI" to kotlin.math.PI
)

// or returned by the closure
Constants {
  return@Constants mapOf(
    "PI" to kotlin.math.PI
  )
}
```

</CodeBlocksTable>
</APIBox>
<APIBox header="Function">

Defines a native synchronous function that will be exported to JavaScript. Synchronous means that when the function is executed in JavaScript, its native code is run on the same thread and blocks further execution of the script until the native function returns.

#### Arguments

- **name**: `String` — Name of the function that you'll call from JavaScript.
- **body**: `(args...) -> ReturnType` — The closure to run when the function is called.

The function can receive up to 8 arguments. This is due to the limitations of generics in both Swift and Kotlin, because this component must be implemented separately for each arity.

See the [Argument Types](#argument-types) section for more details on what types can be used in the function body.

<CodeBlocksTable>

```swift
Function("syncFunction") { (message: String) in
  return message
}
```

```kotlin
Function("syncFunction") { message: String ->
  return@Function message
}
```

</CodeBlocksTable>

```js JavaScript
import { requireNativeModule } from 'expo-modules-core';

// Assume that we have named the module "MyModule"
const MyModule = requireNativeModule('MyModule');

function getMessage() {
  return MyModule.syncFunction('bar');
}
```

</APIBox>
<APIBox header="AsyncFunction">

Defines a JavaScript function that always returns a `Promise` and whose native code is by default dispatched on the different thread than the JavaScript runtime runs on.

#### Arguments

- **name**: `String` — Name of the function that you'll call from JavaScript.
- **body**: `(args...) -> ReturnType` — The closure to run when the function is called.

If the type of the last argument is `Promise`, the function will wait for the promise to be resolved or rejected before the response is passed back to JavaScript. Otherwise, the function is immediately resolved with the returned value or rejected if it throws an exception.
The function can receive up to 8 arguments (including the promise).

See the [Argument Types](#argument-types) section for more details on what types can be used in the function body.

It is recommended to use `AsyncFunction` over `Function` when it:

- does I/O bound tasks such as sending network requests or interacting with the file system
- needs to be run on different thread, e.g. the main UI thread for UI-related tasks
- is an extensive or long-lasting operation that would block the JavaScript thread which in turn would reduce the responsiveness of the application

<CodeBlocksTable>

```swift
AsyncFunction("asyncFunction") { (message: String, promise: Promise) in
  DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
    promise.resolve(message)
  }
}
```

```kotlin
AsyncFunction("asyncFunction") { message: String, promise: Promise ->
  launch(Dispatchers.Main) {
    promise.resolve(message)
  }
}
```

</CodeBlocksTable>

```js JavaScript
import { requireNativeModule } from 'expo-modules-core';

// Assume that we have named the module "MyModule"
const MyModule = requireNativeModule('MyModule');

async function getMessageAsync() {
  return await MyModule.asyncFunction('bar');
}
```

<hr />

#### Kotlin coroutines <PlatformTags prefix="" platforms={['android']} />

`AsyncFunction` can receive a suspendable body on Android. However, it has to be passed in the infix notation after the `Coroutine` block. You can read more about suspendable functions and coroutines on [coroutine overview](https://kotlinlang.org/docs/coroutines-overview.html).

`AsyncFunction` with suspendable body can't receive `Promise` as an argument. It uses a suspension mechanism to execute asynchronous calls.
The function is immediately resolved with the returned value of the provided suspendable block or rejected if it throws an exception. The function can receive up to 8 arguments.

By default, suspend functions are dispatched on the module's coroutine scope. Moreover, every other suspendable function called from the body block is run within the same scope.
This scope's lifecycle is bound to the module's lifecycle - all unfinished suspend functions will be canceled when the module is deallocated.

```kotlin Kotlin
AsyncFunction("suspendFunction") Coroutine { message: String ->
  launch {
    return@Coroutine message
  }
}
```

</APIBox>
<APIBox header="Events">

Defines event names that the module can send to JavaScript.

> **Note**: This component can be used inside of the [`View`](#view) block to define callback names. See [`View callbacks`](#view-callbacks)

<CodeBlocksTable>

```swift
Events("onCameraReady", "onPictureSaved", "onBarCodeScanned")
```

```kotlin
Events("onCameraReady", "onPictureSaved", "onBarCodeScanned")
```

</CodeBlocksTable>

See [Sending events](#sending-events) to learn how to send events from the native code to JavaScript/TypeScript.

</APIBox>
<APIBox header="ViewManager">

> **warning** **Deprecated**: To better integrate with [React Native's new architecture (Fabric)](https://reactnative.dev/architecture/fabric-renderer) and its recycling mechanism, as of SDK 47 the `ViewManager` component is deprecated in favor of [`View`](#view) with a view class passed as the first argument. This component will be removed in SDK 48.

Enables the module to be used as a view manager. The view manager definition is built from the definition components used in the closure passed to `ViewManager`. Definition components that are accepted as part of the view manager definition: [`View`](#view), [`Prop`](#prop).

<CodeBlocksTable>

```swift
ViewManager {
  View {
    MyNativeView()
  }

  Prop("isHidden") { (view: UIView, hidden: Bool) in
    view.isHidden = hidden
  }
}
```

```kotlin
ViewManager {
  View { context ->
    MyNativeView(context)
  }

  Prop("isHidden") { view: View, hidden: Bool ->
    view.isVisible = !hidden
  }
}
```

</CodeBlocksTable>
</APIBox>
<APIBox header="View">

Enables the module to be used as a native view. Definition components that are accepted as part of the view definition: [`Prop`](#prop), [`Events`](#events).

#### Arguments

- **viewType** — The class of the native view that will be rendered. Note: On Android, the provided class must inherit from the [`ExpoView`](#expoview), on iOS it's optional. See [`Extending ExpoView`](#extending--expoview).
- **definition**: `() -> ViewDefinition` — A builder of the view definition.

<CodeBlocksTable>

```swift
View(UITextView.self) {
  Prop("text") { ... }
}
```

```kotlin
View(TextView::class) {
  Prop("text") { ... }
}
```

</CodeBlocksTable>

> Support for rendering SwiftUI views is planned. For now, you can use [`UIHostingController`](https://developer.apple.com/documentation/swiftui/uihostingcontroller) and add its content view to your UIKit view.

</APIBox>
<APIBox header="Prop">

Defines a setter for the view prop of given name.

#### Arguments

- **name**: `String` — Name of view prop that you want to define a setter.
- **setter**: `(view: ViewType, value: ValueType) -> ()` — Closure that is invoked when the view rerenders.

This property can only be used within a [`ViewManager`](#viewmanager) closure.

<CodeBlocksTable>

```swift
Prop("background") { (view: UIView, color: UIColor) in
  view.backgroundColor = color
}
```

```kotlin
Prop("background") { view: View, @ColorInt color: Int ->
  view.setBackgroundColor(color)
}
```

</CodeBlocksTable>

> **Note** Props of function type (callbacks) are not supported yet.

</APIBox>
<APIBox header="OnCreate">

Defines module's lifecycle listener that is called right after module initialization. If you need to set up something when the module gets initialized, use this instead of module's class initializer.

</APIBox>
<APIBox header="OnDestroy">

Defines module's lifecycle listener that is called when the module is about to be deallocated. Use it instead of module's class destructor.

</APIBox>
<APIBox header="OnStartObserving">

Defines the function that is invoked when the first event listener is added.

</APIBox>
<APIBox header="OnStopObserving">

Defines the function that is invoked when all event listeners are removed.

</APIBox>
<APIBox header="OnAppContextDestroys">

Defines module's lifecycle listener that is called when the app context owning the module is about to be deallocated.

</APIBox>
<APIBox header="OnAppEntersForeground" platforms={["ios"]}>

Defines the listener that is called when the app is about to enter the foreground mode.

> **Note** This function is not available on Android — you may want to use [`OnActivityEntersForeground`](#onactivityentersforeground) instead.

</APIBox>
<APIBox header="OnAppEntersBackground" platforms={["ios"]}>

Defines the listener that is called when the app enters the background mode.

> **Note** This function is not available on Android — you may want to use [`OnActivityEntersBackground`](#onactivityentersbackground) instead.

</APIBox>
<APIBox header="OnAppBecomesActive" platforms={["ios"]}>

Defines the listener that is called when the app becomes active again (after `OnAppEntersForeground`).

> **Note** This function is not available on Android — you may want to use [`OnActivityEntersForeground`](#onactivityentersforeground) instead.

</APIBox>
<APIBox header="OnActivityEntersForeground" platforms={["android"]}>

Defines the activity lifecycle listener that is called right after the activity is resumed.

> **Note** This function is not available on iOS — you may want to use [`OnAppEntersForeground`](#onappentersforeground) instead.

</APIBox>
<APIBox header="OnActivityEntersBackground" platforms={["android"]}>

Defines the activity lifecycle listener that is called right after the activity is paused.

> **Note** This function is not available on iOS — you may want to use [`OnAppEntersBackground`](#onappentersbackground) instead.

</APIBox>
<APIBox header="OnActivityDestroys" platforms={["android"]}>

Defines the activity lifecycle listener that is called when the activity owning the JavaScript context is about to be destroyed.

> **Note** This function is not available on iOS — you may want to use [`OnAppEntersBackground`](#onappentersbackground) instead.

</APIBox>

## Argument Types

Fundamentally, only primitive and serializable data can be passed back and forth between the runtimes. However, usually native modules need to receive custom data structures — more sophisticated than just the dictionary/map where the values are of unknown (`Any`) type and so each value has to be validated and casted on its own. The Expo Modules API provides protocols to make it more convenient to work with data objects, to provide automatic validation, and finally, to ensure native type-safety on each object member.

<APIBox header="Primitives">

All functions and view prop setters accept all common primitive types in Swift and Kotlin as the arguments. This includes arrays, dictionaries/maps and optionals of these primitive types.

| Language | Supported primitive types                                                                                                      |
| -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Swift    | `Bool`, `Int`, `Int8`, `Int16`, `Int32`, `Int64`, `UInt`, `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Float32`, `Double`, `String` |
| Kotlin   | `Boolean`, `Int`, `UInt`, `Float`, `Double`, `String`, `Pair`                                                                  |

</APIBox>
<APIBox header="Convertibles">

_Convertibles_ are native types that can be initialized from certain specific kinds of data received from JavaScript. Such types are allowed to be used as an argument type in `Function`'s body. For example, when the `CGPoint` type is used as a function argument type, its instance can be created from an array of two numbers `(x, y)` or a JavaScript object with numeric `x` and `y` properties.

Some common iOS types from `CoreGraphics` and `UIKit` system frameworks are already made convertible.

| Native iOS Type         | TypeScript                                                                                                                                                                        |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `URL`                   | `string` with a URL. When scheme is not provided, it's assumed to be a file URL.                                                                                                  |
| `CGFloat`               | `number`                                                                                                                                                                          |
| `CGPoint`               | `{ x: number, y: number }` or `number[]` with _x_ and _y_ coords                                                                                                                  |
| `CGSize`                | `{ width: number, height: number }` or `number[]` with _width_ and _height_                                                                                                       |
| `CGVector`              | `{ dx: number, dy: number }` or `number[]` with _dx_ and _dy_ vector differentials                                                                                                |
| `CGRect`                | `{ x: number, y: number, width: number, height: number }` or `number[]` with _x_, _y_, _width_ and _height_ values                                                                |
| `CGColor`<br/>`UIColor` | Color hex strings (`#RRGGBB`, `#RRGGBBAA`, `#RGB`, `#RGBA`), named colors following the [CSS3/SVG specification](https://www.w3.org/TR/css-color-3/#svg-color) or `"transparent"` |

Similarly, some common Android types from packages like `java.io`, `java.net`, or `android.graphics` are also made convertible.

| Native Android Type                                                           | TypeScript                                                                                                                                                                        |
| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `java.net.URL`                                                                | `string` with a URL. Note that the scheme has to be provided                                                                                                                      |
| `android.net.Uri`<br/>`java.net.URI`                                          | `string` with a URI. Note that the scheme has to be provided                                                                                                                      |
| `java.io.File`<br/>`java.nio.file.Path` (is only available on Android API 26) | `string` with a path to the file                                                                                                                                                  |
| `android.graphics.Color`                                                      | Color hex strings (`#RRGGBB`, `#RRGGBBAA`, `#RGB`, `#RGBA`), named colors following the [CSS3/SVG specification](https://www.w3.org/TR/css-color-3/#svg-color) or `"transparent"` |
| `kotlin.Pair<A, B>`                                                           | Array with two values, where the first one is of type _A_ and the second is of type _B_                                                                                           |

</APIBox>
<APIBox header="Records">

_Record_ is a convertible type and an equivalent of the dictionary (Swift) or map (Kotlin), but represented as a struct where each field can have its own type and provide a default value.
It is a better way to represent a JavaScript object with the native type-safety.

<CodeBlocksTable>

```swift
struct FileReadOptions: Record {
  @Field
  var encoding: String = "utf8"

  @Field
  var position: Int = 0

  @Field
  var length: Int?
}

// Now this record can be used as an argument of the functions or the view prop setters.
Function("readFile") { (path: String, options: FileReadOptions) -> String in
  // Read the file using given `options`
}
```

```kotlin
class FileReadOptions : Record {
  @Field
  val encoding: String = "utf8"

  @Field
  val position: Int = 0

  @Field
  val length: Int?
}

// Now this record can be used as an argument of the functions or the view prop setters.
Function("readFile") { path: String, options: FileReadOptions ->
  // Read the file using given `options`
}
```

</CodeBlocksTable>
</APIBox>
<APIBox header="Enums">

With enums we can go even further with the above example (with `FileReadOptions` record) and limit supported encodings to `"utf8"` and `"base64"`. To use an enum as an argument or record field, it must represent a primitive value (e.g. `String`, `Int`) and conform to `Enumerable`.

<CodeBlocksTable>

```swift
enum FileEncoding: String, Enumerable {
  case utf8
  case base64
}

struct FileReadOptions: Record {
  @Field
  var encoding: FileEncoding = .utf8
  // ...
}
```

```kotlin
// Note: the constructor must have an argument called value.
enum class FileEncoding(val value: String) : Enumerable {
  utf8("utf8"),
  base64("base64")
}

class FileReadOptions : Record {
  @Field
  val encoding: FileEncoding = FileEncoding.utf8
  // ...
}
```

</CodeBlocksTable>
</APIBox>
<APIBox header="Eithers">

There are some use cases where you want to pass various types for a single function argument. This is where Either types might come in handy.
They act as a container for a value of one of a couple of types.

<CodeBlocksTable>

```swift
Function("foo") { (bar: Either<String, Int>) in
  if let bar: String = bar.get() {
    // `bar` is a String
  }
  if let bar: Int = bar.get() {
    // `bar` is an Int
  }
}
```

```kotlin
Function("foo") { bar: Either<String, Int> ->
  bar.get(String::class).let {
    // `it` is a String
  }
  bar.get(Int::class).let {
    // `it` is an Int
  }
}
```

</CodeBlocksTable>

The implementation for three Either types is currently provided out of the box, allowing you to use up to four different subtypes.

- `Either<FirstType, SecondType>` — A container for one of two types.
- `EitherOfThree<FirstType, SecondType, ThirdType>` — A container for one of three types.
- `EitherOfFour<FirstType, SecondType, ThirdType, FourthType>` — A container for one of four types.

> Either types are available as of SDK 47.

</APIBox>

## Native Classes

<APIBox header="Module">

A base class for a native module.

#### Properties

<APIMethod
  name="appContext"
  comment="Provides access to the [`AppContext`](#appcontext)."
  returnTypeName="AppContext"
  isProperty={true}
  isReturnTypeReference={true}
/>

#### Methods

<APIMethod
  name="sendEvent"
  comment="Sends an event with a given name and a payload to JavaScript. See [`Sending events`](#sending-events)"
  returnTypeName="void"
  parameters={[
    {
      name: 'eventName',
      comment: 'The name of the JavaScript event',
      typeName: 'string',
    },
    {
      name: 'payload',
      comment: 'The event payload',
      typeName: 'Android: Map<String, Any?> | Bundle\niOS: [String: Any?]',
    },
  ]}
/>

</APIBox>

<APIBox header="AppContext">

The app context is an interface to a single Expo app.

#### Properties

<APIMethod
  name="constants"
  comment="Provides access to app's constants from legacy module registry."
  returnTypeName="Android: ConstantsInterface? iOS: EXConstantsInterface?"
  isProperty={true}
/>

<APIMethod
  name="permissions"
  comment="Provides access to the permissions manager from legacy module registry."
  returnTypeName="Android: Permissions? iOS: EXPermissionsInterface?"
  isProperty={true}
/>

<APIMethod
  name="imageLoader"
  comment="Provides access to the image loader from the legacy module registry."
  returnTypeName="Android: ImageLoaderInterface? iOS: EXImageLoaderInterface?"
  isProperty={true}
/>

<APIMethod
  name="barcodeScanner"
  comment="Provides access to the bar code scanner manager from the legacy module registry."
  returnTypeName="ImageLoaderInterface?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="camera"
  comment="Provides access to the camera view manager from the legacy module registry."
  returnTypeName="CameraViewInterface?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="font"
  comment="Provides access to the font manager from the legacy module registry."
  returnTypeName="FontManagerInterface?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="sensor"
  comment="Provides access to the sensor manager from the legacy module registry."
  returnTypeName="SensorServiceInterface?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="taskManager"
  comment="Provides access to the task manager from the legacy module registry."
  returnTypeName="TaskManagerInterface?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="activityProvider"
  comment="Provides access to the activity provider from the legacy module registry."
  returnTypeName="ActivityProvider?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="reactContext"
  comment="Provides access to the react application context."
  returnTypeName="Context?"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="hasActiveReactInstance"
  comment="Checks if there is an not-null, alive react native instance."
  returnTypeName="Boolean"
  isProperty={true}
  platforms={['Android']}
/>

<APIMethod
  name="utilities"
  comment="Provides access to the utilities from legacy module registry."
  returnTypeName="EXUtilitiesInterface?"
  isProperty={true}
  platforms={['iOS']}
/>

</APIBox>

<APIBox header="ExpoView">

A base class that should be used by all exported views.

On iOS, `ExpoView` extends the `RCTView` which handles some styles (e.g. borders) and accessibility.

#### Properties

<APIMethod
  name="appContext"
  comment="Provides access to the [`AppContext`](#appcontext)."
  returnTypeName="AppContext"
  isProperty={true}
  isReturnTypeReference={true}
/>

<hr />

#### Extending `ExpoView`

To export your view using the [`View`](#view) component, your custom class must inherit from the `ExpoView`. By doing that you will get access to the [`AppContext`](#appcontext) object. It's the only way of communicating with other modules and the JavaScript runtime. Also, you can't change constructor parameters, because provided view will be initialized by `expo-modules-core`.

<CodeBlocksTable>

```swift
class LinearGradientView: ExpoView {}

public class LinearGradientModule: Module {
  public func definition() -> ModuleDefinition {
    View(LinearGradientView.self) {
      // ...
    }
  }
}
```

```kotlin
class LinearGradientView(
  context: Context,
  appContext: AppContext,
) : ExpoView(context, appContext)

class LinearGradientModule : Module() {
  override fun definition() = ModuleDefinition {
    View(LinearGradientView::class) {
      // ...
    }
  }
}
```

</CodeBlocksTable>

</APIBox>

## Guides

<APIBox header="Sending events">

While JavaScript/TypeScript to Native communication is mostly covered by native functions, you might also want to let the JavaScript/TypeScript code know about certain system events, for example, when the clipboard content changes.

To do this, in the module definition, you need to provide the event names that the module can send using the [Events](#events) definition component. After that, you can use the `sendEvent(eventName, payload)` function on the module instance to send the actual event with some payload. For example, a minimal clipboard implementation that sends native events may look like this:

<CodeBlocksTable>

```swift
let CLIPBOARD_CHANGED_EVENT_NAME = "onClipboardChanged"

public class ClipboardModule: Module {
  public func definition() -> ModuleDefinition {
    Events(CLIPBOARD_CHANGED_EVENT_NAME)

    OnStartObserving {
      NotificationCenter.default.addObserver(
        self,
        selector: #selector(self.clipboardChangedListener),
        name: UIPasteboard.changedNotification,
        object: nil
      )
    }

    OnStopObserving {
      NotificationCenter.default.removeObserver(
        self,
        name: UIPasteboard.changedNotification,
        object: nil
      )
    }
  }

  @objc
  private func clipboardChangedListener() {
    sendEvent(CLIPBOARD_CHANGED_EVENT_NAME, [
      "contentTypes": availableContentTypes()
    ])
  }
}
```

```kotlin
const val CLIPBOARD_CHANGED_EVENT_NAME = "onClipboardChanged"

class ClipboardModule : Module() {
  override fun definition() = ModuleDefinition {
    Events(CLIPBOARD_CHANGED_EVENT_NAME)

    OnStartObserving {
      clipboardManager?.addPrimaryClipChangedListener(listener)
    }

    OnStopObserving {
      clipboardManager?.removePrimaryClipChangedListener(listener)
    }
  }

  private val clipboardManager: ClipboardManager?
    get() = appContext.reactContext?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager

  private val listener = ClipboardManager.OnPrimaryClipChangedListener {
    clipboardManager?.primaryClipDescription?.let { clip ->
      this@ClipboardModule.sendEvent(
        CLIPBOARD_CHANGED_EVENT_NAME,
        bundleOf(
          "contentTypes" to availableContentTypes(clip)
        )
      )
    }
  }
}
```

</CodeBlocksTable>

To subscribe to these events in JavaScript/TypeScript, you need to wrap the native module with `EventEmitter` class as shown:

```ts TypeScript
import { requireNativeModule, EventEmitter, Subscription } from 'expo-modules-core';

const ClipboardModule = requireNativeModule('Clipboard');
const emitter = new EventEmitter(ClipboardModule);

export function addClipboardListener(listener: (event) => void): Subscription {
  return emitter.addListener('onClipboardChanged', listener);
}
```

</APIBox>

<APIBox header="View callbacks">

Some events are connected to a certain view. For example, the touch event should be sent only to the underlying JavaScript view which was pressed. In that case, you can't use `sendEvent` described in [`Sending events`](#sending-events). The `expo-modules-core` introduces a view callbacks mechanism to handle view-bound events.

To use it, in the view definition, you need to provide the event names that the view can send using the [Events](#events) definition component. After that, you need to declare a property of type `EventDispatcher` in your view class. The name of the declared property has to be the same as the name exported in the `Events` component. Later, you can call it as a function and pass a payload of type `[String: Any?]` on iOS and `Map<String, Any?>` on Android.

> **Note**: On Android, it's possible to specify the payload type. In case of types that don't convert into objects, the payload will be encapsulated and stored under the `payload` key: `{payload: <provided value>}`.

<CodeBlocksTable>

```swift
class CameraViewModule: Module {
  public func definition() -> ModuleDefinition {
    View(CamerView.self) {
      Events(
        "onCameraReady"
      )

      // ...
    }
  }
}

class CameraView: ExpoView {
  let onCameraReady = EventDispatcher()

  func callOnCameraReady() {
    onCameraReady([
      "message": "Camera was mounted"
    ]);
  }
}
```

```kotlin
class CameraViewModule : Module() {
  override fun definition() = ModuleDefinition {
    View(ExpoCameraView::class) {
      Events(
        "onCameraReady"
      )

      // ...
    }
  }
}

class CameraView(
  context: Context,
  appContext: AppContext
) : ExpoView(context, appContext) {
  val onCameraReady by EventDispatcher()

  fun callOnCameraReady() {
    onCameraReady(mapOf(
      "message" to "Camera was mounted"
    ));
  }
}
```

</CodeBlocksTable>

To subscribe to these events in JavaScript/TypeScript, you need to pass a function to the native view as shown:

```ts TypeScript
import { requireNativeViewManager } from 'expo-modules-core';

const CameraView = requireNativeViewManager('CameraView');

export default function MainView() {
  const onCameraReady = event => {
    console.log(event.nativeEvent);
  };

  return <CameraView onCameraReady={onCameraReady} />;
}
```

Provided payload is available under the `nativeEvent` key.

</APIBox>

## Examples

<CodeBlocksTable>

```swift
public class MyModule: Module {
  public func definition() -> ModuleDefinition {
    Name("MyFirstExpoModule")

    Function("hello") { (name: String) in
      return "Hello \(name)!"
    }
  }
}
```

```kotlin
class MyModule : Module() {
  override fun definition() = ModuleDefinition {
    Name("MyFirstExpoModule")

    Function("hello") { name: String ->
      return "Hello $name!"
    }
  }
}
```

</CodeBlocksTable>

For more examples from real modules, you can refer to Expo modules that already use this API on GitHub:

- `expo-battery` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-battery/ios))
- `expo-cellular` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-cellular/ios), [Kotlin](https://github.com/expo/expo/tree/main/packages/expo-cellular/android/src/main/java/expo/modules/cellular))
- `expo-clipboard` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-clipboard/ios), [Kotlin](https://github.com/expo/expo/tree/main/packages/expo-clipboard/android/src/main/java/expo/modules/clipboard))
- `expo-crypto` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-crypto/ios), [Kotlin](https://github.com/expo/expo/tree/main/packages/expo-crypto/android/src/main/java/expo/modules/crypto))
- `expo-haptics` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-haptics/ios))
- `expo-image-manipulator` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-image-manipulator/ios))
- `expo-image-picker` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-image-picker/ios), [Kotlin](https://github.com/expo/expo/tree/main/packages/expo-image-picker/android/src/main/java/expo/modules/imagepicker))
- `expo-linear-gradient` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-linear-gradient/ios), [Kotlin](https://github.com/expo/expo/tree/main/packages/expo-linear-gradient/android/src/main/java/expo/modules/lineargradient))
- `expo-localization` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-localization/ios), [Kotlin](https://github.com/expo/expo/tree/main/packages/expo-localization/android/src/main/java/expo/modules/localization))
- `expo-store-review` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-store-review/ios))
- `expo-system-ui` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-system-ui/ios/ExpoSystemUI))
- `expo-video-thumbnails` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-video-thumbnails/ios))
- `expo-web-browser` ([Swift](https://github.com/expo/expo/blob/main/packages/expo-web-browser/ios), [Kotlin](https://github.com/expo/expo/blob/main/packages/expo-web-browser/android/src/main/java/expo/modules/webbrowser))
