1 | # expo-react-native-adapter
|
2 |
|
3 | A React Native adapter for Expo Universal Modules. It requires [`expo-core`](https://github.com/expo/expo-core) to be installed and linked.
|
4 |
|
5 | **Note:** The following installation/setup instructions are only applicable to plain React Native applications, i. e. if your project is a detached Expo project and it has ExpoKit/expoview included, the installation has already been done for you.
|
6 |
|
7 | ## JavaScript installation
|
8 |
|
9 | ```sh
|
10 | $ yarn add expo-react-native-adapter
|
11 |
|
12 | # or
|
13 |
|
14 | $ npm install expo-react-native-adapter --save
|
15 | ```
|
16 |
|
17 | ## Installation
|
18 |
|
19 | ### iOS (Cocoapods)
|
20 |
|
21 | If you're using Cocoapods, add the dependency to your `Podfile`:
|
22 |
|
23 | `pod 'EXReactNativeAdapter', path: '../node_modules/expo-react-native-adapter/ios', inhibit_warnings: true`
|
24 |
|
25 | and run `pod install`.
|
26 |
|
27 | ### iOS (no Cocoapods) _[this method is currently not supported, sorry]_
|
28 |
|
29 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]`
|
30 | 2. Go to `node_modules` ➜ `expo-react-native-adapter` and add `EXReactNativeAdapter.xcodeproj`
|
31 | 3. In XCode, in the project navigator, select your project. Add `libEXReactNativeAdapter.a` to your project's `Build Phases` ➜ `Link Binary With Libraries`
|
32 | 4. Run your project (`Cmd+R`).
|
33 |
|
34 | ### Android
|
35 |
|
36 | 1. Append the following lines to `android/settings.gradle`:
|
37 | ```gradle
|
38 | include ':expo-react-native-adapter'
|
39 | project(':expo-react-native-adapter').projectDir = new File(rootProject.projectDir, '../node_modules/expo-react-native-adapter/android')
|
40 | ```
|
41 | 2. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
|
42 | ```gradle
|
43 | compile project(':expo-react-native-adapter')
|
44 | ```
|
45 |
|
46 | ## Additional required setup
|
47 |
|
48 | #### iOS
|
49 |
|
50 | 1. Open the `AppDelegate.m` of your application.
|
51 | 2. Import `<EXCore/EXModuleRegistry.h>`, `<EXReactNativeAdapter/EXNativeModulesProxy.h>` and `<EXReactNativeAdapter/EXModuleRegistryAdapter.h>`.
|
52 | 3. Make `AppDelegate` implement `RCTBridgeDelegate` protocol (`@interface AppDelegate () <RCTBridgeDelegate>`).
|
53 | 4. Add a new instance variable to your `AppDelegate`:
|
54 | ```objc
|
55 | @interface AppDelegate () <RCTBridgeDelegate>
|
56 |
|
57 | // add this line
|
58 | @property (nonatomic, strong) EXModuleRegistryAdapter *moduleRegistryAdapter;
|
59 |
|
60 | @end
|
61 | ```
|
62 | 5. In `-application:didFinishLaunchingWithOptions:` add the following at the top of the implementation:
|
63 | ```objc
|
64 | self.moduleRegistryAdapter = [[EXModuleRegistryAdapter alloc] initWithModuleRegistryProvider:[[EXModuleRegistryProvider alloc] init]];
|
65 | ```
|
66 | 4. Add two methods to the `AppDelegate`'s implementation:
|
67 | ```objc
|
68 | - (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
69 | {
|
70 | NSArray<id<RCTBridgeModule>> *extraModules = [_moduleRegistryAdapter extraModulesForBridge:bridge andExperience:nil];
|
71 | // If you'd like to export some custom RCTBridgeModules that are not Expo modules, add them here!
|
72 | return extraModules;
|
73 | }
|
74 |
|
75 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
|
76 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
77 | }
|
78 | ```
|
79 | 5. When initializing `RCTBridge`, make the `AppDelegate` a delegate of the bridge:
|
80 | ```objc
|
81 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
82 | ```
|
83 | 6. That's it! All in all, your `AppDelegate.m` should look similar to:
|
84 | <details>
|
85 | <summary>Click to expand</summary>
|
86 | <p>
|
87 |
|
88 | ```objc
|
89 | #import "AppDelegate.h"
|
90 |
|
91 | #import <React/RCTBundleURLProvider.h>
|
92 | #import <React/RCTRootView.h>
|
93 |
|
94 | #import <EXCore/EXModuleRegistry.h>
|
95 | #import <EXReactNativeAdapter/EXNativeModulesProxy.h>
|
96 | #import <EXReactNativeAdapter/EXModuleRegistryAdapter.h>
|
97 |
|
98 | @interface AppDelegate () <RCTBridgeDelegate>
|
99 |
|
100 | @property (nonatomic, strong) EXModuleRegistryAdapter *moduleRegistryAdapter;
|
101 |
|
102 | @end
|
103 |
|
104 | @implementation AppDelegate
|
105 |
|
106 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
107 | {
|
108 | self.moduleRegistryAdapter = [[EXModuleRegistryAdapter alloc] initWithModuleRegistryProvider:[[EXModuleRegistryProvider alloc] init]];
|
109 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
110 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"YOUR_MODULE_NAME" initialProperties:nil];
|
111 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
|
112 |
|
113 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
114 | UIViewController *rootViewController = [UIViewController new];
|
115 | rootViewController.view = rootView;
|
116 | self.window.rootViewController = rootViewController;
|
117 | [self.window makeKeyAndVisible];
|
118 | return YES;
|
119 | }
|
120 |
|
121 | - (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
|
122 | {
|
123 | NSArray<id<RCTBridgeModule>> *extraModules = [_moduleRegistryAdapter extraModulesForBridge:bridge andExperience:nil];
|
124 | // If you'd like to export some custom RCTBridgeModules that are not Expo modules, add them here!
|
125 | return extraModules;
|
126 | }
|
127 |
|
128 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
|
129 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
130 | }
|
131 |
|
132 | @end
|
133 | ```
|
134 |
|
135 | </details>
|
136 |
|
137 | #### Android
|
138 |
|
139 | 1. Open the `MainApplication.java` of your application.
|
140 | 2. Add to the imports:
|
141 | ```java
|
142 | import expo.adapters.react.ModuleRegistryAdapter;
|
143 | import expo.adapters.react.ReactAdapterPackage;
|
144 | import expo.core.ModuleRegistryProvider;
|
145 | import expo.core.interfaces.Package;
|
146 | ```
|
147 | 3. Create an instance variable on the `Application`:
|
148 | ```java
|
149 | private final ModuleRegistryProvider mModuleRegistryProvider = new ModuleRegistryProvider(Arrays.<Package>asList(
|
150 | new ReactAdapterPackage(),
|
151 | // more packages, like
|
152 | // new CameraPackage(), if you use expo-camera
|
153 | // etc.
|
154 | ));
|
155 | ```
|
156 | 4. Add `new ModuleRegistryAdapter(mModuleRegistryProvider)` to the list returned by `protected List<ReactPackage> getPackages()`.
|
157 | 5. You're good to go!
|
158 |
|
159 | ## Usage
|
160 |
|
161 | ### Calling methods on native modules
|
162 |
|
163 | Native modules are available behind the proxy (`NativeModulesProxy` of `expo-core`).
|
164 |
|
165 | To call an exported method, use `NativeModulesProxy[clientCodeName].exportedMethod(...arguments)`, like this:
|
166 |
|
167 | ```js
|
168 | // For EX_REGISTER_MODULE(FileSystem,) or EX_REGISTER_EXPORTED_MODULE(FileSystem)
|
169 | // and EX_EXPORT_METHOD_AS(getInfo, getInfo:(NSString *)path)
|
170 |
|
171 | // or for method
|
172 | // @ExpoMethod
|
173 | // public void getInfo(String path, Promise promise)
|
174 | // defined in native module with name FileSystem
|
175 |
|
176 | import { NativeModulesProxy } from 'expo-core';
|
177 |
|
178 | const { FileSystem } = NativeModulesProxy;
|
179 |
|
180 | FileSystem.getInfo("file:///...");
|
181 | ```
|
182 |
|
183 | Note that all the methods return `Promise`s.
|