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