137917d47SŁukasz Kosmatyimport { NativeModules } from 'react-native'; 237917d47SŁukasz Kosmaty 3bd0cffe7STomasz Sapetaimport { ProxyNativeModule } from './NativeModulesProxy.types'; 437917d47SŁukasz Kosmaty 5*8bd57a9aSŁukasz Kosmaty// Fixes `cannot find name 'global'.` in tests 6*8bd57a9aSŁukasz Kosmaty// @ts-ignore 7380376eaSBartłomiej Klocekconst ExpoNativeProxy = global.ExpoModules?.NativeModulesProxy; 8380376eaSBartłomiej Klocekconst LegacyNativeProxy = NativeModules.NativeUnimoduleProxy; 9380376eaSBartłomiej Klocek 1037917d47SŁukasz Kosmatyconst modulesConstantsKey = 'modulesConstants'; 1137917d47SŁukasz Kosmatyconst exportedMethodsKey = 'exportedMethods'; 1237917d47SŁukasz Kosmaty 1337917d47SŁukasz Kosmatyconst NativeModulesProxy: { [moduleName: string]: ProxyNativeModule } = {}; 1437917d47SŁukasz Kosmaty 15380376eaSBartłomiej Klocekif (LegacyNativeProxy) { 16380376eaSBartłomiej Klocek // use JSI proxy if available, fallback to legacy RN proxy 17380376eaSBartłomiej Klocek const NativeProxy = ExpoNativeProxy ?? LegacyNativeProxy; 18380376eaSBartłomiej Klocek 1935f78160SBartosz Kaszubowski Object.keys(NativeProxy[exportedMethodsKey]).forEach((moduleName) => { 20380376eaSBartłomiej Klocek // copy constants 2137917d47SŁukasz Kosmaty NativeModulesProxy[moduleName] = NativeProxy[modulesConstantsKey][moduleName] || {}; 22380376eaSBartłomiej Klocek 23380376eaSBartłomiej Klocek // copy methods 2435f78160SBartosz Kaszubowski NativeProxy[exportedMethodsKey][moduleName].forEach((methodInfo) => { 2537917d47SŁukasz Kosmaty NativeModulesProxy[moduleName][methodInfo.name] = (...args: unknown[]): Promise<any> => { 2637917d47SŁukasz Kosmaty const { key, argumentsCount } = methodInfo; 2737917d47SŁukasz Kosmaty if (argumentsCount !== args.length) { 2837917d47SŁukasz Kosmaty return Promise.reject( 2937917d47SŁukasz Kosmaty new Error( 3037917d47SŁukasz Kosmaty `Native method ${moduleName}.${methodInfo.name} expects ${argumentsCount} ${ 3137917d47SŁukasz Kosmaty argumentsCount === 1 ? 'argument' : 'arguments' 3237917d47SŁukasz Kosmaty } but received ${args.length}` 3337917d47SŁukasz Kosmaty ) 3437917d47SŁukasz Kosmaty ); 3537917d47SŁukasz Kosmaty } 36380376eaSBartłomiej Klocek 37380376eaSBartłomiej Klocek // We still want to call methods using the legacy proxy in SDK 46 38380376eaSBartłomiej Klocek return LegacyNativeProxy.callMethod(moduleName, key, args); 3937917d47SŁukasz Kosmaty }; 4037917d47SŁukasz Kosmaty }); 4137917d47SŁukasz Kosmaty 4237917d47SŁukasz Kosmaty // These are called by EventEmitter (which is a wrapper for NativeEventEmitter) 4337917d47SŁukasz Kosmaty // only on iOS and they use iOS-specific native module, EXReactNativeEventEmitter. 4437917d47SŁukasz Kosmaty // 4537917d47SŁukasz Kosmaty // On Android only {start,stop}Observing are called on the native module 4637917d47SŁukasz Kosmaty // and these should be exported as Expo methods. 471036dd0aSŁukasz Kosmaty // 481036dd0aSŁukasz Kosmaty // Before the RN 65, addListener/removeListeners weren't called on Android. However, it no longer stays true. 491036dd0aSŁukasz Kosmaty // See https://github.com/facebook/react-native/commit/f5502fbda9fe271ff6e1d0da773a3a8ee206a453. 501036dd0aSŁukasz Kosmaty // That's why, we check if the `EXReactNativeEventEmitter` exists and only if yes, we use it in the listener implementation. 511036dd0aSŁukasz Kosmaty // Otherwise, those methods are NOOP. 521036dd0aSŁukasz Kosmaty if (NativeModules.EXReactNativeEventEmitter) { 5337917d47SŁukasz Kosmaty NativeModulesProxy[moduleName].addListener = (...args) => 5470c51132SKudo Chien NativeModules.EXReactNativeEventEmitter.addProxiedListener(moduleName, ...args); 5537917d47SŁukasz Kosmaty NativeModulesProxy[moduleName].removeListeners = (...args) => 5670c51132SKudo Chien NativeModules.EXReactNativeEventEmitter.removeProxiedListeners(moduleName, ...args); 571036dd0aSŁukasz Kosmaty } else { 581036dd0aSŁukasz Kosmaty // Fixes on Android: 591036dd0aSŁukasz Kosmaty // WARN `new NativeEventEmitter()` was called with a non-null argument without the required `addListener` method. 601036dd0aSŁukasz Kosmaty // WARN `new NativeEventEmitter()` was called with a non-null argument without the required `removeListeners` method. 611036dd0aSŁukasz Kosmaty NativeModulesProxy[moduleName].addListener = () => {}; 621036dd0aSŁukasz Kosmaty NativeModulesProxy[moduleName].removeListeners = () => {}; 631036dd0aSŁukasz Kosmaty } 6437917d47SŁukasz Kosmaty }); 6537917d47SŁukasz Kosmaty} else { 6637917d47SŁukasz Kosmaty console.warn( 67e7f22797STomasz Sapeta `The "EXNativeModulesProxy" native module is not exported through NativeModules; verify that expo-modules-core's native code is linked properly` 6837917d47SŁukasz Kosmaty ); 6937917d47SŁukasz Kosmaty} 7037917d47SŁukasz Kosmaty 7137917d47SŁukasz Kosmatyexport default NativeModulesProxy; 72