@hot-updater/react-native 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HotUpdater.podspec +1 -2
- package/android/build.gradle +16 -3
- package/android/generated/java/com/hotupdater/NativeHotUpdaterSpec.java +54 -0
- package/android/generated/jni/CMakeLists.txt +36 -0
- package/android/generated/jni/HotUpdaterSpec-generated.cpp +56 -0
- package/android/generated/jni/HotUpdaterSpec.h +31 -0
- package/android/generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI-generated.cpp +57 -0
- package/android/generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI.h +103 -0
- package/android/react-native-helpers.gradle +42 -0
- package/android/src/main/java/com/hotupdater/HotUpdater.kt +151 -240
- package/android/src/main/java/com/hotupdater/HotUpdaterModule.kt +52 -40
- package/android/src/main/java/com/hotupdater/HotUpdaterPackage.kt +25 -24
- package/android/src/main/java/com/hotupdater/ReactIntegrationManagerBase.kt +34 -0
- package/android/src/newarch/HotUpdaterSpec.kt +3 -2
- package/android/src/newarch/ReactIntegrationManager.kt +46 -0
- package/android/src/oldarch/HotUpdaterSpec.kt +12 -8
- package/android/src/oldarch/ReactIntegrationManager.kt +41 -0
- package/dist/index.d.mts +71 -0
- package/dist/index.d.ts +43 -52
- package/dist/index.js +2366 -139
- package/dist/index.mjs +2411 -0
- package/ios/HotUpdater/HotUpdater.h +8 -4
- package/ios/HotUpdater/HotUpdater.mm +167 -116
- package/ios/generated/HotUpdaterSpec/HotUpdaterSpec-generated.mm +67 -0
- package/ios/generated/HotUpdaterSpec/HotUpdaterSpec.h +67 -0
- package/ios/generated/HotUpdaterSpecJSI-generated.cpp +57 -0
- package/ios/generated/HotUpdaterSpecJSI.h +103 -0
- package/package.json +26 -10
- package/react-native.config.js +12 -0
- package/src/const.ts +1 -0
- package/src/ensureBundles.ts +21 -0
- package/src/global.d.ts +3 -0
- package/src/index.ts +27 -5
- package/src/init.tsx +25 -7
- package/src/native.ts +50 -42
- package/src/specs/{NativeHotUpdaterModule.ts → NativeHotUpdater.ts} +6 -7
- package/src/store.ts +48 -0
- package/dist/index.cjs +0 -220
- package/dist/index.d.cts +0 -80
- package/src/checkForUpdate.test.ts +0 -517
- package/src/checkForUpdate.ts +0 -111
- package/src/utils.ts +0 -2
|
@@ -5,286 +5,197 @@ import android.content.Context
|
|
|
5
5
|
import android.os.Handler
|
|
6
6
|
import android.os.Looper
|
|
7
7
|
import android.util.Log
|
|
8
|
-
import
|
|
9
|
-
import com.facebook.react.
|
|
10
|
-
import com.facebook.react.
|
|
11
|
-
import com.facebook.react.bridge.
|
|
8
|
+
import android.view.View
|
|
9
|
+
import com.facebook.react.ReactApplication
|
|
10
|
+
import com.facebook.react.ReactPackage
|
|
11
|
+
import com.facebook.react.bridge.NativeModule
|
|
12
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
13
|
+
import com.facebook.react.uimanager.ReactShadowNode
|
|
14
|
+
import com.facebook.react.uimanager.ViewManager
|
|
12
15
|
import java.io.File
|
|
13
|
-
import java.
|
|
16
|
+
import java.net.HttpURLConnection
|
|
14
17
|
import java.net.URL
|
|
15
18
|
import java.util.zip.ZipFile
|
|
16
19
|
|
|
17
|
-
class HotUpdater
|
|
18
|
-
|
|
19
|
-
private val mReactNativeHost: ReactNativeHost = reactNativeHost
|
|
20
|
+
class HotUpdater : ReactPackage {
|
|
21
|
+
override fun createViewManagers(context: ReactApplicationContext): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
fun init(context: Context, reactNativeHost: ReactNativeHost): HotUpdater {
|
|
25
|
-
Log.d("HotUpdater", "Initializing HotUpdater")
|
|
26
|
-
|
|
27
|
-
return mCurrentInstance
|
|
28
|
-
?: synchronized(this) {
|
|
29
|
-
mCurrentInstance
|
|
30
|
-
?: HotUpdater(context, reactNativeHost).also {
|
|
31
|
-
mCurrentInstance = it
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fun getAppVersion(): String? {
|
|
37
|
-
return mCurrentInstance?.getAppVersion()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
fun initializeOnAppUpdate() {
|
|
41
|
-
mCurrentInstance?.initializeOnAppUpdate()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
fun reload() {
|
|
45
|
-
mCurrentInstance?.reload()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
fun getJSBundleFile(): String? {
|
|
49
|
-
Log.d("HotUpdater", "Getting JS bundle file ${mCurrentInstance?.getBundleURL()}")
|
|
50
|
-
return mCurrentInstance?.getBundleURL()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
fun getBundleVersion(): Double? {
|
|
54
|
-
return mCurrentInstance?.getBundleVersion()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
fun updateBundle(prefix: String, url: String?): Boolean? {
|
|
58
|
-
return mCurrentInstance?.updateBundle(prefix, url)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
private val documentsDir: String
|
|
63
|
-
get() = mContext.getExternalFilesDir(null)?.absolutePath ?: mContext.filesDir.absolutePath
|
|
64
|
-
|
|
65
|
-
private fun convertFileSystemPathFromBasePath(basePath: String): String {
|
|
66
|
-
val separator = if (basePath.startsWith("/")) "" else "/"
|
|
67
|
-
return "$documentsDir$separator$basePath"
|
|
68
|
-
}
|
|
23
|
+
override fun createNativeModules(context: ReactApplicationContext): MutableList<NativeModule> =
|
|
24
|
+
listOf(HotUpdaterModule(context)).toMutableList()
|
|
69
25
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
26
|
+
companion object {
|
|
27
|
+
private fun convertFileSystemPathFromBasePath(
|
|
28
|
+
context: Context,
|
|
29
|
+
basePath: String,
|
|
30
|
+
): String {
|
|
31
|
+
val documentsDir = context.getExternalFilesDir(null)?.absolutePath ?: context.filesDir.absolutePath
|
|
32
|
+
val separator = if (basePath.startsWith("/")) "" else "/"
|
|
33
|
+
|
|
34
|
+
return "$documentsDir$separator$basePath"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private fun stripPrefixFromPath(
|
|
38
|
+
prefix: String,
|
|
39
|
+
path: String,
|
|
40
|
+
): String =
|
|
41
|
+
if (path.startsWith("/$prefix/")) {
|
|
42
|
+
path.replaceFirst("/$prefix/", "")
|
|
43
|
+
} else {
|
|
44
|
+
path
|
|
45
|
+
}
|
|
77
46
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (currentActivity == null) {
|
|
82
|
-
return
|
|
47
|
+
fun getAppVersion(context: Context): String? {
|
|
48
|
+
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
|
49
|
+
return packageInfo.versionName
|
|
83
50
|
}
|
|
84
51
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
52
|
+
private fun setBundleURL(
|
|
53
|
+
context: Context,
|
|
54
|
+
bundleURL: String?,
|
|
55
|
+
) {
|
|
56
|
+
val sharedPreferences =
|
|
57
|
+
context.getSharedPreferences("HotUpdaterPrefs", Context.MODE_PRIVATE)
|
|
58
|
+
with(sharedPreferences.edit()) {
|
|
59
|
+
putString("HotUpdaterBundleURL", bundleURL)
|
|
60
|
+
apply()
|
|
61
|
+
}
|
|
95
62
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private fun setJSBundle(instanceManager: ReactInstanceManager, latestJSBundleFile: String?) {
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
var latestJSBundleLoader: JSBundleLoader? = null
|
|
102
63
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
|
|
64
|
+
private fun extractZipFileAtPath(
|
|
65
|
+
filePath: String,
|
|
66
|
+
destinationPath: String,
|
|
67
|
+
): Boolean =
|
|
68
|
+
try {
|
|
69
|
+
ZipFile(filePath).use { zip ->
|
|
70
|
+
zip.entries().asSequence().forEach { entry ->
|
|
71
|
+
val file = File(destinationPath, entry.name)
|
|
72
|
+
if (entry.isDirectory) {
|
|
73
|
+
file.mkdirs()
|
|
74
|
+
} else {
|
|
75
|
+
file.parentFile?.mkdirs()
|
|
76
|
+
zip.getInputStream(entry).use { input ->
|
|
77
|
+
file.outputStream().use { output -> input.copyTo(output) }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
true
|
|
83
|
+
} catch (e: Exception) {
|
|
84
|
+
Log.d("HotUpdater", "Failed to unzip file: ${e.message}")
|
|
85
|
+
false
|
|
113
86
|
}
|
|
114
|
-
val bundleLoaderField: Field =
|
|
115
|
-
instanceManager::class.java.getDeclaredField("mBundleLoader")
|
|
116
|
-
bundleLoaderField.isAccessible = true
|
|
117
87
|
|
|
118
|
-
|
|
119
|
-
|
|
88
|
+
private fun getCurrentActivity(context: Context): Activity? =
|
|
89
|
+
if (context is ReactApplicationContext) {
|
|
90
|
+
context.currentActivity
|
|
120
91
|
} else {
|
|
121
|
-
|
|
92
|
+
null
|
|
122
93
|
}
|
|
123
|
-
} catch (e: Exception) {
|
|
124
|
-
throw IllegalAccessException("Could not setJSBundle")
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
fun initializeOnAppUpdate() {
|
|
129
|
-
val sharedPreferences =
|
|
130
|
-
mContext.getSharedPreferences("HotUpdaterPrefs", Context.MODE_PRIVATE)
|
|
131
94
|
|
|
132
|
-
|
|
133
|
-
|
|
95
|
+
fun reload(context: Context) {
|
|
96
|
+
val activity: Activity? = getCurrentActivity(context)
|
|
97
|
+
val reactIntegrationManager = ReactIntegrationManager(context)
|
|
134
98
|
|
|
135
|
-
|
|
136
|
-
val
|
|
137
|
-
editor.remove("HotUpdaterBundleURL")
|
|
138
|
-
editor.remove("HotUpdaterBundleVersion")
|
|
139
|
-
editor.putString("HotUpdaterAppVersion", currentVersion)
|
|
140
|
-
editor.apply()
|
|
141
|
-
}
|
|
142
|
-
}
|
|
99
|
+
val reactApplication: ReactApplication = reactIntegrationManager.getReactApplication(activity?.application)
|
|
100
|
+
val bundleURL = getJSBundleFile(context)
|
|
143
101
|
|
|
144
|
-
|
|
145
|
-
Log.d("HotUpdater", "HotUpdater requested a reload ${getBundleURL()}")
|
|
102
|
+
reactIntegrationManager.setJSBundle(reactApplication, bundleURL)
|
|
146
103
|
|
|
147
|
-
setJSBundle(mReactNativeHost.reactInstanceManager, getBundleURL())
|
|
148
|
-
|
|
149
|
-
clearLifecycleEventListener()
|
|
150
|
-
try {
|
|
151
104
|
Handler(Looper.getMainLooper()).post {
|
|
152
|
-
|
|
153
|
-
mReactNativeHost.reactInstanceManager.recreateReactContextInBackground()
|
|
154
|
-
} catch (t: Throwable) {
|
|
155
|
-
loadBundleLegacy()
|
|
156
|
-
}
|
|
105
|
+
reactIntegrationManager.reload(reactApplication)
|
|
157
106
|
}
|
|
158
|
-
} catch (t: Throwable) {
|
|
159
|
-
loadBundleLegacy()
|
|
160
107
|
}
|
|
161
|
-
}
|
|
162
108
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
mContext.getSharedPreferences("HotUpdaterPrefs", Context.MODE_PRIVATE)
|
|
171
|
-
val urlString = sharedPreferences.getString("HotUpdaterBundleURL", null)
|
|
172
|
-
if (urlString.isNullOrEmpty()) {
|
|
173
|
-
return "assets://index.android.bundle"
|
|
174
|
-
}
|
|
109
|
+
public fun getJSBundleFile(context: Context): String {
|
|
110
|
+
val sharedPreferences =
|
|
111
|
+
context.getSharedPreferences("HotUpdaterPrefs", Context.MODE_PRIVATE)
|
|
112
|
+
val urlString = sharedPreferences.getString("HotUpdaterBundleURL", null)
|
|
113
|
+
if (urlString.isNullOrEmpty()) {
|
|
114
|
+
return "assets://index.android.bundle"
|
|
115
|
+
}
|
|
175
116
|
|
|
176
|
-
|
|
177
|
-
|
|
117
|
+
val file = File(urlString)
|
|
118
|
+
if (!file.exists()) {
|
|
119
|
+
setBundleURL(context, null)
|
|
120
|
+
return "assets://index.android.bundle"
|
|
121
|
+
}
|
|
178
122
|
|
|
179
|
-
|
|
180
|
-
val sharedPreferences =
|
|
181
|
-
mContext.getSharedPreferences("HotUpdaterPrefs", Context.MODE_PRIVATE)
|
|
182
|
-
with(sharedPreferences.edit()) {
|
|
183
|
-
putString("HotUpdaterBundleURL", bundleURL)
|
|
184
|
-
apply()
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
private fun setBundleVersion(bundleVersion: String?) {
|
|
188
|
-
val sharedPreferences =
|
|
189
|
-
mContext.getSharedPreferences("HotUpdaterPrefs", Context.MODE_PRIVATE)
|
|
190
|
-
with(sharedPreferences.edit()) {
|
|
191
|
-
putString("HotUpdaterBundleVersion", bundleVersion)
|
|
192
|
-
apply()
|
|
123
|
+
return urlString
|
|
193
124
|
}
|
|
194
|
-
}
|
|
195
125
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
126
|
+
fun updateBundle(
|
|
127
|
+
context: Context,
|
|
128
|
+
bundleId: String,
|
|
129
|
+
zipUrl: String,
|
|
130
|
+
progressCallback: ((Double) -> Unit),
|
|
131
|
+
): Boolean {
|
|
132
|
+
Log.d("HotUpdater", "updateBundle bundleId $bundleId zipUrl $zipUrl")
|
|
133
|
+
if (zipUrl.isEmpty()) {
|
|
134
|
+
setBundleURL(context, null)
|
|
135
|
+
return true
|
|
206
136
|
}
|
|
207
|
-
} else {
|
|
208
|
-
-1.0
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
137
|
|
|
212
|
-
|
|
213
|
-
return try {
|
|
214
|
-
ZipFile(filePath).use { zip ->
|
|
215
|
-
zip.entries().asSequence().forEach { entry ->
|
|
216
|
-
val file = File(destinationPath, entry.name)
|
|
217
|
-
if (entry.isDirectory) {
|
|
218
|
-
file.mkdirs()
|
|
219
|
-
} else {
|
|
220
|
-
file.parentFile?.mkdirs()
|
|
221
|
-
zip.getInputStream(entry).use { input ->
|
|
222
|
-
file.outputStream().use { output -> input.copyTo(output) }
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
true
|
|
228
|
-
} catch (e: Exception) {
|
|
229
|
-
Log.d("HotUpdater", "Failed to unzip file: ${e.message}")
|
|
230
|
-
false
|
|
231
|
-
}
|
|
232
|
-
}
|
|
138
|
+
val downloadUrl = URL(zipUrl)
|
|
233
139
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
setBundleURL(null)
|
|
237
|
-
setBundleVersion(null)
|
|
238
|
-
return true
|
|
239
|
-
}
|
|
140
|
+
val basePath = stripPrefixFromPath(bundleId, downloadUrl.path)
|
|
141
|
+
val path = convertFileSystemPathFromBasePath(context, basePath)
|
|
240
142
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
143
|
+
var connection: HttpURLConnection? = null
|
|
144
|
+
try {
|
|
145
|
+
connection = downloadUrl.openConnection() as HttpURLConnection
|
|
146
|
+
connection.connect()
|
|
245
147
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
} catch (e: Exception) {
|
|
250
|
-
Log.d("HotUpdater", "Failed to download data from URL: $url")
|
|
148
|
+
val totalSize = connection.contentLength
|
|
149
|
+
if (totalSize <= 0) {
|
|
150
|
+
Log.d("HotUpdater", "Invalid content length: $totalSize")
|
|
251
151
|
return false
|
|
252
152
|
}
|
|
253
153
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
file.parentFile?.mkdirs()
|
|
257
|
-
file.writeBytes(data)
|
|
258
|
-
} catch (e: Exception) {
|
|
259
|
-
Log.d("HotUpdater", "Failed to save data: ${e.message}")
|
|
260
|
-
return false
|
|
261
|
-
}
|
|
154
|
+
val file = File(path)
|
|
155
|
+
file.parentFile?.mkdirs()
|
|
262
156
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
157
|
+
connection.inputStream.use { input ->
|
|
158
|
+
file.outputStream().use { output ->
|
|
159
|
+
val buffer = ByteArray(8 * 1024)
|
|
160
|
+
var bytesRead: Int
|
|
161
|
+
var totalRead = 0L
|
|
267
162
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
163
|
+
while (input.read(buffer).also { bytesRead = it } != -1) {
|
|
164
|
+
output.write(buffer, 0, bytesRead)
|
|
165
|
+
totalRead += bytesRead
|
|
166
|
+
val progress = (totalRead.toDouble() / totalSize)
|
|
167
|
+
progressCallback.invoke(progress)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} catch (e: Exception) {
|
|
172
|
+
Log.d("HotUpdater", "Failed to download data from URL: $zipUrl, Error: ${e.message}")
|
|
173
|
+
return false
|
|
174
|
+
} finally {
|
|
175
|
+
connection?.disconnect()
|
|
176
|
+
}
|
|
272
177
|
|
|
273
|
-
|
|
274
|
-
val indexFile = extractedDirectory.walk().find { it.name == "index.android.bundle" }
|
|
178
|
+
val extractedPath = File(path).parentFile?.path ?: return false
|
|
275
179
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
} else {
|
|
281
|
-
Log.d("HotUpdater", "index.android.bundle not found.")
|
|
282
|
-
return false
|
|
283
|
-
}
|
|
180
|
+
if (!extractZipFileAtPath(path, extractedPath)) {
|
|
181
|
+
Log.d("HotUpdater", "Failed to extract zip file.")
|
|
182
|
+
return false
|
|
183
|
+
}
|
|
284
184
|
|
|
285
|
-
|
|
286
|
-
|
|
185
|
+
val extractedDirectory = File(extractedPath)
|
|
186
|
+
val indexFile = extractedDirectory.walk().find { it.name == "index.android.bundle" }
|
|
287
187
|
|
|
288
|
-
|
|
188
|
+
if (indexFile != null) {
|
|
189
|
+
val bundlePath = indexFile.path
|
|
190
|
+
Log.d("HotUpdater", "Setting bundle URL: $bundlePath")
|
|
191
|
+
setBundleURL(context, bundlePath)
|
|
192
|
+
} else {
|
|
193
|
+
Log.d("HotUpdater", "index.android.bundle not found.")
|
|
194
|
+
return false
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
Log.d("HotUpdater", "Downloaded and extracted file successfully.")
|
|
198
|
+
return true
|
|
199
|
+
}
|
|
289
200
|
}
|
|
290
201
|
}
|
|
@@ -1,45 +1,57 @@
|
|
|
1
1
|
package com.hotupdater
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.bridge.
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
5
|
import com.facebook.react.bridge.ReactMethod
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
6
|
+
import com.facebook.react.bridge.WritableNativeMap
|
|
7
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
|
+
|
|
9
|
+
class HotUpdaterModule internal constructor(
|
|
10
|
+
context: ReactApplicationContext,
|
|
11
|
+
) : HotUpdaterSpec(context) {
|
|
12
|
+
private val mReactApplicationContext: ReactApplicationContext = context
|
|
13
|
+
|
|
14
|
+
override fun getName(): String = NAME
|
|
15
|
+
|
|
16
|
+
@ReactMethod
|
|
17
|
+
override fun reload() {
|
|
18
|
+
HotUpdater.reload(mReactApplicationContext)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@ReactMethod
|
|
22
|
+
override fun getAppVersion(promise: Promise) {
|
|
23
|
+
promise.resolve(HotUpdater.getAppVersion(mReactApplicationContext))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@ReactMethod
|
|
27
|
+
override fun updateBundle(
|
|
28
|
+
bundleId: String,
|
|
29
|
+
zipUrl: String,
|
|
30
|
+
promise: Promise,
|
|
31
|
+
) {
|
|
32
|
+
val isSuccess =
|
|
33
|
+
HotUpdater.updateBundle(mReactApplicationContext, bundleId, zipUrl) { progress ->
|
|
34
|
+
val params =
|
|
35
|
+
WritableNativeMap().apply {
|
|
36
|
+
putDouble("progress", progress)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.mReactApplicationContext
|
|
40
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
41
|
+
.emit("onProgress", params)
|
|
42
|
+
}
|
|
43
|
+
promise.resolve(isSuccess)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override fun addListener(eventName: String?) {
|
|
47
|
+
// No-op
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override fun removeListeners(count: Double) {
|
|
51
|
+
// No-op
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
companion object {
|
|
55
|
+
const val NAME = "HotUpdater"
|
|
56
|
+
}
|
|
45
57
|
}
|
|
@@ -8,29 +8,30 @@ import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
|
8
8
|
import java.util.HashMap
|
|
9
9
|
|
|
10
10
|
class HotUpdaterPackage : TurboReactPackage() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
override fun getModule(
|
|
12
|
+
name: String,
|
|
13
|
+
reactContext: ReactApplicationContext,
|
|
14
|
+
): NativeModule? =
|
|
15
|
+
if (name == HotUpdaterModule.NAME) {
|
|
16
|
+
HotUpdaterModule(reactContext)
|
|
17
|
+
} else {
|
|
18
|
+
null
|
|
19
|
+
}
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
21
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider =
|
|
22
|
+
ReactModuleInfoProvider {
|
|
23
|
+
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
|
|
24
|
+
val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
|
25
|
+
moduleInfos[HotUpdaterModule.NAME] =
|
|
26
|
+
ReactModuleInfo(
|
|
27
|
+
HotUpdaterModule.NAME,
|
|
28
|
+
HotUpdaterModule.NAME,
|
|
29
|
+
false, // canOverrideExistingModule
|
|
30
|
+
false, // needsEagerInit
|
|
31
|
+
true, // hasConstants
|
|
32
|
+
false, // isCxxModule
|
|
33
|
+
isTurboModule, // isTurboModule
|
|
34
|
+
)
|
|
35
|
+
moduleInfos
|
|
36
|
+
}
|
|
36
37
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package com.hotupdater
|
|
2
|
+
|
|
3
|
+
import android.app.Application
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import com.facebook.react.ReactApplication
|
|
6
|
+
import com.facebook.react.bridge.JSBundleLoader
|
|
7
|
+
|
|
8
|
+
open class ReactIntegrationManagerBase(
|
|
9
|
+
private val context: Context,
|
|
10
|
+
) {
|
|
11
|
+
fun getJSBundlerLoader(bundleFileUrl: String): JSBundleLoader? {
|
|
12
|
+
val bundleLoader: JSBundleLoader?
|
|
13
|
+
|
|
14
|
+
if (bundleFileUrl.lowercase().startsWith("assets://")) {
|
|
15
|
+
bundleLoader =
|
|
16
|
+
JSBundleLoader.createAssetLoader(
|
|
17
|
+
context,
|
|
18
|
+
bundleFileUrl,
|
|
19
|
+
true,
|
|
20
|
+
)
|
|
21
|
+
} else {
|
|
22
|
+
bundleLoader = JSBundleLoader.createFileLoader(bundleFileUrl)
|
|
23
|
+
}
|
|
24
|
+
return bundleLoader
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public fun getReactApplication(application: Application?): ReactApplication {
|
|
28
|
+
if (application is ReactApplication) {
|
|
29
|
+
return application
|
|
30
|
+
} else {
|
|
31
|
+
throw IllegalArgumentException("Application does not implement ReactApplication")
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -2,5 +2,6 @@ package com.hotupdater
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
4
|
|
|
5
|
-
abstract class HotUpdaterSpec internal constructor(
|
|
6
|
-
|
|
5
|
+
abstract class HotUpdaterSpec internal constructor(
|
|
6
|
+
context: ReactApplicationContext,
|
|
7
|
+
) : NativeHotUpdaterSpec(context)
|