1# @unimodules/react-native-adapter 2 3A React Native adapter for Expo Universal Modules. It requires [`@unimodules/core`](https://github.com/expo/expo/tree/master/packages/@unimodules/core) to be installed and linked. 4 5## JavaScript installation 6 7```sh 8$ yarn add @unimodules/react-native-adapter 9 10# or 11 12$ npm install @unimodules/react-native-adapter --save 13``` 14 15## Installation 16 17If you are using `react-native-unimodules`, this package will already be installed and configured! 18 19### iOS (Cocoapods) 20 21If you're using Cocoapods, add the dependency to your `Podfile`: 22 23`pod 'UMReactNativeAdapter', path: '../node_modules/@unimodules/react-native-adapter/ios', inhibit_warnings: true` 24 25and run `npx pod-install`. 26 27### Android 28 291. Append the following lines to `android/settings.gradle`: 30 ```gradle 31 include ':unimodules-react-native-adapter' 32 project(':unimodules-react-native-adapter').projectDir = new File(rootProject.projectDir, '../node_modules/@unimodules/react-native-adapter/android') 33 ``` 342. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 35 ```gradle 36 compile project(':unimodules-react-native-adapter') 37 ``` 38 39## Additional required setup 40 41#### iOS 42 431. Open the `AppDelegate.m` of your application. 442. Import `<UMCore/UMModuleRegistry.h>`, `<UMReactNativeAdapter/UMNativeModulesProxy.h>` and `<UMReactNativeAdapter/UMModuleRegistryAdapter.h>`. 453. Make `AppDelegate` implement `RCTBridgeDelegate` protocol (`@interface AppDelegate () <RCTBridgeDelegate>`). 464. Add a new instance variable to your `AppDelegate`: 47 48 ```objc 49 @interface AppDelegate () <RCTBridgeDelegate> 50 51 // add this line 52 @property (nonatomic, strong) UMModuleRegistryAdapter *moduleRegistryAdapter; 53 54 @end 55 ``` 56 575. In `-application:didFinishLaunchingWithOptions:` add the following at the top of the implementation: 58 ```objc 59 self.moduleRegistryAdapter = [[UMModuleRegistryAdapter alloc] initWithModuleRegistryProvider:[[UMModuleRegistryProvider alloc] init]]; 60 ``` 616. Add two methods to the `AppDelegate`'s implementation: 62 63 ```objc 64 - (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge 65 { 66 NSArray<id<RCTBridgeModule>> *extraModules = [_moduleRegistryAdapter extraModulesForBridge:bridge andExperience:nil]; 67 // If you'd like to export some custom RCTBridgeModules that are not Expo modules, add them here! 68 return extraModules; 69 } 70 71 - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { 72 return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 73 } 74 ``` 75 767. When initializing `RCTBridge`, make the `AppDelegate` a delegate of the bridge: 77 ```objc 78 RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 79 ``` 808. That's it! All in all, your `AppDelegate.m` should look similar to: 81 82 <details> 83 <summary>Click to expand</summary> 84 <p> 85 86 ```objc 87 #import "AppDelegate.h" 88 89 #import <React/RCTBundleURLProvider.h> 90 #import <React/RCTRootView.h> 91 92 #import <UMCore/UMModuleRegistry.h> 93 #import <UMReactNativeAdapter/UMNativeModulesProxy.h> 94 #import <UMReactNativeAdapter/UMModuleRegistryAdapter.h> 95 96 @interface AppDelegate () <RCTBridgeDelegate> 97 98 @property (nonatomic, strong) UMModuleRegistryAdapter *moduleRegistryAdapter; 99 100 @end 101 102 @implementation AppDelegate 103 104 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 105 { 106 self.moduleRegistryAdapter = [[UMModuleRegistryAdapter alloc] initWithModuleRegistryProvider:[[UMModuleRegistryProvider alloc] init]]; 107 RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 108 RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"YOUR_MODULE_NAME" initialProperties:nil]; 109 rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 110 111 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 112 UIViewController *rootViewController = [UIViewController new]; 113 rootViewController.view = rootView; 114 self.window.rootViewController = rootViewController; 115 [self.window makeKeyAndVisible]; 116 return YES; 117 } 118 119 - (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge 120 { 121 NSArray<id<RCTBridgeModule>> *extraModules = [_moduleRegistryAdapter extraModulesForBridge:bridge andExperience:nil]; 122 // If you'd like to export some custom RCTBridgeModules that are not universal modules, add them here! 123 return extraModules; 124 } 125 126 - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { 127 return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 128 } 129 130 @end 131 ``` 132 133 </details> 134 135#### Android 136 1371. Open the `MainApplication.java` of your application. 1382. Add to the imports: 139 ```java 140 import org.unimodules.adapters.react.ModuleRegistryAdapter; 141 import org.unimodules.adapters.react.ReactAdapterPackage; 142 import org.unimodules.adapters.react.ReactModuleRegistryProvider; 143 import org.unimodules.core.interfaces.Package; 144 ``` 1453. Create an instance variable on the `Application`: 146 ```java 147 private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(Arrays.<Package>asList( 148 new ReactAdapterPackage() 149 // more packages, like 150 // new CameraPackage(), if you use expo-camera 151 // etc. 152 ), /* singletonModules */ null); 153 ``` 1544. Add `new ModuleRegistryAdapter(mModuleRegistryProvider)` to the list returned by `protected List<ReactPackage> getPackages()`. 1555. You're good to go! 156 157## Usage 158 159### Calling methods on native modules 160 161Native modules are available behind the proxy (`NativeModulesProxy` of `@unimodules/core`). 162 163To call an exported method, use `NativeModulesProxy[clientCodeName].exportedMethod(...arguments)`, like this: 164 165```js 166// For UM_REGISTER_MODULE(FileSystem,) or UM_REGISTER_UMPORTED_MODULE(FileSystem) 167// and UM_EXPORT_METHOD_AS(getInfo, getInfo:(NSString *)path) 168 169// or for method 170// @ExpoMethod 171// public void getInfo(String path, Promise promise) 172// defined in native module with name FileSystem 173 174import { NativeModulesProxy } from '@unimodules/core'; 175 176const { FileSystem } = NativeModulesProxy; 177 178FileSystem.getInfo('file:///...'); 179``` 180 181Note that all the methods return `Promise`s. 182 183### Synthetic Platform Events 184 185When creating web universal modules, you may find that you need to send events back to the API layer. 186In this case you will want to use the shared `SyntheticPlatformEmitter` instance from `@unimodules/core`. The shared emitter emit events to `react-native`'s `NativeEventEmitter` and `@unimodules/core`'s `EventEmitter` . 187 188`ExponentGyroscope.web.ts` 189 190```js 191// Example from expo-sensors native web gyroscope sensor 192 193import { SyntheticPlatformEmitter } from '@unimodules/core'; 194 195SyntheticPlatformEmitter.emit('gyroscopeDidUpdate', { x, y, z }); 196``` 197 198This emitted event is then received with a `EventEmitter` in the developer-facing API. 199 200```js 201import { EventEmitter } from '@unimodules/core'; 202 203import ExponentGyroscope from './ExponentGyroscope'; 204 205const nativeEmitter = new EventEmitter(ExponentGyroscope); 206 207// On Android and iOS, `nativeEmitter` receives events sent from Objective-C and Java. On web, it 208// receives events from the shared `SyntheticPlatformEmitter` instance. 209nativeEmitter.addListener('gyroscopeDidUpdate', ({ x, y, z }) => {}); 210``` 211