1 package host.exp.exponent.experience 2 3 import com.facebook.react.bridge.NativeModule 4 import com.facebook.react.bridge.ReactApplicationContext 5 import expo.modules.adapters.react.ReactModuleRegistryProvider 6 import expo.modules.core.ModuleRegistry 7 import expo.modules.core.interfaces.RegistryLifecycleListener 8 import expo.modules.notifications.notifications.categories.ExpoNotificationCategoriesModule 9 import expo.modules.notifications.notifications.handling.NotificationsHandler 10 import expo.modules.notifications.notifications.scheduling.NotificationScheduler 11 import host.exp.exponent.utils.ScopedContext 12 import host.exp.exponent.kernel.ExperienceKey 13 import expo.modules.manifests.core.Manifest 14 import versioned.host.exp.exponent.modules.universal.* 15 import versioned.host.exp.exponent.modules.universal.notifications.ScopedServerRegistrationModule 16 17 open class DetachedModuleRegistryAdapter(moduleRegistryProvider: ReactModuleRegistryProvider) : 18 ExpoModuleRegistryAdapter(moduleRegistryProvider) { 19 20 override fun createNativeModules( 21 scopedContext: ScopedContext, 22 experienceKey: ExperienceKey, 23 experienceProperties: Map<String, Any?>, 24 manifest: Manifest, 25 experienceStableLegacyId: String, 26 otherModules: List<NativeModule> 27 ): List<NativeModule> { 28 val reactApplicationContext = scopedContext.context as ReactApplicationContext 29 30 // We only use React application context, because we're detached -- no scopes 31 val moduleRegistry = mModuleRegistryProvider[scopedContext] 32 33 moduleRegistry.registerInternalModule( 34 ConstantsBinding( 35 scopedContext, 36 experienceProperties, 37 manifest 38 ) 39 ) 40 41 // Overriding expo-updates UpdatesService 42 moduleRegistry.registerInternalModule(UpdatesBinding(scopedContext, experienceProperties)) 43 44 // ReactAdapterPackage requires ReactContext 45 val reactContext = scopedContext.context as ReactApplicationContext 46 for (internalModule in mReactAdapterPackage.createInternalModules(reactContext)) { 47 moduleRegistry.registerInternalModule(internalModule) 48 } 49 50 // Overriding ScopedUIManagerModuleWrapper from ReactAdapterPackage 51 moduleRegistry.registerInternalModule(ScopedUIManagerModuleWrapper(reactContext)) 52 53 // Overriding expo-file-system FileSystemModule 54 moduleRegistry.registerExportedModule(ScopedFileSystemModule(scopedContext)) 55 56 // Overriding expo-secure-store 57 moduleRegistry.registerExportedModule(ScopedSecureStoreModule(scopedContext)) 58 59 // Certain notifications classes should share `SharedPreferences` object with the notifications services, so we don't want to use scoped context. 60 moduleRegistry.registerExportedModule(NotificationScheduler(scopedContext.baseContext)) 61 moduleRegistry.registerExportedModule(ExpoNotificationCategoriesModule(scopedContext.baseContext)) 62 moduleRegistry.registerExportedModule(NotificationsHandler(scopedContext.baseContext)) 63 // We consciously pass scoped context to ScopedServerRegistrationModule 64 // so it can access legacy scoped backed-up storage and migrates 65 // the legacy UUID to scoped non-backed-up storage. 66 moduleRegistry.registerExportedModule(ScopedServerRegistrationModule(scopedContext)) 67 68 // Adding other modules (not universal) to module registry as consumers. 69 // It allows these modules to refer to universal modules. 70 for (otherModule in otherModules) { 71 if (otherModule is RegistryLifecycleListener) { 72 moduleRegistry.registerExtraListener(otherModule as RegistryLifecycleListener) 73 } 74 } 75 configureModuleRegistry(moduleRegistry, reactApplicationContext) 76 return getNativeModulesFromModuleRegistry(reactApplicationContext, moduleRegistry) 77 } 78 79 protected open fun configureModuleRegistry( 80 moduleRegistry: ModuleRegistry, 81 reactContext: ReactApplicationContext 82 ) { 83 // Subclasses may add more modules here. 84 } 85 } 86