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 otherModules: List<NativeModule> 26 ): List<NativeModule> { 27 val reactApplicationContext = scopedContext.context as ReactApplicationContext 28 29 // We only use React application context, because we're detached -- no scopes 30 val moduleRegistry = mModuleRegistryProvider[reactApplicationContext] 31 32 moduleRegistry.registerInternalModule( 33 ConstantsBinding( 34 scopedContext, 35 experienceProperties, 36 manifest 37 ) 38 ) 39 40 // Overriding expo-updates UpdatesService 41 moduleRegistry.registerInternalModule(UpdatesBinding(scopedContext, experienceProperties)) 42 43 // ReactAdapterPackage requires ReactContext 44 val reactContext = scopedContext.context as ReactApplicationContext 45 for (internalModule in mReactAdapterPackage.createInternalModules(reactContext)) { 46 moduleRegistry.registerInternalModule(internalModule) 47 } 48 49 // Overriding ScopedUIManagerModuleWrapper from ReactAdapterPackage 50 moduleRegistry.registerInternalModule(ScopedUIManagerModuleWrapper(reactContext)) 51 52 // Overriding expo-secure-store 53 moduleRegistry.registerExportedModule(ScopedSecureStoreModule(scopedContext)) 54 55 // Certain notifications classes should share `SharedPreferences` object with the notifications services, so we don't want to use scoped context. 56 moduleRegistry.registerExportedModule(NotificationScheduler(scopedContext.baseContext)) 57 moduleRegistry.registerExportedModule(ExpoNotificationCategoriesModule(scopedContext.baseContext)) 58 moduleRegistry.registerExportedModule(NotificationsHandler(scopedContext.baseContext)) 59 // We consciously pass scoped context to ScopedServerRegistrationModule 60 // so it can access legacy scoped backed-up storage and migrates 61 // the legacy UUID to scoped non-backed-up storage. 62 moduleRegistry.registerExportedModule(ScopedServerRegistrationModule(scopedContext)) 63 64 // Adding other modules (not universal) to module registry as consumers. 65 // It allows these modules to refer to universal modules. 66 for (otherModule in otherModules) { 67 if (otherModule is RegistryLifecycleListener) { 68 moduleRegistry.registerExtraListener(otherModule as RegistryLifecycleListener) 69 } 70 } 71 configureModuleRegistry(moduleRegistry, reactApplicationContext) 72 return getNativeModulesFromModuleRegistry(reactApplicationContext, moduleRegistry) 73 } 74 75 protected open fun configureModuleRegistry( 76 moduleRegistry: ModuleRegistry, 77 reactContext: ReactApplicationContext 78 ) { 79 // Subclasses may add more modules here. 80 } 81 } 82