1 // Copyright 2015-present 650 Industries. All rights reserved.
2 package host.exp.exponent
3 
4 import android.util.Log
5 import com.facebook.proguard.annotations.DoNotStrip
6 import com.facebook.react.common.JavascriptException
7 import expo.modules.kotlin.devtools.ExpoNetworkInspectOkHttpAppInterceptor
8 import expo.modules.kotlin.devtools.ExpoNetworkInspectOkHttpNetworkInterceptor
9 import host.exp.exponent.network.ExponentNetwork
10 import host.exp.expoview.Exponent
11 import okhttp3.CookieJar
12 import okhttp3.OkHttpClient
13 import java.util.concurrent.TimeUnit
14 
15 @DoNotStrip
16 object ReactNativeStaticHelpers {
17   private val TAG = ReactNativeStaticHelpers::class.java.simpleName
18 
19   @DoNotStrip
20   @JvmStatic fun reloadFromManifest(activityId: Int) {
21     try {
22       Class.forName("host.exp.exponent.kernel.Kernel")
23         .getMethod("reloadVisibleExperience", Int::class.javaPrimitiveType)
24         .invoke(null, activityId)
25     } catch (e: Exception) {
26       Log.e("reloadFromManifest", "Unable to reload visible experience", e)
27     }
28   }
29 
30   @DoNotStrip
31   @JvmStatic fun getBundleUrlForActivityId(
32     activityId: Int,
33     host: String?,
34     mainModuleId: String?,
35     bundleTypeId: String?,
36     devMode: Boolean,
37     jsMinify: Boolean
38   ): String? {
39     return try {
40       Class.forName("host.exp.exponent.kernel.Kernel")
41         .getMethod(
42           "getBundleUrlForActivityId",
43           Int::class.javaPrimitiveType,
44           String::class.java,
45           String::class.java,
46           String::class.java,
47           Boolean::class.javaPrimitiveType,
48           Boolean::class.javaPrimitiveType
49         )
50         .invoke(null, activityId, host, mainModuleId, bundleTypeId, devMode, jsMinify) as String
51     } catch (e: Exception) {
52       null
53     }
54   }
55 
56   // <= SDK 25
57   @DoNotStrip
58   @JvmStatic fun getBundleUrlForActivityId(
59     activityId: Int,
60     host: String?,
61     jsModulePath: String?,
62     devMode: Boolean,
63     jsMinify: Boolean
64   ): String? {
65     return try {
66       Class.forName("host.exp.exponent.kernel.Kernel")
67         .getMethod(
68           "getBundleUrlForActivityId",
69           Int::class.javaPrimitiveType,
70           String::class.java,
71           String::class.java,
72           Boolean::class.javaPrimitiveType,
73           Boolean::class.javaPrimitiveType
74         )
75         .invoke(null, activityId, host, jsModulePath, devMode, jsMinify) as String
76     } catch (e: Exception) {
77       null
78     }
79   }
80 
81   // <= SDK 21
82   @DoNotStrip
83   @JvmStatic fun getBundleUrlForActivityId(
84     activityId: Int,
85     host: String?,
86     jsModulePath: String?,
87     devMode: Boolean,
88     hmr: Boolean,
89     jsMinify: Boolean
90   ): String? {
91     return try {
92       Class.forName("host.exp.exponent.kernel.Kernel")
93         .getMethod(
94           "getBundleUrlForActivityId",
95           Int::class.javaPrimitiveType,
96           String::class.java,
97           String::class.java,
98           Boolean::class.javaPrimitiveType,
99           Boolean::class.javaPrimitiveType,
100           Boolean::class.javaPrimitiveType
101         )
102         .invoke(null, activityId, host, jsModulePath, devMode, hmr, jsMinify) as String
103     } catch (e: Exception) {
104       null
105     }
106   }
107 
108   @DoNotStrip
109   @JvmStatic fun handleReactNativeError(
110     errorMessage: String?,
111     stackUnversioned: Any?,
112     exceptionId: Int?,
113     isFatal: Boolean?
114   ) {
115     try {
116       Class.forName("host.exp.exponent.kernel.Kernel").getMethod(
117         "handleReactNativeError",
118         String::class.java,
119         Any::class.java,
120         Int::class.java,
121         Boolean::class.java
122       ).invoke(null, errorMessage, stackUnversioned, exceptionId, isFatal)
123     } catch (e: Exception) {
124       throw JavascriptException(errorMessage)
125     }
126   }
127 
128   @DoNotStrip
129   @JvmStatic fun handleReactNativeError(
130     throwable: Throwable?,
131     errorMessage: String?,
132     stackUnversioned: Any?,
133     exceptionId: Int?,
134     isFatal: Boolean?
135   ) {
136     try {
137       Class.forName("host.exp.exponent.kernel.Kernel").getMethod(
138         "handleReactNativeError",
139         Throwable::class.java,
140         String::class.java,
141         Any::class.java,
142         Int::class.java,
143         Boolean::class.java
144       ).invoke(null, throwable, errorMessage, stackUnversioned, exceptionId, isFatal)
145     } catch (e: Exception) {
146       throw JavascriptException(errorMessage)
147     }
148   }
149 
150   @DoNotStrip
151   @JvmStatic fun getBundleSourceForPath(path: String?): String? {
152     return try {
153       Exponent.instance.getBundleSource(path!!)
154     } catch (e: Exception) {
155       null
156     }
157   }
158 
159   private var exponentNetwork: ExponentNetwork? = null
160   fun setExponentNetwork(exponentNetwork: ExponentNetwork?) {
161     this.exponentNetwork = exponentNetwork
162   }
163 
164   @DoNotStrip
165   @JvmStatic fun getOkHttpClient(callingClass: Class<*>): Any {
166     // we build the OkHttp client here so that one cache instance is shared by all concurrent OkHttp instances
167     val version = RNObject.versionForClassname(callingClass.name)
168     val cookieJar =
169       RNObject("com.facebook.react.modules.network.ReactCookieJarContainer").loadVersion(version)
170         .construct().get()
171     val client = OkHttpClient.Builder()
172       .connectTimeout(0, TimeUnit.MILLISECONDS)
173       .readTimeout(0, TimeUnit.MILLISECONDS)
174       .writeTimeout(0, TimeUnit.MILLISECONDS)
175       .cookieJar(cookieJar as CookieJar)
176       .cache(exponentNetwork!!.cache)
177       .addInterceptor(ExpoNetworkInspectOkHttpAppInterceptor())
178       .addNetworkInterceptor(ExpoNetworkInspectOkHttpNetworkInterceptor())
179     return client.build()
180   }
181 }
182