@hot-updater/react-native 0.17.0 → 0.18.1

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.
Files changed (138) hide show
  1. package/HotUpdater.podspec +7 -11
  2. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +200 -0
  3. package/android/src/main/java/com/hotupdater/FileManagerService.kt +104 -0
  4. package/android/src/main/java/com/hotupdater/HotUpdater.kt +62 -305
  5. package/android/src/main/java/com/hotupdater/HotUpdaterFactory.kt +49 -0
  6. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +176 -0
  7. package/android/src/main/java/com/hotupdater/HttpDownloadService.kt +98 -0
  8. package/android/src/main/java/com/hotupdater/VersionedPreferencesService.kt +69 -0
  9. package/android/src/main/java/com/hotupdater/ZipFileUnzipService.kt +52 -0
  10. package/android/src/newarch/HotUpdaterModule.kt +31 -34
  11. package/android/src/oldarch/HotUpdaterModule.kt +32 -34
  12. package/android/src/oldarch/HotUpdaterSpec.kt +2 -9
  13. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +593 -0
  14. package/ios/HotUpdater/Internal/FileManagerService.swift +97 -0
  15. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +8 -0
  16. package/ios/HotUpdater/Internal/HotUpdater.mm +241 -0
  17. package/ios/HotUpdater/Internal/HotUpdaterFactory.swift +24 -0
  18. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +143 -0
  19. package/ios/HotUpdater/Internal/NotificationExtension.swift +6 -0
  20. package/ios/HotUpdater/Internal/SSZipArchiveUnzipService.swift +25 -0
  21. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +101 -0
  22. package/ios/HotUpdater/Internal/VersionedPreferencesService.swift +82 -0
  23. package/ios/HotUpdater/Public/HotUpdater.h +29 -0
  24. package/lib/commonjs/checkForUpdate.js +70 -0
  25. package/lib/commonjs/checkForUpdate.js.map +1 -0
  26. package/lib/commonjs/error.js +14 -0
  27. package/lib/commonjs/error.js.map +1 -0
  28. package/lib/commonjs/fetchUpdateInfo.js +74 -0
  29. package/lib/commonjs/fetchUpdateInfo.js.map +1 -0
  30. package/lib/commonjs/hooks/useEventCallback.js +17 -0
  31. package/lib/commonjs/hooks/useEventCallback.js.map +1 -0
  32. package/lib/commonjs/index.js +234 -0
  33. package/lib/commonjs/index.js.map +1 -0
  34. package/lib/commonjs/native.js +132 -0
  35. package/lib/commonjs/native.js.map +1 -0
  36. package/lib/commonjs/package.json +1 -0
  37. package/lib/commonjs/runUpdateProcess.js +69 -0
  38. package/lib/commonjs/runUpdateProcess.js.map +1 -0
  39. package/lib/commonjs/specs/NativeHotUpdater.js +9 -0
  40. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -0
  41. package/lib/commonjs/store.js +48 -0
  42. package/lib/commonjs/store.js.map +1 -0
  43. package/lib/commonjs/wrap.js +98 -0
  44. package/lib/commonjs/wrap.js.map +1 -0
  45. package/lib/module/checkForUpdate.js +64 -0
  46. package/lib/module/checkForUpdate.js.map +1 -0
  47. package/lib/module/error.js +9 -0
  48. package/lib/module/error.js.map +1 -0
  49. package/lib/module/fetchUpdateInfo.js +69 -0
  50. package/lib/module/fetchUpdateInfo.js.map +1 -0
  51. package/lib/module/hooks/useEventCallback.js +13 -0
  52. package/lib/module/hooks/useEventCallback.js.map +1 -0
  53. package/lib/module/index.js +211 -0
  54. package/lib/module/index.js.map +1 -0
  55. package/lib/module/native.js +119 -0
  56. package/lib/module/native.js.map +1 -0
  57. package/lib/module/package.json +1 -0
  58. package/lib/module/runUpdateProcess.js +64 -0
  59. package/lib/module/runUpdateProcess.js.map +1 -0
  60. package/lib/module/specs/NativeHotUpdater.js +5 -0
  61. package/lib/module/specs/NativeHotUpdater.js.map +1 -0
  62. package/lib/module/store.js +42 -0
  63. package/lib/module/store.js.map +1 -0
  64. package/lib/module/wrap.js +94 -0
  65. package/lib/module/wrap.js.map +1 -0
  66. package/lib/typescript/commonjs/checkForUpdate.d.ts +22 -0
  67. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -0
  68. package/{dist → lib/typescript/commonjs}/error.d.ts +1 -0
  69. package/lib/typescript/commonjs/error.d.ts.map +1 -0
  70. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts +4 -0
  71. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts.map +1 -0
  72. package/{dist → lib/typescript/commonjs}/hooks/useEventCallback.d.ts +1 -0
  73. package/lib/typescript/commonjs/hooks/useEventCallback.d.ts.map +1 -0
  74. package/{dist → lib/typescript/commonjs}/index.d.ts +38 -12
  75. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  76. package/lib/typescript/commonjs/native.d.ts +64 -0
  77. package/lib/typescript/commonjs/native.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/package.json +1 -0
  79. package/{dist → lib/typescript/commonjs}/runUpdateProcess.d.ts +1 -0
  80. package/lib/typescript/commonjs/runUpdateProcess.d.ts.map +1 -0
  81. package/{dist → lib/typescript/commonjs}/specs/NativeHotUpdater.d.ts +8 -9
  82. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -0
  83. package/{dist → lib/typescript/commonjs}/store.d.ts +1 -0
  84. package/lib/typescript/commonjs/store.d.ts.map +1 -0
  85. package/{dist → lib/typescript/commonjs}/wrap.d.ts +3 -2
  86. package/lib/typescript/commonjs/wrap.d.ts.map +1 -0
  87. package/lib/typescript/module/checkForUpdate.d.ts +22 -0
  88. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -0
  89. package/lib/typescript/module/error.d.ts +4 -0
  90. package/lib/typescript/module/error.d.ts.map +1 -0
  91. package/lib/typescript/module/fetchUpdateInfo.d.ts +4 -0
  92. package/lib/typescript/module/fetchUpdateInfo.d.ts.map +1 -0
  93. package/lib/typescript/module/hooks/useEventCallback.d.ts +5 -0
  94. package/lib/typescript/module/hooks/useEventCallback.d.ts.map +1 -0
  95. package/lib/typescript/module/index.d.ts +202 -0
  96. package/lib/typescript/module/index.d.ts.map +1 -0
  97. package/lib/typescript/module/native.d.ts +64 -0
  98. package/lib/typescript/module/native.d.ts.map +1 -0
  99. package/lib/typescript/module/package.json +1 -0
  100. package/lib/typescript/module/runUpdateProcess.d.ts +49 -0
  101. package/lib/typescript/module/runUpdateProcess.d.ts.map +1 -0
  102. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +19 -0
  103. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -0
  104. package/lib/typescript/module/store.d.ts +11 -0
  105. package/lib/typescript/module/store.d.ts.map +1 -0
  106. package/lib/typescript/module/wrap.d.ts +51 -0
  107. package/lib/typescript/module/wrap.d.ts.map +1 -0
  108. package/package.json +59 -30
  109. package/src/checkForUpdate.ts +59 -9
  110. package/src/fetchUpdateInfo.ts +40 -12
  111. package/src/index.ts +37 -11
  112. package/src/native.ts +87 -41
  113. package/src/runUpdateProcess.ts +2 -2
  114. package/src/specs/NativeHotUpdater.ts +8 -10
  115. package/src/wrap.tsx +9 -13
  116. package/android/generated/java/com/hotupdater/NativeHotUpdaterSpec.java +0 -93
  117. package/android/generated/jni/CMakeLists.txt +0 -36
  118. package/android/generated/jni/HotUpdaterSpec-generated.cpp +0 -68
  119. package/android/generated/jni/HotUpdaterSpec.h +0 -31
  120. package/android/generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI-generated.cpp +0 -70
  121. package/android/generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI.h +0 -121
  122. package/android/src/main/java/com/hotupdater/HotUpdaterPrefs.kt +0 -42
  123. package/dist/checkForUpdate.d.ts +0 -12
  124. package/dist/fetchUpdateInfo.d.ts +0 -3
  125. package/dist/index.js +0 -341
  126. package/dist/index.mjs +0 -301
  127. package/dist/native.d.ts +0 -41
  128. package/ios/HotUpdater/HotUpdater.h +0 -15
  129. package/ios/HotUpdater/HotUpdater.mm +0 -468
  130. package/ios/HotUpdater/HotUpdater.modulemap +0 -6
  131. package/ios/HotUpdater/HotUpdaterPrefs.h +0 -9
  132. package/ios/HotUpdater/HotUpdaterPrefs.mm +0 -45
  133. package/ios/generated/HotUpdaterSpec/HotUpdaterSpec-generated.mm +0 -81
  134. package/ios/generated/HotUpdaterSpec/HotUpdaterSpec.h +0 -112
  135. package/ios/generated/HotUpdaterSpecJSI-generated.cpp +0 -70
  136. package/ios/generated/HotUpdaterSpecJSI.h +0 -121
  137. package/react-native.config.js +0 -12
  138. package/src/global.d.ts +0 -3
