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