xref: /expo/docs/pages/modules/module-api.mdx (revision a16ac082)
1e98c3cdfSJon Samp---
2c3ab6167SBrent Vatnetitle: Module API Reference
34d2795ecSAman Mittaldescription: An API reference of Expo modules API.
4683e8eb4SAman Mittalsidebar_title: Module API
5e98c3cdfSJon Samp---
6e98c3cdfSJon Samp
7e98c3cdfSJon Sampimport { CodeBlocksTable } from '~/components/plugins/CodeBlocksTable';
8e98c3cdfSJon Sampimport { APIBox } from '~/components/plugins/APIBox';
906c01802SŁukasz Kosmatyimport { PlatformTags } from '~/ui/components/Tag';
10adede39aSŁukasz Kosmatyimport { APIMethod } from '~/components/plugins/api/APISectionMethods';
11e98c3cdfSJon Samp
12*a16ac082SAman MittalThe 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.
13e98c3cdfSJon Samp
14*a16ac082SAman Mittal## Definition components
15e98c3cdfSJon Samp
16*a16ac082SAman MittalAs you might have noticed in the snippets on the [Get Started](/modules/get-started) page, each module class must implement the `definition` function.
17d9f7814cSTomasz SapetaThe module definition consists of the DSL components that describe the module's functionality and behavior.
18e98c3cdfSJon Samp
19e98c3cdfSJon Samp<APIBox header="Name">
20e98c3cdfSJon Samp
21*a16ac082SAman MittalSets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument. This can be inferred from the module's class name, but it's recommended to set it explicitly for clarity.
22e98c3cdfSJon Samp
23448dd81eSBartosz Kaszubowski```swift Swift / Kotlin
24e98c3cdfSJon SampName("MyModuleName")
25e98c3cdfSJon Samp```
26e98c3cdfSJon Samp
27e98c3cdfSJon Samp</APIBox>
28e98c3cdfSJon Samp<APIBox header="Constants">
29e98c3cdfSJon Samp
30e98c3cdfSJon SampSets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
31e98c3cdfSJon Samp
32e98c3cdfSJon Samp<CodeBlocksTable>
33e98c3cdfSJon Samp
34e98c3cdfSJon Samp```swift
35e98c3cdfSJon Samp// Created from the dictionary
36e98c3cdfSJon SampConstants([
37e98c3cdfSJon Samp  "PI": Double.pi
38e98c3cdfSJon Samp])
39e98c3cdfSJon Samp
40e98c3cdfSJon Samp// or returned by the closure
41e98c3cdfSJon SampConstants {
42e98c3cdfSJon Samp  return [
43e98c3cdfSJon Samp    "PI": Double.pi
44e98c3cdfSJon Samp  ]
45e98c3cdfSJon Samp}
46e98c3cdfSJon Samp```
47e98c3cdfSJon Samp
48e98c3cdfSJon Samp```kotlin
49e98c3cdfSJon Samp// Passed as arguments
50e98c3cdfSJon SampConstants(
51e98c3cdfSJon Samp  "PI" to kotlin.math.PI
52e98c3cdfSJon Samp)
53e98c3cdfSJon Samp
54e98c3cdfSJon Samp// or returned by the closure
55e98c3cdfSJon SampConstants {
56e98c3cdfSJon Samp  return@Constants mapOf(
57e98c3cdfSJon Samp    "PI" to kotlin.math.PI
58e98c3cdfSJon Samp  )
59e98c3cdfSJon Samp}
60e98c3cdfSJon Samp```
61e98c3cdfSJon Samp
62e98c3cdfSJon Samp</CodeBlocksTable>
63e98c3cdfSJon Samp</APIBox>
64e98c3cdfSJon Samp<APIBox header="Function">
65e98c3cdfSJon Samp
66e98c3cdfSJon SampDefines 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.
67e98c3cdfSJon Samp
68e98c3cdfSJon Samp#### Arguments
69e98c3cdfSJon Samp
70e98c3cdfSJon Samp- **name**: `String` — Name of the function that you'll call from JavaScript.
71e98c3cdfSJon Samp- **body**: `(args...) -> ReturnType` — The closure to run when the function is called.
72e98c3cdfSJon Samp
73*a16ac082SAman MittalThe 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.
74e98c3cdfSJon Samp
75*a16ac082SAman MittalSee the [Argument types](#argument-types) section for more details on what types can be used in the function body.
76e98c3cdfSJon Samp
77e98c3cdfSJon Samp<CodeBlocksTable>
78e98c3cdfSJon Samp
79e98c3cdfSJon Samp```swift
80e98c3cdfSJon SampFunction("syncFunction") { (message: String) in
81e98c3cdfSJon Samp  return message
82e98c3cdfSJon Samp}
83e98c3cdfSJon Samp```
84e98c3cdfSJon Samp
85e98c3cdfSJon Samp```kotlin
86e98c3cdfSJon SampFunction("syncFunction") { message: String ->
87e98c3cdfSJon Samp  return@Function message
88e98c3cdfSJon Samp}
89e98c3cdfSJon Samp```
90e98c3cdfSJon Samp
91448dd81eSBartosz Kaszubowski</CodeBlocksTable>
92448dd81eSBartosz Kaszubowski
93448dd81eSBartosz Kaszubowski```js JavaScript
94e98c3cdfSJon Sampimport { requireNativeModule } from 'expo-modules-core';
95e98c3cdfSJon Samp
96e98c3cdfSJon Samp// Assume that we have named the module "MyModule"
97e98c3cdfSJon Sampconst MyModule = requireNativeModule('MyModule');
98e98c3cdfSJon Samp
99e98c3cdfSJon Sampfunction getMessage() {
100e98c3cdfSJon Samp  return MyModule.syncFunction('bar');
101e98c3cdfSJon Samp}
102e98c3cdfSJon Samp```
103e98c3cdfSJon Samp
104e98c3cdfSJon Samp</APIBox>
105e98c3cdfSJon Samp<APIBox header="AsyncFunction">
106e98c3cdfSJon Samp
107*a16ac082SAman MittalDefines a JavaScript function that always returns a `Promise` and whose native code is by default dispatched on a different thread than the JavaScript runtime runs on.
108e98c3cdfSJon Samp
109e98c3cdfSJon Samp#### Arguments
110e98c3cdfSJon Samp
111e98c3cdfSJon Samp- **name**: `String` — Name of the function that you'll call from JavaScript.
112e98c3cdfSJon Samp- **body**: `(args...) -> ReturnType` — The closure to run when the function is called.
113e98c3cdfSJon Samp
114e98c3cdfSJon SampIf 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.
115e98c3cdfSJon SampThe function can receive up to 8 arguments (including the promise).
116e98c3cdfSJon Samp
117*a16ac082SAman MittalSee the [Argument types](#argument-types) section for more details on what types can be used in the function body.
118e98c3cdfSJon Samp
119e98c3cdfSJon SampIt is recommended to use `AsyncFunction` over `Function` when it:
120e98c3cdfSJon Samp
121e98c3cdfSJon Samp- does I/O bound tasks such as sending network requests or interacting with the file system
122afd513e4SAman Mittal- needs to be run on a different thread, for example, the main UI thread for UI-related tasks
123e98c3cdfSJon Samp- is an extensive or long-lasting operation that would block the JavaScript thread which in turn would reduce the responsiveness of the application
124e98c3cdfSJon Samp
125e98c3cdfSJon Samp<CodeBlocksTable>
126e98c3cdfSJon Samp
127e98c3cdfSJon Samp```swift
128e98c3cdfSJon SampAsyncFunction("asyncFunction") { (message: String, promise: Promise) in
129e98c3cdfSJon Samp  DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
130e98c3cdfSJon Samp    promise.resolve(message)
131e98c3cdfSJon Samp  }
132e98c3cdfSJon Samp}
133e98c3cdfSJon Samp```
134e98c3cdfSJon Samp
135e98c3cdfSJon Samp```kotlin
136e98c3cdfSJon SampAsyncFunction("asyncFunction") { message: String, promise: Promise ->
137e98c3cdfSJon Samp  launch(Dispatchers.Main) {
138e98c3cdfSJon Samp    promise.resolve(message)
139e98c3cdfSJon Samp  }
140e98c3cdfSJon Samp}
141e98c3cdfSJon Samp```
142e98c3cdfSJon Samp
143448dd81eSBartosz Kaszubowski</CodeBlocksTable>
144448dd81eSBartosz Kaszubowski
145448dd81eSBartosz Kaszubowski```js JavaScript
146e98c3cdfSJon Sampimport { requireNativeModule } from 'expo-modules-core';
147e98c3cdfSJon Samp
148e98c3cdfSJon Samp// Assume that we have named the module "MyModule"
149e98c3cdfSJon Sampconst MyModule = requireNativeModule('MyModule');
150e98c3cdfSJon Samp
151e98c3cdfSJon Sampasync function getMessageAsync() {
152e98c3cdfSJon Samp  return await MyModule.asyncFunction('bar');
153e98c3cdfSJon Samp}
154e98c3cdfSJon Samp```
155e98c3cdfSJon Samp
156de0f7b57SBartosz Kaszubowski---
15706c01802SŁukasz Kosmaty
15806c01802SŁukasz Kosmaty#### Kotlin coroutines <PlatformTags prefix="" platforms={['android']} />
15906c01802SŁukasz Kosmaty
16006c01802SŁukasz Kosmaty`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).
16106c01802SŁukasz Kosmaty
162*a16ac082SAman Mittal`AsyncFunction` with a suspendable body can't receive `Promise` as an argument. It uses a suspension mechanism to execute asynchronous calls.
16306c01802SŁukasz KosmatyThe 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.
16406c01802SŁukasz Kosmaty
16506c01802SŁukasz KosmatyBy 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.
16606c01802SŁukasz KosmatyThis scope's lifecycle is bound to the module's lifecycle - all unfinished suspend functions will be canceled when the module is deallocated.
16706c01802SŁukasz Kosmaty
16806c01802SŁukasz Kosmaty```kotlin Kotlin
16906c01802SŁukasz KosmatyAsyncFunction("suspendFunction") Coroutine { message: String ->
17006c01802SŁukasz Kosmaty  launch {
17106c01802SŁukasz Kosmaty    return@Coroutine message
17206c01802SŁukasz Kosmaty  }
17306c01802SŁukasz Kosmaty}
17406c01802SŁukasz Kosmaty```
17506c01802SŁukasz Kosmaty
176e98c3cdfSJon Samp</APIBox>
177e98c3cdfSJon Samp<APIBox header="Events">
178e98c3cdfSJon Samp
179e98c3cdfSJon SampDefines event names that the module can send to JavaScript.
180e98c3cdfSJon Samp
181becae9d9SŁukasz Kosmaty> **Note**: This component can be used inside of the [`View`](#view) block to define callback names. See [`View callbacks`](#view-callbacks)
182becae9d9SŁukasz Kosmaty
183e98c3cdfSJon Samp<CodeBlocksTable>
184e98c3cdfSJon Samp
185e98c3cdfSJon Samp```swift
186e98c3cdfSJon SampEvents("onCameraReady", "onPictureSaved", "onBarCodeScanned")
187e98c3cdfSJon Samp```
188e98c3cdfSJon Samp
189e98c3cdfSJon Samp```kotlin
190e98c3cdfSJon SampEvents("onCameraReady", "onPictureSaved", "onBarCodeScanned")
191e98c3cdfSJon Samp```
192e98c3cdfSJon Samp
193e98c3cdfSJon Samp</CodeBlocksTable>
194f1e821d1STomasz Sapeta
195f1e821d1STomasz SapetaSee [Sending events](#sending-events) to learn how to send events from the native code to JavaScript/TypeScript.
196f1e821d1STomasz Sapeta
197e98c3cdfSJon Samp</APIBox>
198b0681c8cSŁukasz Kosmaty<APIBox header="Property">
199b0681c8cSŁukasz Kosmaty
200b0681c8cSŁukasz KosmatyDefines a new property directly on the JavaScript object that represents a native module. It is the same as calling [`Object.defineProperty`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) on the module object.
201b0681c8cSŁukasz Kosmaty
202b0681c8cSŁukasz KosmatyTo declare a read-only property, you can use a shorthanded syntax that requires two arguments:
203b0681c8cSŁukasz Kosmaty
204b0681c8cSŁukasz Kosmaty- **name**: `String` — Name of the property that you'll use from JavaScript.
205b0681c8cSŁukasz Kosmaty- **getter**: `() -> PropertyType` — The closure to run when the getter for a property was called.
206b0681c8cSŁukasz Kosmaty
207b0681c8cSŁukasz Kosmaty<CodeBlocksTable>
208b0681c8cSŁukasz Kosmaty
209b0681c8cSŁukasz Kosmaty```swift
210b0681c8cSŁukasz KosmatyProperty("foo") {
211b0681c8cSŁukasz Kosmaty  return "bar"
212b0681c8cSŁukasz Kosmaty}
213b0681c8cSŁukasz Kosmaty```
214b0681c8cSŁukasz Kosmaty
215b0681c8cSŁukasz Kosmaty```kotlin
216b0681c8cSŁukasz KosmatyProperty("foo") {
217b0681c8cSŁukasz Kosmaty  return@Property "bar"
218b0681c8cSŁukasz Kosmaty}
219b0681c8cSŁukasz Kosmaty```
220b0681c8cSŁukasz Kosmaty
221b0681c8cSŁukasz Kosmaty</CodeBlocksTable>
222b0681c8cSŁukasz Kosmaty
223b0681c8cSŁukasz KosmatyIn the case of the mutable property, both the getter and the setter closure are needed (using the syntax below is also possible to declare a property with only a setter):
224b0681c8cSŁukasz Kosmaty
225b0681c8cSŁukasz Kosmaty- **name**: `String` — Name of the property that you'll use from JavaScript.
2262670795dSGuilherme Santos- **getter**: `() -> PropertyType` — The closure to run when the getter for a property was called.
227b0681c8cSŁukasz Kosmaty- **setter**: `(newValue: PropertyType) -> void` — The closure to run when the setter for a property was called.
228b0681c8cSŁukasz Kosmaty
229b0681c8cSŁukasz Kosmaty<CodeBlocksTable>
230b0681c8cSŁukasz Kosmaty
231b0681c8cSŁukasz Kosmaty```swift
232b0681c8cSŁukasz KosmatyProperty("foo")
233b0681c8cSŁukasz Kosmaty  .get { return "bar" }
234b0681c8cSŁukasz Kosmaty  .set { (newValue: String) in
235b0681c8cSŁukasz Kosmaty    // do something with new value
236b0681c8cSŁukasz Kosmaty  }
237b0681c8cSŁukasz Kosmaty```
238b0681c8cSŁukasz Kosmaty
239b0681c8cSŁukasz Kosmaty```kotlin
240b0681c8cSŁukasz KosmatyProperty("foo")
241b0681c8cSŁukasz Kosmaty  .get { return@get "bar" }
242b0681c8cSŁukasz Kosmaty  .set { newValue: String ->
243b0681c8cSŁukasz Kosmaty    // do something with new value
244b0681c8cSŁukasz Kosmaty  }
245b0681c8cSŁukasz Kosmaty```
246b0681c8cSŁukasz Kosmaty
247b0681c8cSŁukasz Kosmaty</CodeBlocksTable>
248b0681c8cSŁukasz Kosmaty
249b0681c8cSŁukasz Kosmaty```js JavaScript
250b0681c8cSŁukasz Kosmatyimport { requireNativeModule } from 'expo-modules-core';
251b0681c8cSŁukasz Kosmaty
252b0681c8cSŁukasz Kosmaty// Assume that we have named the module "MyModule"
253b0681c8cSŁukasz Kosmatyconst MyModule = requireNativeModule('MyModule');
254b0681c8cSŁukasz Kosmaty
255b0681c8cSŁukasz Kosmaty// Obtain the property value
256b0681c8cSŁukasz KosmatyMyModule.foo;
257b0681c8cSŁukasz Kosmaty
258b0681c8cSŁukasz Kosmaty// Set a new value
259b0681c8cSŁukasz KosmatyMyModule.foo = 'foobar';
260b0681c8cSŁukasz Kosmaty```
261b0681c8cSŁukasz Kosmaty
262b0681c8cSŁukasz Kosmaty</APIBox>
263e98c3cdfSJon Samp<APIBox header="View">
264e98c3cdfSJon Samp
26519019f8aSTomasz SapetaEnables the module to be used as a native view. Definition components that are accepted as part of the view definition: [`Prop`](#prop), [`Events`](#events), [`GroupView`](#groupview) and [`AsyncFunction`](#asyncfunction).
26619019f8aSTomasz Sapeta
26719019f8aSTomasz Sapeta[`AsyncFunction`](#asyncfunction) in the view definition is added to the React ref of the React component representing the native view.
26819019f8aSTomasz SapetaSuch async functions automatically receive an instance of the native view as the first argument and run on the UI thread by default.
269a51d1a38STomasz Sapeta
270a51d1a38STomasz Sapeta#### Arguments
271a51d1a38STomasz Sapeta
272adede39aSŁukasz Kosmaty- **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).
273c468593bSŁukasz Kosmaty- **definition**: `() -> ViewDefinition` — A builder of the view definition.
274e98c3cdfSJon Samp
275e98c3cdfSJon Samp<CodeBlocksTable>
276e98c3cdfSJon Samp
277e98c3cdfSJon Samp```swift
278a51d1a38STomasz SapetaView(UITextView.self) {
279a51d1a38STomasz Sapeta  Prop("text") { ... }
28019019f8aSTomasz Sapeta
28119019f8aSTomasz Sapeta  AsyncFunction("focus") { (view: UITextView) in
28219019f8aSTomasz Sapeta    view.becomeFirstResponder()
28319019f8aSTomasz Sapeta  }
284e98c3cdfSJon Samp}
285e98c3cdfSJon Samp```
286e98c3cdfSJon Samp
287e98c3cdfSJon Samp```kotlin
288a51d1a38STomasz SapetaView(TextView::class) {
289a51d1a38STomasz Sapeta  Prop("text") { ... }
29019019f8aSTomasz Sapeta
29119019f8aSTomasz Sapeta  AsyncFunction("focus") { view: TextView ->
29219019f8aSTomasz Sapeta    view.requestFocus()
29319019f8aSTomasz Sapeta  }
294e98c3cdfSJon Samp}
295e98c3cdfSJon Samp```
296e98c3cdfSJon Samp
297e98c3cdfSJon Samp</CodeBlocksTable>
298a51d1a38STomasz Sapeta
29919019f8aSTomasz Sapeta> **Info** 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.
30019019f8aSTomasz Sapeta
30119019f8aSTomasz Sapeta> **Info** View functions are available as of SDK 49.
302a51d1a38STomasz Sapeta
303e98c3cdfSJon Samp</APIBox>
304e98c3cdfSJon Samp<APIBox header="Prop">
305e98c3cdfSJon Samp
306e98c3cdfSJon SampDefines a setter for the view prop of given name.
307e98c3cdfSJon Samp
308e98c3cdfSJon Samp#### Arguments
309e98c3cdfSJon Samp
310e98c3cdfSJon Samp- **name**: `String` — Name of view prop that you want to define a setter.
311e98c3cdfSJon Samp- **setter**: `(view: ViewType, value: ValueType) -> ()` — Closure that is invoked when the view rerenders.
312e98c3cdfSJon Samp
313e98c3cdfSJon SampThis property can only be used within a [`ViewManager`](#viewmanager) closure.
314e98c3cdfSJon Samp
315e98c3cdfSJon Samp<CodeBlocksTable>
316e98c3cdfSJon Samp
317e98c3cdfSJon Samp```swift
318e98c3cdfSJon SampProp("background") { (view: UIView, color: UIColor) in
319e98c3cdfSJon Samp  view.backgroundColor = color
320e98c3cdfSJon Samp}
321e98c3cdfSJon Samp```
322e98c3cdfSJon Samp
323e98c3cdfSJon Samp```kotlin
324e98c3cdfSJon SampProp("background") { view: View, @ColorInt color: Int ->
325e98c3cdfSJon Samp  view.setBackgroundColor(color)
326e98c3cdfSJon Samp}
327e98c3cdfSJon Samp```
328e98c3cdfSJon Samp
329e98c3cdfSJon Samp</CodeBlocksTable>
330e98c3cdfSJon Samp
331e98c3cdfSJon Samp> **Note** Props of function type (callbacks) are not supported yet.
332e98c3cdfSJon Samp
333e98c3cdfSJon Samp</APIBox>
334e98c3cdfSJon Samp<APIBox header="OnCreate">
335e98c3cdfSJon Samp
336e98c3cdfSJon SampDefines 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.
337e98c3cdfSJon Samp
338e98c3cdfSJon Samp</APIBox>
339e98c3cdfSJon Samp<APIBox header="OnDestroy">
340e98c3cdfSJon Samp
341e98c3cdfSJon SampDefines module's lifecycle listener that is called when the module is about to be deallocated. Use it instead of module's class destructor.
342e98c3cdfSJon Samp
343e98c3cdfSJon Samp</APIBox>
344e98c3cdfSJon Samp<APIBox header="OnStartObserving">
345e98c3cdfSJon Samp
346e98c3cdfSJon SampDefines the function that is invoked when the first event listener is added.
347e98c3cdfSJon Samp
348e98c3cdfSJon Samp</APIBox>
349e98c3cdfSJon Samp<APIBox header="OnStopObserving">
350e98c3cdfSJon Samp
351e98c3cdfSJon SampDefines the function that is invoked when all event listeners are removed.
352e98c3cdfSJon Samp
353e98c3cdfSJon Samp</APIBox>
354e98c3cdfSJon Samp<APIBox header="OnAppContextDestroys">
355e98c3cdfSJon Samp
356e98c3cdfSJon SampDefines module's lifecycle listener that is called when the app context owning the module is about to be deallocated.
357e98c3cdfSJon Samp
358e98c3cdfSJon Samp</APIBox>
359e98c3cdfSJon Samp<APIBox header="OnAppEntersForeground" platforms={["ios"]}>
360e98c3cdfSJon Samp
361e98c3cdfSJon SampDefines the listener that is called when the app is about to enter the foreground mode.
362e98c3cdfSJon Samp
363e98c3cdfSJon Samp> **Note** This function is not available on Android — you may want to use [`OnActivityEntersForeground`](#onactivityentersforeground) instead.
364e98c3cdfSJon Samp
365e98c3cdfSJon Samp</APIBox>
366e98c3cdfSJon Samp<APIBox header="OnAppEntersBackground" platforms={["ios"]}>
367e98c3cdfSJon Samp
368e98c3cdfSJon SampDefines the listener that is called when the app enters the background mode.
369e98c3cdfSJon Samp
370e98c3cdfSJon Samp> **Note** This function is not available on Android — you may want to use [`OnActivityEntersBackground`](#onactivityentersbackground) instead.
371e98c3cdfSJon Samp
372e98c3cdfSJon Samp</APIBox>
373e98c3cdfSJon Samp<APIBox header="OnAppBecomesActive" platforms={["ios"]}>
374e98c3cdfSJon Samp
375e98c3cdfSJon SampDefines the listener that is called when the app becomes active again (after `OnAppEntersForeground`).
376e98c3cdfSJon Samp
377e98c3cdfSJon Samp> **Note** This function is not available on Android — you may want to use [`OnActivityEntersForeground`](#onactivityentersforeground) instead.
378e98c3cdfSJon Samp
379e98c3cdfSJon Samp</APIBox>
380e98c3cdfSJon Samp<APIBox header="OnActivityEntersForeground" platforms={["android"]}>
381e98c3cdfSJon Samp
382e98c3cdfSJon SampDefines the activity lifecycle listener that is called right after the activity is resumed.
383e98c3cdfSJon Samp
384e98c3cdfSJon Samp> **Note** This function is not available on iOS — you may want to use [`OnAppEntersForeground`](#onappentersforeground) instead.
385e98c3cdfSJon Samp
386e98c3cdfSJon Samp</APIBox>
387e98c3cdfSJon Samp<APIBox header="OnActivityEntersBackground" platforms={["android"]}>
388e98c3cdfSJon Samp
389e98c3cdfSJon SampDefines the activity lifecycle listener that is called right after the activity is paused.
390e98c3cdfSJon Samp
391e98c3cdfSJon Samp> **Note** This function is not available on iOS — you may want to use [`OnAppEntersBackground`](#onappentersbackground) instead.
392e98c3cdfSJon Samp
393e98c3cdfSJon Samp</APIBox>
394e98c3cdfSJon Samp<APIBox header="OnActivityDestroys" platforms={["android"]}>
395e98c3cdfSJon Samp
396e98c3cdfSJon SampDefines the activity lifecycle listener that is called when the activity owning the JavaScript context is about to be destroyed.
397e98c3cdfSJon Samp
398e98c3cdfSJon Samp> **Note** This function is not available on iOS — you may want to use [`OnAppEntersBackground`](#onappentersbackground) instead.
399e98c3cdfSJon Samp
400e98c3cdfSJon Samp</APIBox>
401e98c3cdfSJon Samp
4025685bb54SŁukasz Kosmaty<APIBox header="GroupView" platforms={["android"]}>
4035685bb54SŁukasz Kosmaty
4045685bb54SŁukasz KosmatyEnables the view to be used as a view group. Definition components that are accepted as part of the group view definition: [`AddChildView`](#addchildview), [`GetChildCount`](#getchildcount), [`GetChildViewAt`](#getchildviewat), [`RemoveChildView`](#removechildview), [`RemoveChildViewAt`](#removechildviewat).
4055685bb54SŁukasz Kosmaty
4065685bb54SŁukasz Kosmaty#### Arguments
4075685bb54SŁukasz Kosmaty
4085685bb54SŁukasz Kosmaty- **viewType** — The class of the native view. Note that the provided class must inherit from the Android `ViewGroup`.
4095685bb54SŁukasz Kosmaty- **definition**: `() -> ViewGroupDefinition` — A builder of the view group definition.
4105685bb54SŁukasz Kosmaty
4115685bb54SŁukasz KosmatyThis property can only be used within a [`View`](#view) closure.
4125685bb54SŁukasz Kosmaty
4135685bb54SŁukasz Kosmaty```kotlin Kotlin
4145685bb54SŁukasz KosmatyGroupView<ViewGroup> {
4155685bb54SŁukasz Kosmaty  AddChildView { parent, child, index -> ... }
4165685bb54SŁukasz Kosmaty}
4175685bb54SŁukasz Kosmaty```
4185685bb54SŁukasz Kosmaty
4195685bb54SŁukasz Kosmaty</APIBox>
4205685bb54SŁukasz Kosmaty
4215685bb54SŁukasz Kosmaty<APIBox header="AddChildView" platforms={["android"]}>
4225685bb54SŁukasz Kosmaty
4235685bb54SŁukasz KosmatyDefines action that adds a child view to the view group.
4245685bb54SŁukasz Kosmaty
4255685bb54SŁukasz Kosmaty#### Arguments
4265685bb54SŁukasz Kosmaty
4275685bb54SŁukasz Kosmaty- **action**: `(parent: ParentType, child: ChildType, index: Int) -> ()` — An action that adds a child view to the view group.
4285685bb54SŁukasz Kosmaty
4295685bb54SŁukasz KosmatyThis property can only be used within a [`GroupView`](#groupview) closure.
4305685bb54SŁukasz Kosmaty
4315685bb54SŁukasz Kosmaty```kotlin Kotlin
4325685bb54SŁukasz KosmatyAddChildView { parent, child: View, index ->
4335685bb54SŁukasz Kosmaty  parent.addView(child, index)
4345685bb54SŁukasz Kosmaty}
4355685bb54SŁukasz Kosmaty```
4365685bb54SŁukasz Kosmaty
4375685bb54SŁukasz Kosmaty</APIBox>
4385685bb54SŁukasz Kosmaty
4395685bb54SŁukasz Kosmaty<APIBox header="GetChildCount" platforms={["android"]}>
4405685bb54SŁukasz Kosmaty
4415685bb54SŁukasz KosmatyDefines action the retrieves the number of child views in the view group.
4425685bb54SŁukasz Kosmaty
4435685bb54SŁukasz Kosmaty#### Arguments
4445685bb54SŁukasz Kosmaty
445a20d767eSSara Tavares- **action**: `(parent: ParentType) -> Int` — A function that returns number of child views.
4465685bb54SŁukasz Kosmaty
4475685bb54SŁukasz KosmatyThis property can only be used within a [`GroupView`](#groupview) closure.
4485685bb54SŁukasz Kosmaty
4495685bb54SŁukasz Kosmaty```kotlin Kotlin
4505685bb54SŁukasz KosmatyGetChildCount { parent ->
4515685bb54SŁukasz Kosmaty  return@GetChildCount parent.childCount
4525685bb54SŁukasz Kosmaty}
4535685bb54SŁukasz Kosmaty```
4545685bb54SŁukasz Kosmaty
4555685bb54SŁukasz Kosmaty</APIBox>
4565685bb54SŁukasz Kosmaty
4575685bb54SŁukasz Kosmaty<APIBox header="GetChildViewAt" platforms={["android"]}>
4585685bb54SŁukasz Kosmaty
4595685bb54SŁukasz KosmatyDefines action that retrieves a child view at a specific index from the view group.
4605685bb54SŁukasz Kosmaty
4615685bb54SŁukasz Kosmaty#### Arguments
4625685bb54SŁukasz Kosmaty
4635685bb54SŁukasz Kosmaty- **action**: `(parent: ParentType, index: Int) -> ChildType` — A function that retrieves a child view at a specific index from the view group.
4645685bb54SŁukasz Kosmaty
4655685bb54SŁukasz KosmatyThis property can only be used within a [`GroupView`](#groupview) closure.
4665685bb54SŁukasz Kosmaty
4675685bb54SŁukasz Kosmaty```kotlin Kotlin
4685685bb54SŁukasz KosmatyGetChildViewAt { parent, index ->
4695685bb54SŁukasz Kosmaty  parent.getChildAt(index)
4705685bb54SŁukasz Kosmaty}
4715685bb54SŁukasz Kosmaty```
4725685bb54SŁukasz Kosmaty
4735685bb54SŁukasz Kosmaty</APIBox>
4745685bb54SŁukasz Kosmaty
4755685bb54SŁukasz Kosmaty<APIBox header="RemoveChildView" platforms={["android"]}>
4765685bb54SŁukasz Kosmaty
4775685bb54SŁukasz KosmatyDefines action that removes a specific child view from the view group.
4785685bb54SŁukasz Kosmaty
4795685bb54SŁukasz Kosmaty#### Arguments
4805685bb54SŁukasz Kosmaty
4815685bb54SŁukasz Kosmaty- **action**: `(parent: ParentType, child: ChildType) -> ()` — A function that remove a specific child view from the view group.
4825685bb54SŁukasz Kosmaty
4835685bb54SŁukasz KosmatyThis property can only be used within a [`GroupView`](#groupview) closure.
4845685bb54SŁukasz Kosmaty
4855685bb54SŁukasz Kosmaty```kotlin Kotlin
4865685bb54SŁukasz KosmatyRemoveChildView { parent, child: View ->
4875685bb54SŁukasz Kosmaty  parent.removeView(child)
4885685bb54SŁukasz Kosmaty}
4895685bb54SŁukasz Kosmaty```
4905685bb54SŁukasz Kosmaty
4915685bb54SŁukasz Kosmaty</APIBox>
4925685bb54SŁukasz Kosmaty
4935685bb54SŁukasz Kosmaty<APIBox header="RemoveChildViewAt" platforms={["android"]}>
4945685bb54SŁukasz Kosmaty
4955685bb54SŁukasz KosmatyDefines action that removes a child view at a specific index from the view group.
4965685bb54SŁukasz Kosmaty
4975685bb54SŁukasz Kosmaty#### Arguments
4985685bb54SŁukasz Kosmaty
4995685bb54SŁukasz Kosmaty- **action**: `(parent: ParentType, child: ChildType) -> ()` — A function that removes a child view at a specific index from the view group.
5005685bb54SŁukasz Kosmaty
5015685bb54SŁukasz KosmatyThis property can only be used within a [`GroupView`](#groupview) closure.
5025685bb54SŁukasz Kosmaty
5035685bb54SŁukasz Kosmaty```kotlin Kotlin
5045685bb54SŁukasz KosmatyRemoveChildViewAt { parent, index ->
5055685bb54SŁukasz Kosmaty  parent.removeViewAt(child)
5065685bb54SŁukasz Kosmaty}
5075685bb54SŁukasz Kosmaty```
5085685bb54SŁukasz Kosmaty
5095685bb54SŁukasz Kosmaty</APIBox>
5105685bb54SŁukasz Kosmaty
511*a16ac082SAman Mittal## Argument types
512e98c3cdfSJon Samp
513*a16ac082SAman MittalFundamentally, 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 cast 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.
514e98c3cdfSJon Samp
515e98c3cdfSJon Samp<APIBox header="Primitives">
516e98c3cdfSJon Samp
517e98c3cdfSJon SampAll 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.
518e98c3cdfSJon Samp
519e98c3cdfSJon Samp| Language | Supported primitive types                                                                                                      |
5208682b075SBartosz Kaszubowski| -------- | ------------------------------------------------------------------------------------------------------------------------------ |
521e98c3cdfSJon Samp| Swift    | `Bool`, `Int`, `Int8`, `Int16`, `Int32`, `Int64`, `UInt`, `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Float32`, `Double`, `String` |
5226f6581b6SŁukasz Kosmaty| Kotlin   | `Boolean`, `Int`, `Long`, `UInt`, `Float`, `Double`, `String`, `Pair`                                                          |
523e98c3cdfSJon Samp
524e98c3cdfSJon Samp</APIBox>
525e98c3cdfSJon Samp<APIBox header="Convertibles">
526e98c3cdfSJon Samp
527837aa7efSTomasz Sapeta_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.
528e98c3cdfSJon Samp
529de0f7b57SBartosz Kaszubowski---
530de0f7b57SBartosz Kaszubowski
531e98c3cdfSJon SampSome common iOS types from `CoreGraphics` and `UIKit` system frameworks are already made convertible.
532e98c3cdfSJon Samp
5334c448cb7SŁukasz Kosmaty| Native iOS Type         | TypeScript                                                                                                                                                                        |
534fc141ba9SJakov Glavina| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
535*a16ac082SAman Mittal| `URL`                   | `string` with a URL. When a scheme is not provided, it's assumed to be a file URL.                                                                                                |
536e98c3cdfSJon Samp| `CGFloat`               | `number`                                                                                                                                                                          |
537e98c3cdfSJon Samp| `CGPoint`               | `{ x: number, y: number }` or `number[]` with _x_ and _y_ coords                                                                                                                  |
538e98c3cdfSJon Samp| `CGSize`                | `{ width: number, height: number }` or `number[]` with _width_ and _height_                                                                                                       |
539e98c3cdfSJon Samp| `CGVector`              | `{ dx: number, dy: number }` or `number[]` with _dx_ and _dy_ vector differentials                                                                                                |
540e98c3cdfSJon Samp| `CGRect`                | `{ x: number, y: number, width: number, height: number }` or `number[]` with _x_, _y_, _width_ and _height_ values                                                                |
541837aa7efSTomasz Sapeta| `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"` |
542e98c3cdfSJon Samp
543de0f7b57SBartosz Kaszubowski---
544de0f7b57SBartosz Kaszubowski
5454c448cb7SŁukasz KosmatySimilarly, some common Android types from packages like `java.io`, `java.net`, or `android.graphics` are also made convertible.
5464c448cb7SŁukasz Kosmaty
5474c448cb7SŁukasz Kosmaty| Native Android Type                                                           | TypeScript                                                                                                                                                                        |
548cc8a0222SŁukasz Kosmaty| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5494c448cb7SŁukasz Kosmaty| `java.net.URL`                                                                | `string` with a URL. Note that the scheme has to be provided                                                                                                                      |
5504c448cb7SŁukasz Kosmaty| `android.net.Uri`<br/>`java.net.URI`                                          | `string` with a URI. Note that the scheme has to be provided                                                                                                                      |
551cc8a0222SŁukasz Kosmaty| `java.io.File`<br/>`java.nio.file.Path` (is only available on Android API 26) | `string` with a path to the file                                                                                                                                                  |
5524c448cb7SŁukasz Kosmaty| `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"` |
5534c448cb7SŁukasz Kosmaty| `kotlin.Pair<A, B>`                                                           | Array with two values, where the first one is of type _A_ and the second is of type _B_                                                                                           |
5544c448cb7SŁukasz Kosmaty
555e98c3cdfSJon Samp</APIBox>
556e98c3cdfSJon Samp<APIBox header="Records">
557e98c3cdfSJon Samp
558*a16ac082SAman Mittal_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 type and provide a default value.
559*a16ac082SAman MittalIt is a better way to represent a JavaScript object with the native type safety.
560e98c3cdfSJon Samp
561e98c3cdfSJon Samp<CodeBlocksTable>
562e98c3cdfSJon Samp
563e98c3cdfSJon Samp```swift
564e98c3cdfSJon Sampstruct FileReadOptions: Record {
565e98c3cdfSJon Samp  @Field
566e98c3cdfSJon Samp  var encoding: String = "utf8"
567e98c3cdfSJon Samp
568e98c3cdfSJon Samp  @Field
569e98c3cdfSJon Samp  var position: Int = 0
570e98c3cdfSJon Samp
571e98c3cdfSJon Samp  @Field
572e98c3cdfSJon Samp  var length: Int?
573e98c3cdfSJon Samp}
574e98c3cdfSJon Samp
575e98c3cdfSJon Samp// Now this record can be used as an argument of the functions or the view prop setters.
576e98c3cdfSJon SampFunction("readFile") { (path: String, options: FileReadOptions) -> String in
577e98c3cdfSJon Samp  // Read the file using given `options`
578e98c3cdfSJon Samp}
579e98c3cdfSJon Samp```
580e98c3cdfSJon Samp
581e98c3cdfSJon Samp```kotlin
582e98c3cdfSJon Sampclass FileReadOptions : Record {
583e98c3cdfSJon Samp  @Field
584e98c3cdfSJon Samp  val encoding: String = "utf8"
585e98c3cdfSJon Samp
586e98c3cdfSJon Samp  @Field
587e98c3cdfSJon Samp  val position: Int = 0
588e98c3cdfSJon Samp
589e98c3cdfSJon Samp  @Field
5900f0710ccSŁukasz Kosmaty  val length: Int? = null
591e98c3cdfSJon Samp}
592e98c3cdfSJon Samp
593e98c3cdfSJon Samp// Now this record can be used as an argument of the functions or the view prop setters.
594e98c3cdfSJon SampFunction("readFile") { path: String, options: FileReadOptions ->
595e98c3cdfSJon Samp  // Read the file using given `options`
596e98c3cdfSJon Samp}
597e98c3cdfSJon Samp```
598e98c3cdfSJon Samp
599e98c3cdfSJon Samp</CodeBlocksTable>
600e98c3cdfSJon Samp</APIBox>
601e98c3cdfSJon Samp<APIBox header="Enums">
602e98c3cdfSJon Samp
603*a16ac082SAman MittalWith 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 (for example, `String`, `Int`) and conform to `Enumerable`.
604e98c3cdfSJon Samp
605e98c3cdfSJon Samp<CodeBlocksTable>
606e98c3cdfSJon Samp
607e98c3cdfSJon Samp```swift
6084651a35bSlukmccallenum FileEncoding: String, Enumerable {
609e98c3cdfSJon Samp  case utf8
610e98c3cdfSJon Samp  case base64
611e98c3cdfSJon Samp}
612e98c3cdfSJon Samp
613e98c3cdfSJon Sampstruct FileReadOptions: Record {
614e98c3cdfSJon Samp  @Field
615e98c3cdfSJon Samp  var encoding: FileEncoding = .utf8
616e98c3cdfSJon Samp  // ...
617e98c3cdfSJon Samp}
618e98c3cdfSJon Samp```
619e98c3cdfSJon Samp
620e98c3cdfSJon Samp```kotlin
621e98c3cdfSJon Samp// Note: the constructor must have an argument called value.
62207b7ece3Slukmccallenum class FileEncoding(val value: String) : Enumerable {
623e98c3cdfSJon Samp  utf8("utf8"),
624e98c3cdfSJon Samp  base64("base64")
625e98c3cdfSJon Samp}
626e98c3cdfSJon Samp
627e98c3cdfSJon Sampclass FileReadOptions : Record {
628e98c3cdfSJon Samp  @Field
629e98c3cdfSJon Samp  val encoding: FileEncoding = FileEncoding.utf8
630e98c3cdfSJon Samp  // ...
631e98c3cdfSJon Samp}
632e98c3cdfSJon Samp```
633e98c3cdfSJon Samp
634e98c3cdfSJon Samp</CodeBlocksTable>
635e98c3cdfSJon Samp</APIBox>
636aedf0c04STomasz Sapeta<APIBox header="Eithers">
637aedf0c04STomasz Sapeta
638aedf0c04STomasz SapetaThere 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.
639aedf0c04STomasz SapetaThey act as a container for a value of one of a couple of types.
640aedf0c04STomasz Sapeta
641aedf0c04STomasz Sapeta<CodeBlocksTable>
642aedf0c04STomasz Sapeta
643aedf0c04STomasz Sapeta```swift
644aedf0c04STomasz SapetaFunction("foo") { (bar: Either<String, Int>) in
645aedf0c04STomasz Sapeta  if let bar: String = bar.get() {
646aedf0c04STomasz Sapeta    // `bar` is a String
647aedf0c04STomasz Sapeta  }
648aedf0c04STomasz Sapeta  if let bar: Int = bar.get() {
649aedf0c04STomasz Sapeta    // `bar` is an Int
650aedf0c04STomasz Sapeta  }
651aedf0c04STomasz Sapeta}
652aedf0c04STomasz Sapeta```
653aedf0c04STomasz Sapeta
654aedf0c04STomasz Sapeta```kotlin
655aedf0c04STomasz SapetaFunction("foo") { bar: Either<String, Int> ->
656aedf0c04STomasz Sapeta  bar.get(String::class).let {
657aedf0c04STomasz Sapeta    // `it` is a String
658aedf0c04STomasz Sapeta  }
659aedf0c04STomasz Sapeta  bar.get(Int::class).let {
660aedf0c04STomasz Sapeta    // `it` is an Int
661aedf0c04STomasz Sapeta  }
662aedf0c04STomasz Sapeta}
663aedf0c04STomasz Sapeta```
664aedf0c04STomasz Sapeta
665aedf0c04STomasz Sapeta</CodeBlocksTable>
666aedf0c04STomasz Sapeta
667aedf0c04STomasz SapetaThe implementation for three Either types is currently provided out of the box, allowing you to use up to four different subtypes.
668aedf0c04STomasz Sapeta
669aedf0c04STomasz Sapeta- `Either<FirstType, SecondType>` — A container for one of two types.
670aedf0c04STomasz Sapeta- `EitherOfThree<FirstType, SecondType, ThirdType>` — A container for one of three types.
671aedf0c04STomasz Sapeta- `EitherOfFour<FirstType, SecondType, ThirdType, FourthType>` — A container for one of four types.
672aedf0c04STomasz Sapeta
67319019f8aSTomasz Sapeta> **Info** Either types are available as of SDK 47.
67419019f8aSTomasz Sapeta
67519019f8aSTomasz Sapeta</APIBox>
67619019f8aSTomasz Sapeta<APIBox header="JavaScript values">
67719019f8aSTomasz Sapeta
67819019f8aSTomasz SapetaIt's also possible to use a `JavaScriptValue` type which is a holder for any value that can be represented in JavaScript.
67919019f8aSTomasz SapetaThis type is useful when you want to mutate the given argument or when you want to omit type validations and conversions.
68019019f8aSTomasz SapetaNote that using JavaScript-specific types is restricted to synchronous functions as all reads and writes in the JavaScript runtime must happen on the JavaScript thread.
68119019f8aSTomasz SapetaAny access to these values from different threads will result in a crash.
68219019f8aSTomasz Sapeta
68319019f8aSTomasz SapetaIn addition to the raw value, the `JavaScriptObject` type can be used to allow only object types and `JavaScriptFunction<ReturnType>` for callbacks.
68419019f8aSTomasz Sapeta
68519019f8aSTomasz Sapeta<CodeBlocksTable>
68619019f8aSTomasz Sapeta
68719019f8aSTomasz Sapeta```swift
68819019f8aSTomasz SapetaFunction("mutateMe") { (value: JavaScriptValue) in
68919019f8aSTomasz Sapeta  if value.isObject() {
69019019f8aSTomasz Sapeta    let jsObject = value.getObject()
69119019f8aSTomasz Sapeta    jsObject.setProperty("expo", value: "modules")
69219019f8aSTomasz Sapeta  }
69319019f8aSTomasz Sapeta}
69419019f8aSTomasz Sapeta
69519019f8aSTomasz Sapeta// or
69619019f8aSTomasz Sapeta
69719019f8aSTomasz SapetaFunction("mutateMe") { (jsObject: JavaScriptObject) in
69819019f8aSTomasz Sapeta  jsObject.setProperty("expo", value: "modules")
69919019f8aSTomasz Sapeta}
70019019f8aSTomasz Sapeta```
70119019f8aSTomasz Sapeta
70219019f8aSTomasz Sapeta```kotlin
70319019f8aSTomasz SapetaFunction("mutateMe") { value: JavaScriptValue ->
70419019f8aSTomasz Sapeta  if (value.isObject()) {
70519019f8aSTomasz Sapeta    val jsObject = value.getObject()
70619019f8aSTomasz Sapeta    jsObject.setProperty("expo", "modules")
70719019f8aSTomasz Sapeta  }
70819019f8aSTomasz Sapeta}
70919019f8aSTomasz Sapeta
71019019f8aSTomasz Sapeta// or
71119019f8aSTomasz Sapeta
71219019f8aSTomasz SapetaFunction("mutateMe") { jsObject: JavaScriptObject ->
71319019f8aSTomasz Sapeta  jsObject.setProperty("expo", "modules")
71419019f8aSTomasz Sapeta}
71519019f8aSTomasz Sapeta```
71619019f8aSTomasz Sapeta
71719019f8aSTomasz Sapeta</CodeBlocksTable>
71819019f8aSTomasz Sapeta
71919019f8aSTomasz Sapeta> **Info** JavaScript types are available as of SDK 49.
720aedf0c04STomasz Sapeta
721aedf0c04STomasz Sapeta</APIBox>
722e98c3cdfSJon Samp
723*a16ac082SAman Mittal## Native classes
724adede39aSŁukasz Kosmaty
725adede39aSŁukasz Kosmaty<APIBox header="Module">
726adede39aSŁukasz Kosmaty
727adede39aSŁukasz KosmatyA base class for a native module.
728adede39aSŁukasz Kosmaty
729adede39aSŁukasz Kosmaty#### Properties
730adede39aSŁukasz Kosmaty
731adede39aSŁukasz Kosmaty<APIMethod
732adede39aSŁukasz Kosmaty  name="appContext"
733adede39aSŁukasz Kosmaty  comment="Provides access to the [`AppContext`](#appcontext)."
734adede39aSŁukasz Kosmaty  returnTypeName="AppContext"
735adede39aSŁukasz Kosmaty  isProperty={true}
736adede39aSŁukasz Kosmaty  isReturnTypeReference={true}
737adede39aSŁukasz Kosmaty/>
738adede39aSŁukasz Kosmaty
739adede39aSŁukasz Kosmaty#### Methods
740adede39aSŁukasz Kosmaty
741adede39aSŁukasz Kosmaty<APIMethod
742adede39aSŁukasz Kosmaty  name="sendEvent"
743adede39aSŁukasz Kosmaty  comment="Sends an event with a given name and a payload to JavaScript. See [`Sending events`](#sending-events)"
744adede39aSŁukasz Kosmaty  returnTypeName="void"
745adede39aSŁukasz Kosmaty  parameters={[
746adede39aSŁukasz Kosmaty    {
747adede39aSŁukasz Kosmaty      name: 'eventName',
748adede39aSŁukasz Kosmaty      comment: 'The name of the JavaScript event',
749adede39aSŁukasz Kosmaty      typeName: 'string',
750adede39aSŁukasz Kosmaty    },
751adede39aSŁukasz Kosmaty    {
752adede39aSŁukasz Kosmaty      name: 'payload',
753adede39aSŁukasz Kosmaty      comment: 'The event payload',
754adede39aSŁukasz Kosmaty      typeName: 'Android: Map<String, Any?> | Bundle\niOS: [String: Any?]',
755adede39aSŁukasz Kosmaty    },
756adede39aSŁukasz Kosmaty  ]}
757adede39aSŁukasz Kosmaty/>
758adede39aSŁukasz Kosmaty
759adede39aSŁukasz Kosmaty</APIBox>
760adede39aSŁukasz Kosmaty
761adede39aSŁukasz Kosmaty<APIBox header="AppContext">
762adede39aSŁukasz Kosmaty
763adede39aSŁukasz KosmatyThe app context is an interface to a single Expo app.
764adede39aSŁukasz Kosmaty
765c468593bSŁukasz Kosmaty#### Properties
766c468593bSŁukasz Kosmaty
767c468593bSŁukasz Kosmaty<APIMethod
768c468593bSŁukasz Kosmaty  name="constants"
769c468593bSŁukasz Kosmaty  comment="Provides access to app's constants from legacy module registry."
770c468593bSŁukasz Kosmaty  returnTypeName="Android: ConstantsInterface? iOS: EXConstantsInterface?"
771c468593bSŁukasz Kosmaty  isProperty={true}
772c468593bSŁukasz Kosmaty/>
773c468593bSŁukasz Kosmaty
774c468593bSŁukasz Kosmaty<APIMethod
775c468593bSŁukasz Kosmaty  name="permissions"
776c468593bSŁukasz Kosmaty  comment="Provides access to the permissions manager from legacy module registry."
777c468593bSŁukasz Kosmaty  returnTypeName="Android: Permissions? iOS: EXPermissionsInterface?"
778c468593bSŁukasz Kosmaty  isProperty={true}
779c468593bSŁukasz Kosmaty/>
780c468593bSŁukasz Kosmaty
781c468593bSŁukasz Kosmaty<APIMethod
782c468593bSŁukasz Kosmaty  name="imageLoader"
783c468593bSŁukasz Kosmaty  comment="Provides access to the image loader from the legacy module registry."
784c468593bSŁukasz Kosmaty  returnTypeName="Android: ImageLoaderInterface? iOS: EXImageLoaderInterface?"
785c468593bSŁukasz Kosmaty  isProperty={true}
786c468593bSŁukasz Kosmaty/>
787c468593bSŁukasz Kosmaty
788c468593bSŁukasz Kosmaty<APIMethod
789c468593bSŁukasz Kosmaty  name="barcodeScanner"
790c468593bSŁukasz Kosmaty  comment="Provides access to the bar code scanner manager from the legacy module registry."
791c468593bSŁukasz Kosmaty  returnTypeName="ImageLoaderInterface?"
792c468593bSŁukasz Kosmaty  isProperty={true}
793c468593bSŁukasz Kosmaty  platforms={['Android']}
794c468593bSŁukasz Kosmaty/>
795c468593bSŁukasz Kosmaty
796c468593bSŁukasz Kosmaty<APIMethod
797c468593bSŁukasz Kosmaty  name="camera"
798c468593bSŁukasz Kosmaty  comment="Provides access to the camera view manager from the legacy module registry."
799c468593bSŁukasz Kosmaty  returnTypeName="CameraViewInterface?"
800c468593bSŁukasz Kosmaty  isProperty={true}
801c468593bSŁukasz Kosmaty  platforms={['Android']}
802c468593bSŁukasz Kosmaty/>
803c468593bSŁukasz Kosmaty
804c468593bSŁukasz Kosmaty<APIMethod
805c468593bSŁukasz Kosmaty  name="font"
806c468593bSŁukasz Kosmaty  comment="Provides access to the font manager from the legacy module registry."
807c468593bSŁukasz Kosmaty  returnTypeName="FontManagerInterface?"
808c468593bSŁukasz Kosmaty  isProperty={true}
809c468593bSŁukasz Kosmaty  platforms={['Android']}
810c468593bSŁukasz Kosmaty/>
811c468593bSŁukasz Kosmaty
812c468593bSŁukasz Kosmaty<APIMethod
813c468593bSŁukasz Kosmaty  name="sensor"
814c468593bSŁukasz Kosmaty  comment="Provides access to the sensor manager from the legacy module registry."
815c468593bSŁukasz Kosmaty  returnTypeName="SensorServiceInterface?"
816c468593bSŁukasz Kosmaty  isProperty={true}
817c468593bSŁukasz Kosmaty  platforms={['Android']}
818c468593bSŁukasz Kosmaty/>
819c468593bSŁukasz Kosmaty
820c468593bSŁukasz Kosmaty<APIMethod
821c468593bSŁukasz Kosmaty  name="taskManager"
822c468593bSŁukasz Kosmaty  comment="Provides access to the task manager from the legacy module registry."
823c468593bSŁukasz Kosmaty  returnTypeName="TaskManagerInterface?"
824c468593bSŁukasz Kosmaty  isProperty={true}
825c468593bSŁukasz Kosmaty  platforms={['Android']}
826c468593bSŁukasz Kosmaty/>
827c468593bSŁukasz Kosmaty
828c468593bSŁukasz Kosmaty<APIMethod
829c468593bSŁukasz Kosmaty  name="activityProvider"
830c468593bSŁukasz Kosmaty  comment="Provides access to the activity provider from the legacy module registry."
831c468593bSŁukasz Kosmaty  returnTypeName="ActivityProvider?"
832c468593bSŁukasz Kosmaty  isProperty={true}
833c468593bSŁukasz Kosmaty  platforms={['Android']}
834c468593bSŁukasz Kosmaty/>
835c468593bSŁukasz Kosmaty
836c468593bSŁukasz Kosmaty<APIMethod
837c468593bSŁukasz Kosmaty  name="reactContext"
838c468593bSŁukasz Kosmaty  comment="Provides access to the react application context."
839c468593bSŁukasz Kosmaty  returnTypeName="Context?"
840c468593bSŁukasz Kosmaty  isProperty={true}
841c468593bSŁukasz Kosmaty  platforms={['Android']}
842c468593bSŁukasz Kosmaty/>
843c468593bSŁukasz Kosmaty
844c468593bSŁukasz Kosmaty<APIMethod
845c468593bSŁukasz Kosmaty  name="hasActiveReactInstance"
846c468593bSŁukasz Kosmaty  comment="Checks if there is an not-null, alive react native instance."
847c468593bSŁukasz Kosmaty  returnTypeName="Boolean"
848c468593bSŁukasz Kosmaty  isProperty={true}
849c468593bSŁukasz Kosmaty  platforms={['Android']}
850c468593bSŁukasz Kosmaty/>
851c468593bSŁukasz Kosmaty
852c468593bSŁukasz Kosmaty<APIMethod
853c468593bSŁukasz Kosmaty  name="utilities"
854c468593bSŁukasz Kosmaty  comment="Provides access to the utilities from legacy module registry."
855c468593bSŁukasz Kosmaty  returnTypeName="EXUtilitiesInterface?"
856c468593bSŁukasz Kosmaty  isProperty={true}
857c468593bSŁukasz Kosmaty  platforms={['iOS']}
858c468593bSŁukasz Kosmaty/>
859c468593bSŁukasz Kosmaty
860adede39aSŁukasz Kosmaty</APIBox>
861adede39aSŁukasz Kosmaty
862adede39aSŁukasz Kosmaty<APIBox header="ExpoView">
863adede39aSŁukasz Kosmaty
864adede39aSŁukasz KosmatyA base class that should be used by all exported views.
865adede39aSŁukasz Kosmaty
866afd513e4SAman MittalOn iOS, `ExpoView` extends the `RCTView` which handles some styles (for example, borders) and accessibility.
867adede39aSŁukasz Kosmaty
868adede39aSŁukasz Kosmaty#### Properties
869adede39aSŁukasz Kosmaty
870adede39aSŁukasz Kosmaty<APIMethod
871adede39aSŁukasz Kosmaty  name="appContext"
872adede39aSŁukasz Kosmaty  comment="Provides access to the [`AppContext`](#appcontext)."
873adede39aSŁukasz Kosmaty  returnTypeName="AppContext"
874adede39aSŁukasz Kosmaty  isProperty={true}
875adede39aSŁukasz Kosmaty  isReturnTypeReference={true}
876adede39aSŁukasz Kosmaty/>
877adede39aSŁukasz Kosmaty
878adede39aSŁukasz Kosmaty#### Extending `ExpoView`
879adede39aSŁukasz Kosmaty
8808e2d7692SBartosz KaszubowskiTo 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`.
881adede39aSŁukasz Kosmaty
882adede39aSŁukasz Kosmaty<CodeBlocksTable>
883adede39aSŁukasz Kosmaty
884adede39aSŁukasz Kosmaty```swift
885adede39aSŁukasz Kosmatyclass LinearGradientView: ExpoView {}
886adede39aSŁukasz Kosmaty
887adede39aSŁukasz Kosmatypublic class LinearGradientModule: Module {
888adede39aSŁukasz Kosmaty  public func definition() -> ModuleDefinition {
889adede39aSŁukasz Kosmaty    View(LinearGradientView.self) {
890adede39aSŁukasz Kosmaty      // ...
891adede39aSŁukasz Kosmaty    }
892adede39aSŁukasz Kosmaty  }
893adede39aSŁukasz Kosmaty}
894adede39aSŁukasz Kosmaty```
895adede39aSŁukasz Kosmaty
896adede39aSŁukasz Kosmaty```kotlin
897adede39aSŁukasz Kosmatyclass LinearGradientView(
898adede39aSŁukasz Kosmaty  context: Context,
899adede39aSŁukasz Kosmaty  appContext: AppContext,
900adede39aSŁukasz Kosmaty) : ExpoView(context, appContext)
901adede39aSŁukasz Kosmaty
902adede39aSŁukasz Kosmatyclass LinearGradientModule : Module() {
903adede39aSŁukasz Kosmaty  override fun definition() = ModuleDefinition {
904adede39aSŁukasz Kosmaty    View(LinearGradientView::class) {
905adede39aSŁukasz Kosmaty      // ...
906adede39aSŁukasz Kosmaty    }
907adede39aSŁukasz Kosmaty  }
908adede39aSŁukasz Kosmaty}
909adede39aSŁukasz Kosmaty```
910adede39aSŁukasz Kosmaty
911adede39aSŁukasz Kosmaty</CodeBlocksTable>
912adede39aSŁukasz Kosmaty
913adede39aSŁukasz Kosmaty</APIBox>
914adede39aSŁukasz Kosmaty
915f1e821d1STomasz Sapeta## Guides
916f1e821d1STomasz Sapeta
9173324c13cSBartosz Kaszubowski<APIBox>
9183324c13cSBartosz Kaszubowski### Sending events
919f1e821d1STomasz Sapeta
920f1e821d1STomasz SapetaWhile 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.
921f1e821d1STomasz Sapeta
922f1e821d1STomasz SapetaTo 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:
923f1e821d1STomasz Sapeta
924f1e821d1STomasz Sapeta<CodeBlocksTable>
925f1e821d1STomasz Sapeta
926f1e821d1STomasz Sapeta```swift
927f1e821d1STomasz Sapetalet CLIPBOARD_CHANGED_EVENT_NAME = "onClipboardChanged"
928f1e821d1STomasz Sapeta
929f1e821d1STomasz Sapetapublic class ClipboardModule: Module {
930f1e821d1STomasz Sapeta  public func definition() -> ModuleDefinition {
931f1e821d1STomasz Sapeta    Events(CLIPBOARD_CHANGED_EVENT_NAME)
932f1e821d1STomasz Sapeta
933f1e821d1STomasz Sapeta    OnStartObserving {
934f1e821d1STomasz Sapeta      NotificationCenter.default.addObserver(
935f1e821d1STomasz Sapeta        self,
936f1e821d1STomasz Sapeta        selector: #selector(self.clipboardChangedListener),
937f1e821d1STomasz Sapeta        name: UIPasteboard.changedNotification,
938f1e821d1STomasz Sapeta        object: nil
939f1e821d1STomasz Sapeta      )
940f1e821d1STomasz Sapeta    }
941f1e821d1STomasz Sapeta
942f1e821d1STomasz Sapeta    OnStopObserving {
943f1e821d1STomasz Sapeta      NotificationCenter.default.removeObserver(
944f1e821d1STomasz Sapeta        self,
945f1e821d1STomasz Sapeta        name: UIPasteboard.changedNotification,
946f1e821d1STomasz Sapeta        object: nil
947f1e821d1STomasz Sapeta      )
948f1e821d1STomasz Sapeta    }
949f1e821d1STomasz Sapeta  }
950f1e821d1STomasz Sapeta
951f1e821d1STomasz Sapeta  @objc
952f1e821d1STomasz Sapeta  private func clipboardChangedListener() {
953f1e821d1STomasz Sapeta    sendEvent(CLIPBOARD_CHANGED_EVENT_NAME, [
954f1e821d1STomasz Sapeta      "contentTypes": availableContentTypes()
955f1e821d1STomasz Sapeta    ])
956f1e821d1STomasz Sapeta  }
957f1e821d1STomasz Sapeta}
958f1e821d1STomasz Sapeta```
959f1e821d1STomasz Sapeta
960f1e821d1STomasz Sapeta```kotlin
961f1e821d1STomasz Sapetaconst val CLIPBOARD_CHANGED_EVENT_NAME = "onClipboardChanged"
962f1e821d1STomasz Sapeta
963f1e821d1STomasz Sapetaclass ClipboardModule : Module() {
964f1e821d1STomasz Sapeta  override fun definition() = ModuleDefinition {
965f1e821d1STomasz Sapeta    Events(CLIPBOARD_CHANGED_EVENT_NAME)
966f1e821d1STomasz Sapeta
967f1e821d1STomasz Sapeta    OnStartObserving {
968f1e821d1STomasz Sapeta      clipboardManager?.addPrimaryClipChangedListener(listener)
969f1e821d1STomasz Sapeta    }
970f1e821d1STomasz Sapeta
971f1e821d1STomasz Sapeta    OnStopObserving {
972f1e821d1STomasz Sapeta      clipboardManager?.removePrimaryClipChangedListener(listener)
973f1e821d1STomasz Sapeta    }
974f1e821d1STomasz Sapeta  }
975f1e821d1STomasz Sapeta
976f1e821d1STomasz Sapeta  private val clipboardManager: ClipboardManager?
977f1e821d1STomasz Sapeta    get() = appContext.reactContext?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
978f1e821d1STomasz Sapeta
979f1e821d1STomasz Sapeta  private val listener = ClipboardManager.OnPrimaryClipChangedListener {
980f1e821d1STomasz Sapeta    clipboardManager?.primaryClipDescription?.let { clip ->
981f1e821d1STomasz Sapeta      [email protected](
982f1e821d1STomasz Sapeta        CLIPBOARD_CHANGED_EVENT_NAME,
983f1e821d1STomasz Sapeta        bundleOf(
984f1e821d1STomasz Sapeta          "contentTypes" to availableContentTypes(clip)
985f1e821d1STomasz Sapeta        )
986f1e821d1STomasz Sapeta      )
987f1e821d1STomasz Sapeta    }
988f1e821d1STomasz Sapeta  }
989f1e821d1STomasz Sapeta}
990f1e821d1STomasz Sapeta```
991f1e821d1STomasz Sapeta
992f1e821d1STomasz Sapeta</CodeBlocksTable>
993f1e821d1STomasz Sapeta
994f1e821d1STomasz SapetaTo subscribe to these events in JavaScript/TypeScript, you need to wrap the native module with `EventEmitter` class as shown:
995f1e821d1STomasz Sapeta
996f1e821d1STomasz Sapeta```ts TypeScript
997f1e821d1STomasz Sapetaimport { requireNativeModule, EventEmitter, Subscription } from 'expo-modules-core';
998f1e821d1STomasz Sapeta
999f1e821d1STomasz Sapetaconst ClipboardModule = requireNativeModule('Clipboard');
1000f1e821d1STomasz Sapetaconst emitter = new EventEmitter(ClipboardModule);
1001f1e821d1STomasz Sapeta
1002f1e821d1STomasz Sapetaexport function addClipboardListener(listener: (event) => void): Subscription {
1003f1e821d1STomasz Sapeta  return emitter.addListener('onClipboardChanged', listener);
1004f1e821d1STomasz Sapeta}
1005f1e821d1STomasz Sapeta```
1006f1e821d1STomasz Sapeta
1007f1e821d1STomasz Sapeta</APIBox>
1008f1e821d1STomasz Sapeta
10093324c13cSBartosz Kaszubowski<APIBox>
10103324c13cSBartosz Kaszubowski### View callbacks
1011becae9d9SŁukasz Kosmaty
1012becae9d9SŁukasz KosmatySome 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.
1013becae9d9SŁukasz Kosmaty
1014becae9d9SŁukasz KosmatyTo 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.
1015becae9d9SŁukasz Kosmaty
1016becae9d9SŁukasz Kosmaty> **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>}`.
1017becae9d9SŁukasz Kosmaty
1018becae9d9SŁukasz Kosmaty<CodeBlocksTable>
1019becae9d9SŁukasz Kosmaty
1020becae9d9SŁukasz Kosmaty```swift
1021becae9d9SŁukasz Kosmatyclass CameraViewModule: Module {
1022becae9d9SŁukasz Kosmaty  public func definition() -> ModuleDefinition {
1023d4a1a85aSFernando Rojo    View(CameraView.self) {
1024becae9d9SŁukasz Kosmaty      Events(
1025becae9d9SŁukasz Kosmaty        "onCameraReady"
1026becae9d9SŁukasz Kosmaty      )
1027becae9d9SŁukasz Kosmaty
1028becae9d9SŁukasz Kosmaty      // ...
1029becae9d9SŁukasz Kosmaty    }
1030becae9d9SŁukasz Kosmaty  }
1031becae9d9SŁukasz Kosmaty}
1032becae9d9SŁukasz Kosmaty
1033becae9d9SŁukasz Kosmatyclass CameraView: ExpoView {
1034becae9d9SŁukasz Kosmaty  let onCameraReady = EventDispatcher()
1035becae9d9SŁukasz Kosmaty
1036becae9d9SŁukasz Kosmaty  func callOnCameraReady() {
1037becae9d9SŁukasz Kosmaty    onCameraReady([
1038becae9d9SŁukasz Kosmaty      "message": "Camera was mounted"
1039becae9d9SŁukasz Kosmaty    ]);
1040becae9d9SŁukasz Kosmaty  }
1041becae9d9SŁukasz Kosmaty}
1042becae9d9SŁukasz Kosmaty```
1043becae9d9SŁukasz Kosmaty
1044becae9d9SŁukasz Kosmaty```kotlin
1045becae9d9SŁukasz Kosmatyclass CameraViewModule : Module() {
1046becae9d9SŁukasz Kosmaty  override fun definition() = ModuleDefinition {
1047becae9d9SŁukasz Kosmaty    View(ExpoCameraView::class) {
1048becae9d9SŁukasz Kosmaty      Events(
1049becae9d9SŁukasz Kosmaty        "onCameraReady"
1050becae9d9SŁukasz Kosmaty      )
1051becae9d9SŁukasz Kosmaty
1052becae9d9SŁukasz Kosmaty      // ...
1053becae9d9SŁukasz Kosmaty    }
1054becae9d9SŁukasz Kosmaty  }
1055becae9d9SŁukasz Kosmaty}
1056becae9d9SŁukasz Kosmaty
1057becae9d9SŁukasz Kosmatyclass CameraView(
1058becae9d9SŁukasz Kosmaty  context: Context,
1059becae9d9SŁukasz Kosmaty  appContext: AppContext
1060becae9d9SŁukasz Kosmaty) : ExpoView(context, appContext) {
1061becae9d9SŁukasz Kosmaty  val onCameraReady by EventDispatcher()
1062becae9d9SŁukasz Kosmaty
1063becae9d9SŁukasz Kosmaty  fun callOnCameraReady() {
1064becae9d9SŁukasz Kosmaty    onCameraReady(mapOf(
1065becae9d9SŁukasz Kosmaty      "message" to "Camera was mounted"
1066becae9d9SŁukasz Kosmaty    ));
1067becae9d9SŁukasz Kosmaty  }
1068becae9d9SŁukasz Kosmaty}
1069becae9d9SŁukasz Kosmaty```
1070becae9d9SŁukasz Kosmaty
1071becae9d9SŁukasz Kosmaty</CodeBlocksTable>
1072becae9d9SŁukasz Kosmaty
1073becae9d9SŁukasz KosmatyTo subscribe to these events in JavaScript/TypeScript, you need to pass a function to the native view as shown:
1074becae9d9SŁukasz Kosmaty
1075becae9d9SŁukasz Kosmaty```ts TypeScript
1076becae9d9SŁukasz Kosmatyimport { requireNativeViewManager } from 'expo-modules-core';
1077becae9d9SŁukasz Kosmaty
1078becae9d9SŁukasz Kosmatyconst CameraView = requireNativeViewManager('CameraView');
1079becae9d9SŁukasz Kosmaty
1080becae9d9SŁukasz Kosmatyexport default function MainView() {
1081becae9d9SŁukasz Kosmaty  const onCameraReady = event => {
1082becae9d9SŁukasz Kosmaty    console.log(event.nativeEvent);
1083becae9d9SŁukasz Kosmaty  };
1084becae9d9SŁukasz Kosmaty
1085becae9d9SŁukasz Kosmaty  return <CameraView onCameraReady={onCameraReady} />;
1086becae9d9SŁukasz Kosmaty}
1087becae9d9SŁukasz Kosmaty```
1088becae9d9SŁukasz Kosmaty
1089becae9d9SŁukasz KosmatyProvided payload is available under the `nativeEvent` key.
1090becae9d9SŁukasz Kosmaty
1091becae9d9SŁukasz Kosmaty</APIBox>
1092becae9d9SŁukasz Kosmaty
1093e98c3cdfSJon Samp## Examples
1094e98c3cdfSJon Samp
1095e98c3cdfSJon Samp<CodeBlocksTable>
1096e98c3cdfSJon Samp
1097e98c3cdfSJon Samp```swift
1098e98c3cdfSJon Samppublic class MyModule: Module {
1099e98c3cdfSJon Samp  public func definition() -> ModuleDefinition {
1100e98c3cdfSJon Samp    Name("MyFirstExpoModule")
1101e98c3cdfSJon Samp
1102e98c3cdfSJon Samp    Function("hello") { (name: String) in
1103e98c3cdfSJon Samp      return "Hello \(name)!"
1104e98c3cdfSJon Samp    }
1105e98c3cdfSJon Samp  }
1106e98c3cdfSJon Samp}
1107e98c3cdfSJon Samp```
1108e98c3cdfSJon Samp
1109e98c3cdfSJon Samp```kotlin
1110e98c3cdfSJon Sampclass MyModule : Module() {
1111e98c3cdfSJon Samp  override fun definition() = ModuleDefinition {
1112e98c3cdfSJon Samp    Name("MyFirstExpoModule")
1113e98c3cdfSJon Samp
1114e98c3cdfSJon Samp    Function("hello") { name: String ->
1115e98c3cdfSJon Samp      return "Hello $name!"
1116e98c3cdfSJon Samp    }
1117e98c3cdfSJon Samp  }
1118e98c3cdfSJon Samp}
1119e98c3cdfSJon Samp```
1120e98c3cdfSJon Samp
1121e98c3cdfSJon Samp</CodeBlocksTable>
1122e98c3cdfSJon Samp
1123e98c3cdfSJon SampFor more examples from real modules, you can refer to Expo modules that already use this API on GitHub:
1124e98c3cdfSJon Samp
1125c2250018SJakov Glavina- `expo-battery` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-battery/ios))
1126e98c3cdfSJon Samp- `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))
1127e98c3cdfSJon Samp- `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))
1128e98c3cdfSJon Samp- `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))
11296a04a9d0SJakov Glavina- `expo-device` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-device/ios))
1130e98c3cdfSJon Samp- `expo-haptics` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-haptics/ios))
1131e98c3cdfSJon Samp- `expo-image-manipulator` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-image-manipulator/ios))
1132e98c3cdfSJon Samp- `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))
1133e98c3cdfSJon Samp- `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))
1134e98c3cdfSJon Samp- `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))
1135fc141ba9SJakov Glavina- `expo-store-review` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-store-review/ios))
1136e98c3cdfSJon Samp- `expo-system-ui` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-system-ui/ios/ExpoSystemUI))
1137d4b26ac8SJakov Glavina- `expo-video-thumbnails` ([Swift](https://github.com/expo/expo/tree/main/packages/expo-video-thumbnails/ios))
1138e98c3cdfSJon Samp- `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))
1139