@@ -13,19 +13,15 @@ Pod::Spec.new do |s|
13
13
 
14
14
  s.platforms = { :ios => min_ios_version_supported }
15
15
  s.source = { :git => "https://github.com/gronxb/hot-updater.git", :tag => "#{s.version}" }
16
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
17
+ s.public_header_files = "ios/HotUpdater/Public/*.h"
18
+ s.private_header_files = "ios/HotUpdater/Internal/*.h"
19
+ s.exclude_files = "ios/HotUpdater/Package.swift", "ios/HotUpdater/Test/**/*.{swift,h,m,mm}"
16
20
 
17
21
  s.pod_target_xcconfig = {
18
- 'SWIFT_VERSION' => '5.0',
19
- 'DEFINES_MODULE' => 'YES'
22
+ "DEFINES_MODULE" => "YES",
23
+ "OTHER_SWIFT_FLAGS" => "-enable-experimental-feature AccessLevelOnImport"
20
24
  }
21
-
22
- s.module_map = 'ios/HotUpdater/HotUpdater.modulemap'
23
-
24
- s.source_files = "ios/**/*.{h,m,mm}"
25
- if ENV['RCT_NEW_ARCH_ENABLED'] != '1' then
26
- s.exclude_files = "ios/generated/**/*"
27
- end
28
-
29
25
  s.dependency "SSZipArchive", "~> 2.2.2"
