1 // Copyright 2015-present 650 Industries. All rights reserved. 2 3 package versioned.host.exp.exponent 4 5 import com.facebook.react.ReactInstanceManager 6 import com.facebook.react.bridge.Inspector 7 import com.facebook.react.devsupport.DevServerHelper 8 import com.facebook.react.devsupport.DevSupportManagerBase 9 import com.facebook.react.devsupport.InspectorPackagerConnection 10 import expo.modules.kotlin.devtools.ExpoRequestCdpInterceptor 11 import expo.modules.manifests.core.Manifest 12 import java.io.Closeable 13 14 @Suppress("unused") 15 class ExpoNetworkInterceptor : Closeable, ExpoRequestCdpInterceptor.Delegate { 16 private var isStarted = false 17 private val inspectorPackagerConnection = InspectorPackagerConnectionWrapper() 18 private var reactInstanceManager: ReactInstanceManager? = null 19 startnull20 fun start(manifest: Manifest, reactInstanceManager: ReactInstanceManager) { 21 val buildProps = (manifest?.getPluginProperties("expo-build-properties")?.get("android") as? Map<*, *>) 22 ?.mapKeys { it.key.toString() } 23 val enableNetworkInspector = buildProps?.get("networkInspector") as? Boolean ?: true 24 isStarted = enableNetworkInspector 25 26 this.onResume(reactInstanceManager) 27 } 28 onResumenull29 fun onResume(reactInstanceManager: ReactInstanceManager) { 30 if (!isStarted || !reactInstanceManager.devSupportManager.devSupportEnabled) { 31 return 32 } 33 this.reactInstanceManager = reactInstanceManager 34 ExpoRequestCdpInterceptor.setDelegate(this) 35 } 36 onPausenull37 fun onPause() { 38 if (!isStarted) { 39 return 40 } 41 ExpoRequestCdpInterceptor.setDelegate(null) 42 this.reactInstanceManager = null 43 } 44 closenull45 override fun close() { 46 this.onPause() 47 } 48 dispatchnull49 override fun dispatch(event: String) { 50 reactInstanceManager?.let { 51 inspectorPackagerConnection.sendWrappedEventToAllPages(it, event) 52 } 53 } 54 } 55 56 /** 57 * A `InspectorPackagerConnection` wrapper to expose private members with reflection 58 */ 59 internal class InspectorPackagerConnectionWrapper { 60 private val devServerHelperField = DevSupportManagerBase::class.java.getDeclaredField("mDevServerHelper") 61 private val inspectorPackagerConnectionField = DevServerHelper::class.java.getDeclaredField("mInspectorPackagerConnection") 62 private val sendWrappedEventMethod = InspectorPackagerConnection::class.java.getDeclaredMethod("sendWrappedEvent", String::class.java, String::class.java) 63 64 init { 65 devServerHelperField.isAccessible = true 66 inspectorPackagerConnectionField.isAccessible = true 67 sendWrappedEventMethod.isAccessible = true 68 } 69 sendWrappedEventToAllPagesnull70 fun sendWrappedEventToAllPages(reactInstanceManager: ReactInstanceManager, event: String) { 71 val devServerHelper = devServerHelperField[reactInstanceManager.devSupportManager] 72 val inspectorPackagerConnection = inspectorPackagerConnectionField[devServerHelper] as? InspectorPackagerConnection 73 for (page in Inspector.getPages()) { 74 if (!page.title.contains("Reanimated")) { 75 sendWrappedEventMethod.invoke(inspectorPackagerConnection, page.id.toString(), event) 76 } 77 } 78 } 79 } 80