1 // Copyright 2015-present 650 Industries. All rights reserved. 2 package host.exp.exponent.di 3 4 import android.app.Application 5 import android.content.Context 6 import android.os.Handler 7 import android.os.Looper 8 import com.facebook.proguard.annotations.DoNotStrip 9 import expo.modules.updates.db.DatabaseHolder 10 import expo.modules.updates.db.UpdatesDatabase 11 import host.exp.exponent.ExpoHandler 12 import host.exp.exponent.ExponentManifest 13 import host.exp.exponent.analytics.EXL 14 import host.exp.exponent.kernel.services.ExpoKernelServiceRegistry 15 import host.exp.exponent.network.ExponentNetwork 16 import host.exp.exponent.storage.ExponentSharedPreferences 17 import java.lang.reflect.Field 18 import javax.inject.Inject 19 20 class NativeModuleDepsProvider(application: Application) { 21 @Inject 22 @DoNotStrip 23 val mContext: Context = application 24 25 @Inject 26 @DoNotStrip 27 val mApplicationContext: Application = application 28 29 @Inject 30 @DoNotStrip 31 val mExpoHandler: ExpoHandler = ExpoHandler(Handler(Looper.getMainLooper())) 32 33 @Inject 34 @DoNotStrip 35 val mExponentSharedPreferences: ExponentSharedPreferences = ExponentSharedPreferences(mContext) 36 37 @Inject 38 @DoNotStrip 39 val mExponentNetwork: ExponentNetwork = ExponentNetwork(mContext, mExponentSharedPreferences) 40 41 @Inject 42 @DoNotStrip 43 var mExponentManifest: ExponentManifest = ExponentManifest(mContext, mExponentSharedPreferences) 44 45 @Inject 46 @DoNotStrip 47 var mKernelServiceRegistry: ExpoKernelServiceRegistry = ExpoKernelServiceRegistry(mContext, mExponentSharedPreferences) 48 49 @Inject 50 @DoNotStrip 51 val mUpdatesDatabaseHolder: DatabaseHolder = DatabaseHolder(UpdatesDatabase.getInstance(mContext)) 52 53 private val classToInstanceMap = mutableMapOf<Class<*>, Any>() 54 addnull55 fun add(clazz: Class<*>, instance: Any) { 56 classToInstanceMap[clazz] = instance 57 } 58 injectnull59 fun inject(clazz: Class<*>, target: Any) { 60 for (field in clazz.declaredFields) { 61 injectFieldInTarget(target, field) 62 } 63 } 64 injectFieldInTargetnull65 private fun injectFieldInTarget(target: Any, field: Field) { 66 if (field.isAnnotationPresent(Inject::class.java)) { 67 val fieldClazz = field.type 68 if (!classToInstanceMap.containsKey(fieldClazz)) { 69 throw RuntimeException("NativeModuleDepsProvider could not find object for class $fieldClazz") 70 } 71 val instance = classToInstanceMap[fieldClazz] 72 try { 73 field.isAccessible = true 74 field[target] = instance 75 } catch (e: IllegalAccessException) { 76 EXL.e(TAG, e.toString()) 77 } 78 } 79 } 80 81 companion object { 82 private val TAG = NativeModuleDepsProvider::class.java.simpleName 83 84 @JvmStatic lateinit var instance: NativeModuleDepsProvider 85 private set 86 87 private var useTestInstance = false 88 initializenull89 fun initialize(application: Application) { 90 if (!useTestInstance) { 91 instance = NativeModuleDepsProvider(application) 92 } 93 } 94 95 // Only for testing! setTestInstancenull96 fun setTestInstance(instance: NativeModuleDepsProvider) { 97 Companion.instance = instance 98 useTestInstance = true 99 } 100 } 101 102 init { fieldnull103 for (field in NativeModuleDepsProvider::class.java.declaredFields) { 104 if (field.isAnnotationPresent(Inject::class.java)) { 105 try { 106 classToInstanceMap[field.type] = field[this] 107 } catch (e: IllegalAccessException) { 108 EXL.e(TAG, e.toString()) 109 } 110 } 111 } 112 } 113 } 114