30
26
 
31
27
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
@@ -36,7 +32,7 @@ Pod::Spec.new do |s|
36
32
  s.dependency "React-Core"
37
33
 
38
34
  # Don't install the dependencies when we run `pod install` in the old architecture.
39
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
35
+ if ENV["RCT_NEW_ARCH_ENABLED"] == "1" then
40
36
  s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
41
37
  s.pod_target_xcconfig = {
42
38
  "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
@@ -0,0 +1,200 @@
1
+ package com.hotupdater
2
+
3
+ import android.util.Log
4
+ import kotlinx.coroutines.Dispatchers
5
+ import kotlinx.coroutines.withContext
6
+ import java.io.File
7
+ import java.net.URL
8
+
9
+ /**
10
+ * Interface for bundle storage operations
11
+ */
12
+ interface BundleStorageService {
13
+ /**
14
+ * Sets the current bundle URL
15
+ * @param localPath Path to the bundle file (or null to reset)
16
+ * @return true if the operation was successful
17
+ */
18
+ fun setBundleURL(localPath: String?): Boolean
19
+
20
+ /**
21
+ * Gets the URL to the cached bundle file
22
+ * @return The path to the cached bundle or null if not found
23
+ */
24
+ fun getCachedBundleURL(): String?
25
+
26
+ /**
27
+ * Gets the URL to the fallback bundle included in the app
28
+ * @return The fallback bundle path
29
+ */
30
+ fun getFallbackBundleURL(): String
31
+
32
+ /**
33
+ * Gets the URL to the bundle file (cached or fallback)
34
+ * @return The path to the bundle file
35
+ */
36
+ fun getBundleURL(): String
37
+
38
+ /**
39
+ * Updates the bundle from the specified URL
40
+ * @param bundleId ID of the bundle to update
41
+ * @param fileUrl URL of the bundle file to download (or null to reset)
42
+ * @param progressCallback Callback for download progress updates
43
+ * @return true if the update was successful
44
+ */
45
+ suspend fun updateBundle(
46
+ bundleId: String,
47
+ fileUrl: String?,
48
+ progressCallback: (Double) -> Unit,
49
+ ): Boolean
50
+ }
51
+
52
+ /**
53
+ * Implementation of BundleStorageService
54
+ */
55
+ class BundleFileStorageService(
56
+ private val fileSystem: FileSystemService,
57
+ private val downloadService: DownloadService,
58
+ private val unzipService: UnzipService,
59
+ private val preferences: PreferencesService,
60
+ ) : BundleStorageService {
61
+ override fun setBundleURL(localPath: String?): Boolean {
62
+ preferences.setItem("HotUpdaterBundleURL", localPath)
63
+ return true
64
+ }
65
+
66
+ override fun getCachedBundleURL(): String? {
67
+ val urlString = preferences.getItem("HotUpdaterBundleURL")
68
+ if (urlString.isNullOrEmpty()) {
69
+ return null
70
+ }
71
+
72
+ val file = File(urlString)
73
+ if (!file.exists()) {
74
+ preferences.setItem("HotUpdaterBundleURL", null)
75
+ return null
76
+ }
77
+ return urlString
78
+ }
79
+
80
+ override fun getFallbackBundleURL(): String = "assets://index.android.bundle"
81
+
82
+ override fun getBundleURL(): String = getCachedBundleURL() ?: getFallbackBundleURL()
83
+
84
+ override suspend fun updateBundle(
85
+ bundleId: String,
86
+ fileUrl: String?,
87
+ progressCallback: (Double) -> Unit,
88
+ ): Boolean {
89
+ Log.d("BundleStorage", "updateBundle bundleId $bundleId fileUrl $fileUrl")
90
+
91
+ if (fileUrl.isNullOrEmpty()) {
92
+ setBundleURL(null)
93
+ return true
94
+ }
95
+
96
+ val baseDir = fileSystem.getExternalFilesDir()
97
+ val bundleStoreDir = File(baseDir, "bundle-store")
98
+ if (!bundleStoreDir.exists()) {
99
+ bundleStoreDir.mkdirs()
100
+ }
101
+
102
+ val finalBundleDir = File(bundleStoreDir, bundleId)
103
+ if (finalBundleDir.exists()) {
104
+ Log.d("BundleStorage", "Bundle for bundleId $bundleId already exists. Using cached bundle.")
105
+ val existingIndexFile = finalBundleDir.walk().find { it.name == "index.android.bundle" }
106
+ if (existingIndexFile != null) {
107
+ finalBundleDir.setLastModified(System.currentTimeMillis())
108
+ setBundleURL(existingIndexFile.absolutePath)
109
+ cleanupOldBundles(bundleStoreDir)
110
+ return true
111
+ } else {
112
+ finalBundleDir.deleteRecursively()
113
+ }
114
+ }
115
+
116
+ val tempDir = File(baseDir, "bundle-temp")
117
+ if (tempDir.exists()) {
118
+ tempDir.deleteRecursively()
119
+ }
120
+ tempDir.mkdirs()
121
+
122
+ val tempZipFile = File(tempDir, "bundle.zip")
123
+ val extractedDir = File(tempDir, "extracted")
124
+ extractedDir.mkdirs()
125
+
126
+ return withContext(Dispatchers.IO) {
127
+ val downloadUrl = URL(fileUrl)
128
+
129
+ // Download the file
130
+ val downloadResult =
131
+ downloadService.downloadFile(
132
+ downloadUrl,
133
+ tempZipFile,
134
+ progressCallback,
135
+ )
136
+
137
+ when (downloadResult) {
138
+ is DownloadResult.Error -> {
139
+ Log.d("BundleStorage", "Download failed: ${downloadResult.exception.message}")
140
+ tempDir.deleteRecursively()
141
+ return@withContext false
142
+ }
143
+ is DownloadResult.Success -> {
144
+ // Extract the zip file
145
+ if (!unzipService.extractZipFile(tempZipFile.absolutePath, extractedDir.absolutePath)) {
146
+ Log.d("BundleStorage", "Failed to extract zip file.")
147
+ tempDir.deleteRecursively()
148
+ return@withContext false
149
+ }
150
+
151
+ // Find the bundle file
152
+ val indexFileExtracted = extractedDir.walk().find { it.name == "index.android.bundle" }
153
+ if (indexFileExtracted == null) {
154
+ Log.d("BundleStorage", "index.android.bundle not found in extracted files.")
155
+ tempDir.deleteRecursively()
156
+ return@withContext false
157
+ }
158
+
159
+ // Move to final location
160
+ if (finalBundleDir.exists()) {
161
+ finalBundleDir.deleteRecursively()
162
+ }
163
+
164
+ if (!fileSystem.moveItem(extractedDir.absolutePath, finalBundleDir.absolutePath)) {
165
+ fileSystem.copyItem(extractedDir.absolutePath, finalBundleDir.absolutePath)
166
+ extractedDir.deleteRecursively()
167
+ }
168
+
169
+ val finalIndexFile = finalBundleDir.walk().find { it.name == "index.android.bundle" }
170
+ if (finalIndexFile == null) {
171
+ Log.d("BundleStorage", "index.android.bundle not found in final directory.")
172
+ tempDir.deleteRecursively()
173
+ return@withContext false
174
+ }
175
+
176
+ finalBundleDir.setLastModified(System.currentTimeMillis())
177
+ val bundlePath = finalIndexFile.absolutePath
178
+ Log.d("BundleStorage", "Setting bundle URL: $bundlePath")
179
+ setBundleURL(bundlePath)
180
+ cleanupOldBundles(bundleStoreDir)
181
+ tempDir.deleteRecursively()
182
+
183
+ Log.d("BundleStorage", "Downloaded and extracted file successfully.")
184
+ return@withContext true
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ private fun cleanupOldBundles(bundleStoreDir: File) {
191
+ val bundles = bundleStoreDir.listFiles { file -> file.isDirectory }?.toList() ?: return
192
+ val sortedBundles = bundles.sortedByDescending { it.lastModified() }
193
+ if (sortedBundles.size > 1) {
194
+ sortedBundles.drop(1).forEach { oldBundle ->
195
+ Log.d("BundleStorage", "Removing old bundle: ${oldBundle.name}")
196
+ oldBundle.deleteRecursively()
197
+ }
198
+ }
199
+ }
200
+ }
@@ -0,0 +1,104 @@
1
+ package com.hotupdater
2
+
3
+ import android.content.Context
4
+ import java.io.File
5
+
6
+ /**
7
+ * Interface for file system operations
8
+ */
9
+ interface FileSystemService {
10
+ /**
11
+ * Checks if a file exists at the given path
12
+ */
13
+ fun fileExists(path: String): Boolean
14
+
15
+ /**
16
+ * Creates directory at the given path, including any necessary parent directories
17
+ */
18
+ fun createDirectory(path: String): Boolean
19
+
20
+ /**
21
+ * Removes a file or directory at the given path
22
+ */
23
+ fun removeItem(path: String): Boolean
24
+
25
+ /**
26
+ * Moves a file or directory from source path to destination path
27
+ */
28
+ fun moveItem(
29
+ sourcePath: String,
30
+ destinationPath: String,
31
+ ): Boolean
32
+
33
+ /**
34
+ * Copies a file or directory from source path to destination path
35
+ */
36
+ fun copyItem(
37
+ sourcePath: String,
38
+ destinationPath: String,
39
+ ): Boolean
40
+
41
+ /**
42
+ * Lists the contents of a directory
43
+ */
44
+ fun contentsOfDirectory(path: String): List<String>
45
+
46
+ /**
47
+ * Gets the external files directory for the application
48
+ */
49
+ fun getExternalFilesDir(): File?
50
+ }
51
+
52
+ /**
53
+ * Implementation of FileSystemService using standard File API
54
+ */
55
+ class FileManagerService(
56
+ private val context: Context,
57
+ ) : FileSystemService {
58
+ override fun fileExists(path: String): Boolean = File(path).exists()
59
+
60
+ override fun createDirectory(path: String): Boolean = File(path).mkdirs()
61
+
62
+ override fun removeItem(path: String): Boolean = File(path).deleteRecursively()
63
+
64
+ override fun moveItem(
65
+ sourcePath: String,
66
+ destinationPath: String,
67
+ ): Boolean {
68
+ val source = File(sourcePath)
69
+ val destination = File(destinationPath)
70
+
71
+ return try {
72
+ if (destination.exists()) {
73
+ destination.deleteRecursively()
74
+ }
75
+ source.renameTo(destination)
76
+ } catch (e: Exception) {
77
+ false
78
+ }
79
+ }
80
+
81
+ override fun copyItem(
82
+ sourcePath: String,
83
+ destinationPath: String,
84
+ ): Boolean {
85
+ val source = File(sourcePath)
86
+ val destination = File(destinationPath)
87
+
88
+ return try {
89
+ if (destination.exists()) {
90
+ destination.deleteRecursively()
91
+ }
92
+ source.copyRecursively(target = destination, overwrite = true)
93
+ } catch (e: Exception) {
94
+ false
95
+ }
96
+ }
97
+
98
+ override fun contentsOfDirectory(path: String): List<String> {
99
+ val directory = File(path)
100
+ return directory.listFiles()?.map { it.name } ?: listOf()
101
+ }
102
+
103
+ override fun getExternalFilesDir(): File? = context.getExternalFilesDir(null)
104
+ }