1import { NativeModules } from 'react-native'; 2const LegacyNativeProxy = NativeModules.NativeUnimoduleProxy; 3// Fixes `cannot find name 'global'.` in tests 4// @ts-ignore 5const ExpoNativeProxy = global.expo?.modules?.NativeModulesProxy; 6const modulesConstantsKey = 'modulesConstants'; 7const exportedMethodsKey = 'exportedMethods'; 8const NativeModulesProxy = {}; 9if (LegacyNativeProxy) { 10 // use JSI proxy if available, fallback to legacy RN proxy 11 const NativeProxy = ExpoNativeProxy ?? LegacyNativeProxy; 12 Object.keys(NativeProxy[exportedMethodsKey]).forEach((moduleName) => { 13 // copy constants 14 NativeModulesProxy[moduleName] = NativeProxy[modulesConstantsKey][moduleName] || {}; 15 // copy methods 16 NativeProxy[exportedMethodsKey][moduleName].forEach((methodInfo) => { 17 NativeModulesProxy[moduleName][methodInfo.name] = (...args) => { 18 // Use the new proxy to call methods on legacy modules, if possible. 19 if (ExpoNativeProxy?.callMethod) { 20 return ExpoNativeProxy.callMethod(moduleName, methodInfo.name, args); 21 } 22 // Otherwise fall back to the legacy proxy. 23 // This is deprecated and might be removed in SDK47 or later. 24 const { key, argumentsCount } = methodInfo; 25 if (argumentsCount !== args.length) { 26 return Promise.reject(new Error(`Native method ${moduleName}.${methodInfo.name} expects ${argumentsCount} ${argumentsCount === 1 ? 'argument' : 'arguments'} but received ${args.length}`)); 27 } 28 return LegacyNativeProxy.callMethod(moduleName, key, args); 29 }; 30 }); 31 // These are called by EventEmitter (which is a wrapper for NativeEventEmitter) 32 // only on iOS and they use iOS-specific native module, EXReactNativeEventEmitter. 33 // 34 // On Android only {start,stop}Observing are called on the native module 35 // and these should be exported as Expo methods. 36 // 37 // Before the RN 65, addListener/removeListeners weren't called on Android. However, it no longer stays true. 38 // See https://github.com/facebook/react-native/commit/f5502fbda9fe271ff6e1d0da773a3a8ee206a453. 39 // That's why, we check if the `EXReactNativeEventEmitter` exists and only if yes, we use it in the listener implementation. 40 // Otherwise, those methods are NOOP. 41 if (NativeModules.EXReactNativeEventEmitter) { 42 NativeModulesProxy[moduleName].addListener = (...args) => NativeModules.EXReactNativeEventEmitter.addProxiedListener(moduleName, ...args); 43 NativeModulesProxy[moduleName].removeListeners = (...args) => NativeModules.EXReactNativeEventEmitter.removeProxiedListeners(moduleName, ...args); 44 } 45 else { 46 // Fixes on Android: 47 // WARN `new NativeEventEmitter()` was called with a non-null argument without the required `addListener` method. 48 // WARN `new NativeEventEmitter()` was called with a non-null argument without the required `removeListeners` method. 49 NativeModulesProxy[moduleName].addListener = () => { }; 50 NativeModulesProxy[moduleName].removeListeners = () => { }; 51 } 52 }); 53} 54else { 55 console.warn(`The "EXNativeModulesProxy" native module is not exported through NativeModules; verify that expo-modules-core's native code is linked properly`); 56} 57export default NativeModulesProxy; 58//# sourceMappingURL=NativeModulesProxy.native.js.map