@hot-updater/react-native 0.16.7-0 → 0.18.0

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 (143) hide show
  1. package/HotUpdater.podspec +7 -11
  2. package/android/{generated/java/com/hotupdater → app/build/generated/source/codegen/java/com/facebook/fbreact/specs}/NativeHotUpdaterSpec.java +3 -2
  3. package/android/app/build/generated/source/codegen/jni/HotUpdater-generated.cpp +68 -0
  4. package/android/app/build/generated/source/codegen/jni/HotUpdater.h +31 -0
  5. package/android/{generated → app/build/generated/source/codegen}/jni/HotUpdaterSpec-generated.cpp +2 -2
  6. package/android/{generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI-generated.cpp → app/build/generated/source/codegen/jni/react/renderer/components/HotUpdater/HotUpdaterJSI-generated.cpp} +3 -4
  7. package/{ios/generated/HotUpdaterSpecJSI.h → android/app/build/generated/source/codegen/jni/react/renderer/components/HotUpdater/HotUpdaterJSI.h} +53 -6
  8. package/{ios/generated → android/app/build/generated/source/codegen/jni/react/renderer/components/HotUpdaterSpec}/HotUpdaterSpecJSI-generated.cpp +2 -3
  9. package/android/{generated → app/build/generated/source/codegen}/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI.h +59 -8
  10. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +200 -0
  11. package/android/src/main/java/com/hotupdater/FileManagerService.kt +104 -0
  12. package/android/src/main/java/com/hotupdater/HotUpdater.kt +62 -305
  13. package/android/src/main/java/com/hotupdater/HotUpdaterFactory.kt +49 -0
  14. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +176 -0
  15. package/android/src/main/java/com/hotupdater/HttpDownloadService.kt +98 -0
  16. package/android/src/main/java/com/hotupdater/VersionedPreferencesService.kt +69 -0
  17. package/android/src/main/java/com/hotupdater/ZipFileUnzipService.kt +52 -0
  18. package/android/src/newarch/HotUpdaterModule.kt +31 -34
  19. package/android/src/newarch/ReactIntegrationManager.kt +17 -3
  20. package/android/src/oldarch/HotUpdaterModule.kt +32 -34
  21. package/android/src/oldarch/HotUpdaterSpec.kt +2 -9
  22. package/android/src/oldarch/ReactIntegrationManager.kt +0 -2
  23. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +593 -0
  24. package/ios/HotUpdater/Internal/FileManagerService.swift +97 -0
  25. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +8 -0
  26. package/ios/HotUpdater/Internal/HotUpdater.mm +241 -0
  27. package/ios/HotUpdater/Internal/HotUpdaterFactory.swift +24 -0
  28. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +143 -0
  29. package/ios/HotUpdater/Internal/NotificationExtension.swift +6 -0
  30. package/ios/HotUpdater/Internal/SSZipArchiveUnzipService.swift +25 -0
  31. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +101 -0
  32. package/ios/HotUpdater/Internal/VersionedPreferencesService.swift +82 -0
  33. package/ios/HotUpdater/Package.resolved +15 -0
  34. package/ios/HotUpdater/Public/HotUpdater.h +29 -0
  35. package/lib/commonjs/checkForUpdate.js +70 -0
  36. package/lib/commonjs/checkForUpdate.js.map +1 -0
  37. package/lib/commonjs/error.js +14 -0
  38. package/lib/commonjs/error.js.map +1 -0
  39. package/lib/commonjs/fetchUpdateInfo.js +74 -0
  40. package/lib/commonjs/fetchUpdateInfo.js.map +1 -0
  41. package/lib/commonjs/hooks/useEventCallback.js +17 -0
  42. package/lib/commonjs/hooks/useEventCallback.js.map +1 -0
  43. package/lib/commonjs/index.js +234 -0
  44. package/lib/commonjs/index.js.map +1 -0
  45. package/lib/commonjs/native.js +132 -0
  46. package/lib/commonjs/native.js.map +1 -0
  47. package/lib/commonjs/package.json +1 -0
  48. package/lib/commonjs/runUpdateProcess.js +69 -0
  49. package/lib/commonjs/runUpdateProcess.js.map +1 -0
  50. package/lib/commonjs/specs/NativeHotUpdater.js +9 -0
  51. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -0
  52. package/lib/commonjs/store.js +48 -0
  53. package/lib/commonjs/store.js.map +1 -0
  54. package/lib/commonjs/wrap.js +98 -0
  55. package/lib/commonjs/wrap.js.map +1 -0
  56. package/lib/module/checkForUpdate.js +64 -0
  57. package/lib/module/checkForUpdate.js.map +1 -0
  58. package/lib/module/error.js +9 -0
  59. package/lib/module/error.js.map +1 -0
  60. package/lib/module/fetchUpdateInfo.js +69 -0
  61. package/lib/module/fetchUpdateInfo.js.map +1 -0
  62. package/lib/module/hooks/useEventCallback.js +13 -0
  63. package/lib/module/hooks/useEventCallback.js.map +1 -0
  64. package/lib/module/index.js +211 -0
  65. package/lib/module/index.js.map +1 -0
  66. package/lib/module/native.js +119 -0
  67. package/lib/module/native.js.map +1 -0
  68. package/lib/module/package.json +1 -0
  69. package/lib/module/runUpdateProcess.js +64 -0
  70. package/lib/module/runUpdateProcess.js.map +1 -0
  71. package/lib/module/specs/NativeHotUpdater.js +5 -0
  72. package/lib/module/specs/NativeHotUpdater.js.map +1 -0
  73. package/lib/module/store.js +42 -0
  74. package/lib/module/store.js.map +1 -0
  75. package/lib/module/wrap.js +94 -0
  76. package/lib/module/wrap.js.map +1 -0
  77. package/lib/typescript/commonjs/checkForUpdate.d.ts +22 -0
  78. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -0
  79. package/{dist → lib/typescript/commonjs}/error.d.ts +1 -0
  80. package/lib/typescript/commonjs/error.d.ts.map +1 -0
  81. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts +4 -0
  82. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts.map +1 -0
  83. package/{dist → lib/typescript/commonjs}/hooks/useEventCallback.d.ts +1 -0
  84. package/lib/typescript/commonjs/hooks/useEventCallback.d.ts.map +1 -0
  85. package/{dist → lib/typescript/commonjs}/index.d.ts +38 -12
  86. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  87. package/lib/typescript/commonjs/native.d.ts +64 -0
  88. package/lib/typescript/commonjs/native.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/package.json +1 -0
  90. package/{dist → lib/typescript/commonjs}/runUpdateProcess.d.ts +1 -0
  91. package/lib/typescript/commonjs/runUpdateProcess.d.ts.map +1 -0
  92. package/{dist → lib/typescript/commonjs}/specs/NativeHotUpdater.d.ts +8 -9
  93. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -0
  94. package/{dist → lib/typescript/commonjs}/store.d.ts +1 -0
  95. package/lib/typescript/commonjs/store.d.ts.map +1 -0
  96. package/{dist → lib/typescript/commonjs}/wrap.d.ts +3 -2
  97. package/lib/typescript/commonjs/wrap.d.ts.map +1 -0
  98. package/lib/typescript/module/checkForUpdate.d.ts +22 -0
  99. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -0
  100. package/lib/typescript/module/error.d.ts +4 -0
  101. package/lib/typescript/module/error.d.ts.map +1 -0
  102. package/lib/typescript/module/fetchUpdateInfo.d.ts +4 -0
  103. package/lib/typescript/module/fetchUpdateInfo.d.ts.map +1 -0
  104. package/lib/typescript/module/hooks/useEventCallback.d.ts +5 -0
  105. package/lib/typescript/module/hooks/useEventCallback.d.ts.map +1 -0
  106. package/lib/typescript/module/index.d.ts +202 -0
  107. package/lib/typescript/module/index.d.ts.map +1 -0
  108. package/lib/typescript/module/native.d.ts +64 -0
  109. package/lib/typescript/module/native.d.ts.map +1 -0
  110. package/lib/typescript/module/package.json +1 -0
  111. package/lib/typescript/module/runUpdateProcess.d.ts +49 -0
  112. package/lib/typescript/module/runUpdateProcess.d.ts.map +1 -0
  113. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +19 -0
  114. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -0
  115. package/lib/typescript/module/store.d.ts +11 -0
  116. package/lib/typescript/module/store.d.ts.map +1 -0
  117. package/lib/typescript/module/wrap.d.ts +51 -0
  118. package/lib/typescript/module/wrap.d.ts.map +1 -0
  119. package/package.json +59 -30
  120. package/src/checkForUpdate.ts +59 -9
  121. package/src/fetchUpdateInfo.ts +40 -12
  122. package/src/index.ts +37 -11
  123. package/src/native.ts +87 -41
  124. package/src/runUpdateProcess.ts +2 -2
  125. package/src/specs/NativeHotUpdater.ts +8 -10
  126. package/src/wrap.tsx +9 -13
  127. package/android/src/main/java/com/hotupdater/HotUpdaterPrefs.kt +0 -42
  128. package/dist/checkForUpdate.d.ts +0 -12
  129. package/dist/fetchUpdateInfo.d.ts +0 -3
  130. package/dist/index.js +0 -341
  131. package/dist/index.mjs +0 -301
  132. package/dist/native.d.ts +0 -41
  133. package/ios/HotUpdater/HotUpdater.h +0 -15
  134. package/ios/HotUpdater/HotUpdater.mm +0 -468
  135. package/ios/HotUpdater/HotUpdater.modulemap +0 -6
  136. package/ios/HotUpdater/HotUpdaterPrefs.h +0 -9
  137. package/ios/HotUpdater/HotUpdaterPrefs.mm +0 -45
  138. package/ios/generated/HotUpdaterSpec/HotUpdaterSpec-generated.mm +0 -81
  139. package/ios/generated/HotUpdaterSpec/HotUpdaterSpec.h +0 -112
  140. package/react-native.config.js +0 -12
  141. package/src/global.d.ts +0 -3
  142. /package/android/{generated → app/build/generated/source/codegen}/jni/CMakeLists.txt +0 -0
  143. /package/android/{generated → app/build/generated/source/codegen}/jni/HotUpdaterSpec.h +0 -0
@@ -1,15 +0,0 @@
1
- #import <React/RCTEventEmitter.h>
2
- #import <React/RCTBundleURLProvider.h>
3
-
4
- #ifdef RCT_NEW_ARCH_ENABLED
5
- #import "HotUpdaterSpec.h"
6
- @interface HotUpdater : RCTEventEmitter <NativeHotUpdaterSpec>
7
- #else
8
- #import <React/RCTBridgeModule.h>
9
- @interface HotUpdater : RCTEventEmitter <RCTBridgeModule>
10
- #endif // RCT_NEW_ARCH_ENABLED
11
-
12
- @property (nonatomic, assign) NSTimeInterval lastUpdateTime;
13
- + (NSURL *)bundleURL;
14
-
15
- @end
@@ -1,468 +0,0 @@
1
- #import "HotUpdater.h"
2
- #import "HotUpdaterPrefs.h"
3
- #import <React/RCTReloadCommand.h>
4
- #import <SSZipArchive/SSZipArchive.h>
5
- #import <Foundation/NSURLSession.h>
6
-
7
- @implementation HotUpdater {
8
- bool hasListeners;
9
- }
10
-
11
- + (BOOL)requiresMainQueueSetup {
12
- return YES;
13
- }
14
-
15
- - (instancetype)init {
16
- self = [super init];
17
- if (self) {
18
- _lastUpdateTime = 0;
19
- }
20
- return self;
21
- }
22
-
23
- RCT_EXPORT_MODULE();
24
-
25
- #pragma mark - React Native Constants
26
-
27
- - (NSString *)getMinBundleId {
28
- static NSString *uuid = nil;
29
- static dispatch_once_t onceToken;
30
- dispatch_once(&onceToken, ^{
31
- #if DEBUG
32
- uuid = @"00000000-0000-0000-0000-000000000000";
33
- return;
34
- #else
35
- // __DATE__, __TIME__ is compile-time
36
- NSString *compileDateStr = [NSString stringWithFormat:@"%s %s", __DATE__, __TIME__];
37
- NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
38
- [formatter setDateFormat:@"MMM d yyyy HH:mm:ss"];
39
- NSDate *buildDate = [formatter dateFromString:compileDateStr];
40
- if (!buildDate) {
41
- uuid = @"00000000-0000-0000-0000-000000000000";
42
- return;
43
- }
44
-
45
- uint64_t buildTimestampMs = (uint64_t)([buildDate timeIntervalSince1970] * 1000.0);
46
- unsigned char bytes[16];
47
- bytes[0] = (buildTimestampMs >> 40) & 0xFF;
48
- bytes[1] = (buildTimestampMs >> 32) & 0xFF;
49
- bytes[2] = (buildTimestampMs >> 24) & 0xFF;
50
- bytes[3] = (buildTimestampMs >> 16) & 0xFF;
51
- bytes[4] = (buildTimestampMs >> 8) & 0xFF;
52
- bytes[5] = buildTimestampMs & 0xFF;
53
-
54
- bytes[6] = 0x70;
55
- bytes[7] = 0x00;
56
-
57
- bytes[8] = 0x80;
58
- bytes[9] = 0x00;
59
-
60
- bytes[10] = 0x00;
61
- bytes[11] = 0x00;
62
- bytes[12] = 0x00;
63
- bytes[13] = 0x00;
64
- bytes[14] = 0x00;
65
- bytes[15] = 0x00;
66
-
67
- uuid = [NSString stringWithFormat:
68
- @"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
69
- bytes[0], bytes[1], bytes[2], bytes[3],
70
- bytes[4], bytes[5],
71
- bytes[6], bytes[7],
72
- bytes[8], bytes[9],
73
- bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]];
74
- #endif
75
- });
76
- return uuid;
77
- }
78
-
79
- - (NSString *)getChannel {
80
- HotUpdaterPrefs *prefs = [self getPrefs];
81
- return [prefs getItemForKey:@"HotUpdaterChannel"];
82
- }
83
-
84
- - (NSString *)getAppVersion {
85
- NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
86
- return appVersion;
87
- }
88
-
89
- - (NSDictionary *)constantsToExport {
90
- return @{
91
- @"MIN_BUNDLE_ID": [self getMinBundleId] ?: [NSNull null],
92
- @"APP_VERSION": [self getAppVersion] ?: [NSNull null],
93
- @"CHANNEL": [self getChannel] ?: [NSNull null]
94
- };
95
- }
96
-
97
- - (NSDictionary *)getConstants {
98
- return [self constantsToExport];
99
- }
100
-
101
- #pragma mark - Convenience: HotUpdaterPrefs Instance
102
-
103
- - (HotUpdaterPrefs *)getPrefs {
104
- return [HotUpdaterPrefs sharedInstanceWithAppVersion:[self getAppVersion]];
105
- }
106
-
107
- #pragma mark - Bundle URL Management
108
-
109
- + (void)setChannel:(NSString *)channel {
110
- NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
111
- HotUpdaterPrefs *prefs = [HotUpdaterPrefs sharedInstanceWithAppVersion:appVersion];
112
- [prefs setItem:channel forKey:@"HotUpdaterChannel"];
113
- }
114
-
115
- - (void)setBundleURL:(NSString *)localPath {
116
- NSLog(@"Setting bundle URL: %@", localPath);
117
- HotUpdaterPrefs *prefs = [self getPrefs];
118
- [prefs setItem:localPath forKey:@"HotUpdaterBundleURL"];
119
- }
120
-
121
- - (NSURL *)cachedURLFromBundle {
122
- HotUpdaterPrefs *prefs = [self getPrefs];
123
- NSString *savedURLString = [prefs getItemForKey:@"HotUpdaterBundleURL"];
124
- if (savedURLString) {
125
- NSURL *bundleURL = [NSURL URLWithString:savedURLString];
126
- if (bundleURL && [[NSFileManager defaultManager] fileExistsAtPath:[bundleURL path]]) {
127
- return bundleURL;
128
- }
129
- }
130
- return nil;
131
- }
132
-
133
- + (NSURL *)fallbackURL {
134
- return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
135
- }
136
-
137
- + (NSURL *)bundleURL {
138
- HotUpdater *instance = [[HotUpdater alloc] init];
139
- NSURL *url = [instance cachedURLFromBundle];
140
- return url ? url : [self fallbackURL];
141
- }
142
-
143
- #pragma mark - Utility Methods
144
-
145
- - (BOOL)extractZipFileAtPath:(NSString *)filePath toDestination:(NSString *)destinationPath {
146
- NSError *error = nil;
147
- BOOL success = [SSZipArchive unzipFileAtPath:filePath toDestination:destinationPath overwrite:YES password:nil error:&error];
148
- if (!success) {
149
- NSLog(@"Failed to unzip file: %@", error);
150
- }
151
- return success;
152
- }
153
-
154
- #pragma mark - Cleanup Old Bundles
155
-
156
- - (void)cleanupOldBundlesAtDirectory:(NSString *)bundleStoreDir {
157
- NSFileManager *fileManager = [NSFileManager defaultManager];
158
- NSError *error = nil;
159
- NSArray *contents = [fileManager contentsOfDirectoryAtPath:bundleStoreDir error:&error];
160
- if (error) {
161
- NSLog(@"Failed to list bundle store directory: %@", error);
162
- return;
163
- }
164
-
165
- NSMutableArray *bundleDirs = [NSMutableArray array];
166
- for (NSString *item in contents) {
167
- NSString *fullPath = [bundleStoreDir stringByAppendingPathComponent:item];
168
- BOOL isDir = NO;
169
- if ([fileManager fileExistsAtPath:fullPath isDirectory:&isDir] && isDir) {
170
- [bundleDirs addObject:fullPath];
171
- }
172
- }
173
-
174
- // Sort in descending order by modification time (keep latest 1)
175
- [bundleDirs sortUsingComparator:^NSComparisonResult(NSString *path1, NSString *path2) {
176
- NSDictionary *attr1 = [fileManager attributesOfItemAtPath:path1 error:nil];
177
- NSDictionary *attr2 = [fileManager attributesOfItemAtPath:path2 error:nil];
178
- NSDate *date1 = attr1[NSFileModificationDate] ?: [NSDate dateWithTimeIntervalSince1970:0];
179
- NSDate *date2 = attr2[NSFileModificationDate] ?: [NSDate dateWithTimeIntervalSince1970:0];
180
- return [date2 compare:date1];
181
- }];
182
-
183
- if (bundleDirs.count > 1) {
184
- NSArray *oldBundles = [bundleDirs subarrayWithRange:NSMakeRange(1, bundleDirs.count - 1)];
185
- for (NSString *oldBundle in oldBundles) {
186
- NSError *delError = nil;
187
- if ([fileManager removeItemAtPath:oldBundle error:&delError]) {
188
- NSLog(@"Removed old bundle: %@", oldBundle);
189
- } else {
190
- NSLog(@"Failed to remove old bundle %@: %@", oldBundle, delError);
191
- }
192
- }
193
- }
194
- }
195
-
196
- #pragma mark - Update Bundle Method
197
-
198
- - (void)updateBundle:(NSString *)bundleId zipUrl:(NSURL *)zipUrl completion:(void (^)(BOOL success))completion {
199
- if (!zipUrl) {
200
- dispatch_async(dispatch_get_main_queue(), ^{
201
- [self setBundleURL:nil];
202
- if (completion) completion(YES);
203
- });
204
- return;
205
- }
206
-
207
- NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
208
- NSString *bundleStoreDir = [documentsPath stringByAppendingPathComponent:@"bundle-store"];
209
-
210
- NSFileManager *fileManager = [NSFileManager defaultManager];
211
- if (![fileManager fileExistsAtPath:bundleStoreDir]) {
212
- [fileManager createDirectoryAtPath:bundleStoreDir withIntermediateDirectories:YES attributes:nil error:nil];
213
- }
214
-
215
- NSString *finalBundleDir = [bundleStoreDir stringByAppendingPathComponent:bundleId];
216
-
217
- if ([fileManager fileExistsAtPath:finalBundleDir]) {
218
- NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:finalBundleDir];
219
- NSString *foundBundle = nil;
220
- for (NSString *file in enumerator) {
221
- if ([file isEqualToString:@"index.ios.bundle"]) {
222
- foundBundle = file;
223
- break;
224
- }
225
- }
226
- if (foundBundle) {
227
- NSDictionary *attributes = @{NSFileModificationDate: [NSDate date]};
228
- [fileManager setAttributes:attributes ofItemAtPath:finalBundleDir error:nil];
229
- NSString *bundlePath = [finalBundleDir stringByAppendingPathComponent:foundBundle];
230
- NSLog(@"Using cached bundle at path: %@", bundlePath);
231
- [self setBundleURL:bundlePath];
232
- [self cleanupOldBundlesAtDirectory:bundleStoreDir];
233
- dispatch_async(dispatch_get_main_queue(), ^{
234
- if (completion) completion(YES);
235
- });
236
- return;
237
- } else {
238
- [fileManager removeItemAtPath:finalBundleDir error:nil];
239
- }
240
- }
241
-
242
- // Set up temporary folder (for download and extraction)
243
- NSString *tempDir = [documentsPath stringByAppendingPathComponent:@"bundle-temp"];
244
- if ([fileManager fileExistsAtPath:tempDir]) {
245
- [fileManager removeItemAtPath:tempDir error:nil];
246
- }
247
- [fileManager createDirectoryAtPath:tempDir withIntermediateDirectories:YES attributes:nil error:nil];
248
-
249
- NSString *tempZipFile = [tempDir stringByAppendingPathComponent:@"bundle.zip"];
250
- NSString *extractedDir = [tempDir stringByAppendingPathComponent:@"extracted"];
251
- [fileManager createDirectoryAtPath:extractedDir withIntermediateDirectories:YES attributes:nil error:nil];
252
-
253
- NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
254
- NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
255
-
256
- NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:zipUrl completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
257
- if (error) {
258
- NSLog(@"Failed to download data from URL: %@, error: %@", zipUrl, error);
259
- if (completion) completion(NO);
260
- return;
261
- }
262
-
263
- // Save temporary zip file
264
- if ([fileManager fileExistsAtPath:tempZipFile]) {
265
- [fileManager removeItemAtPath:tempZipFile error:nil];
266
- }
267
-
268
- NSError *moveError = nil;
269
- if (![fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:tempZipFile] error:&moveError]) {
270
- NSLog(@"Failed to save downloaded file: %@", moveError);
271
- if (completion) completion(NO);
272
- return;
273
- }
274
-
275
- // Extract zip
276
- if (![self extractZipFileAtPath:tempZipFile toDestination:extractedDir]) {
277
- NSLog(@"Failed to extract zip file.");
278
- if (completion) completion(NO);
279
- return;
280
- }
281
-
282
- // Search for index.ios.bundle in extracted folder
283
- NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:extractedDir];
284
- NSString *foundBundle = nil;
285
- for (NSString *file in enumerator) {
286
- if ([file isEqualToString:@"index.ios.bundle"]) {
287
- foundBundle = file;
288
- break;
289
- }
290
- }
291
-
292
- if (!foundBundle) {
293
- NSLog(@"index.ios.bundle not found in extracted files.");
294
- if (completion) completion(NO);
295
- return;
296
- }
297
-
298
- // Move extracted folder to final bundle folder
299
- if ([fileManager fileExistsAtPath:finalBundleDir]) {
300
- [fileManager removeItemAtPath:finalBundleDir error:nil];
301
- }
302
- NSError *moveFinalError = nil;
303
- BOOL moved = [fileManager moveItemAtPath:extractedDir toPath:finalBundleDir error:&moveFinalError];
304
- if (!moved) {
305
- // Try copy and delete if move fails
306
- BOOL copied = [fileManager copyItemAtPath:extractedDir toPath:finalBundleDir error:&moveFinalError];
307
- if (copied) {
308
- [fileManager removeItemAtPath:extractedDir error:nil];
309
- } else {
310
- NSLog(@"Failed to move or copy extracted bundle: %@", moveFinalError);
311
- if (completion) completion(NO);
312
- return;
313
- }
314
- }
315
-
316
- // Recheck index.ios.bundle in final folder
317
- NSDirectoryEnumerator *finalEnum = [fileManager enumeratorAtPath:finalBundleDir];
318
- NSString *finalFoundBundle = nil;
319
- for (NSString *file in finalEnum) {
320
- if ([file isEqualToString:@"index.ios.bundle"]) {
321
- finalFoundBundle = file;
322
- break;
323
- }
324
- }
325
-
326
- if (!finalFoundBundle) {
327
- NSLog(@"index.ios.bundle not found in final directory.");
328
- if (completion) completion(NO);
329
- return;
330
- }
331
-
332
- // Update modification time of final bundle
333
- NSDictionary *attributes = @{NSFileModificationDate: [NSDate date]};
334
- [fileManager setAttributes:attributes ofItemAtPath:finalBundleDir error:nil];
335
-
336
- NSString *bundlePath = [finalBundleDir stringByAppendingPathComponent:finalFoundBundle];
337
- NSLog(@"Setting bundle URL: %@", bundlePath);
338
- dispatch_async(dispatch_get_main_queue(), ^{
339
- [self setBundleURL:bundlePath];
340
- [self cleanupOldBundlesAtDirectory:bundleStoreDir];
341
- [fileManager removeItemAtPath:tempDir error:nil];
342
- if (completion) completion(YES);
343
- });
344
- }];
345
-
346
- // Register KVO for progress updates
347
- [downloadTask addObserver:self forKeyPath:@"countOfBytesReceived" options:NSKeyValueObservingOptionNew context:nil];
348
- [downloadTask addObserver:self forKeyPath:@"countOfBytesExpectedToReceive" options:NSKeyValueObservingOptionNew context:nil];
349
-
350
- __weak HotUpdater *weakSelf = self;
351
- [[NSNotificationCenter defaultCenter] addObserverForName:@"NSURLSessionDownloadTaskDidFinishDownloading"
352
- object:downloadTask
353
- queue:[NSOperationQueue mainQueue]
354
- usingBlock:^(NSNotification * _Nonnull note) {
355
- [weakSelf removeObserversForTask:downloadTask];
356
- }];
357
-
358
- [downloadTask resume];
359
- }
360
-
361
- #pragma mark - Folder Deletion Utility
362
-
363
- - (void)deleteFolderIfExists:(NSString *)path {
364
- NSFileManager *fileManager = [NSFileManager defaultManager];
365
- if ([fileManager fileExistsAtPath:path]) {
366
- NSError *error;
367
- [fileManager removeItemAtPath:path error:&error];
368
- if (error) {
369
- NSLog(@"Failed to delete existing folder: %@", error);
370
- } else {
371
- NSLog(@"Successfully deleted existing folder: %@", path);
372
- }
373
- }
374
- }
375
-
376
- #pragma mark - Progress Updates
377
-
378
- - (void)removeObserversForTask:(NSURLSessionDownloadTask *)task {
379
- @try {
380
- if ([task observationInfo]) {
381
- [task removeObserver:self forKeyPath:@"countOfBytesReceived"];
382
- [task removeObserver:self forKeyPath:@"countOfBytesExpectedToReceive"];
383
- NSLog(@"KVO observers removed successfully for task: %@", task);
384
- }
385
- } @catch (NSException *exception) {
386
- NSLog(@"Failed to remove observers: %@", exception);
387
- }
388
- }
389
-
390
- - (void)observeValueForKeyPath:(NSString *)keyPath
391
- ofObject:(id)object
392
- change:(NSDictionary<NSKeyValueChangeKey, id> *)change
393
- context:(void *)context {
394
- if ([keyPath isEqualToString:@"countOfBytesReceived"] || [keyPath isEqualToString:@"countOfBytesExpectedToReceive"]) {
395
- NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)object;
396
- if (task.countOfBytesExpectedToReceive > 0) {
397
- double progress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive;
398
- NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970] * 1000; // In milliseconds
399
- if ((currentTime - self.lastUpdateTime) >= 100 || progress >= 1.0) {
400
- self.lastUpdateTime = currentTime;
401
- [self sendEventWithName:@"onProgress" body:@{@"progress": @(progress)}];
402
- }
403
- }
404
- }
405
- }
406
-
407
- #pragma mark - React Native Events
408
-
409
- - (NSArray<NSString *> *)supportedEvents {
410
- return @[@"onProgress"];
411
- }
412
-
413
- - (void)startObserving {
414
- hasListeners = YES;
415
- }
416
-
417
- - (void)stopObserving {
418
- hasListeners = NO;
419
- }
420
-
421
- - (void)sendEventWithName:(NSString * _Nonnull)name result:(NSDictionary *)result {
422
- [self sendEventWithName:name body:result];
423
- }
424
-
425
- #pragma mark - React Native Exports
426
-
427
- RCT_EXPORT_METHOD(setChannel:(NSString *)channel
428
- resolve:(RCTPromiseResolveBlock)resolve
429
- reject:(RCTPromiseRejectBlock)reject) {
430
- [HotUpdater setChannel:channel];
431
- resolve(nil);
432
- }
433
-
434
- RCT_EXPORT_METHOD(reload) {
435
- NSLog(@"HotUpdater requested a reload");
436
- dispatch_async(dispatch_get_main_queue(), ^{
437
- NSURL *bundleURL = [HotUpdater bundleURL];
438
- if (bundleURL) {
439
- [super.bridge setValue:bundleURL forKey:@"bundleURL"];
440
- }
441
- RCTTriggerReloadCommandListeners(@"HotUpdater requested a reload");
442
- });
443
- }
444
-
445
- RCT_EXPORT_METHOD(getAppVersion:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
446
- NSString *version = [self getAppVersion];
447
- resolve(version ?: [NSNull null]);
448
- }
449
-
450
- RCT_EXPORT_METHOD(updateBundle:(NSString *)bundleId zipUrl:(NSString *)zipUrlString resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
451
- NSURL *zipUrl = nil;
452
- if (![zipUrlString isEqualToString:@""]) {
453
- zipUrl = [NSURL URLWithString:zipUrlString];
454
- }
455
- [self updateBundle:bundleId zipUrl:zipUrl completion:^(BOOL success) {
456
- dispatch_async(dispatch_get_main_queue(), ^{
457
- resolve(@[@(success)]);
458
- });
459
- }];
460
- }
461
-
462
- #ifdef RCT_NEW_ARCH_ENABLED
463
- - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
464
- return std::make_shared<facebook::react::NativeHotUpdaterSpecJSI>(params);
465
- }
466
- #endif
467
-
468
- @end
@@ -1,6 +0,0 @@
1
- framework module HotUpdater {
2
- umbrella header "HotUpdater.h"
3
-
4
- export *
5
- module * { export * }
6
- }
@@ -1,9 +0,0 @@
1
- #import <Foundation/Foundation.h>
2
-
3
- @interface HotUpdaterPrefs : NSObject
4
-
5
- + (instancetype)sharedInstanceWithAppVersion:(NSString *)appVersion;
6
- - (NSString *)getItemForKey:(NSString *)key;
7
- - (void)setItem:(NSString *)value forKey:(NSString *)key;
8
-
9
- @end
@@ -1,45 +0,0 @@
1
- #import "HotUpdaterPrefs.h"
2
-
3
- @interface HotUpdaterPrefs ()
4
- @property (nonatomic, strong) NSUserDefaults *userDefaults;
5
- @property (nonatomic, copy) NSString *suiteName;
6
- @end
7
-
8
- @implementation HotUpdaterPrefs
9
-
10
- + (instancetype)sharedInstanceWithAppVersion:(NSString *)appVersion {
11
- static HotUpdaterPrefs *instance = nil;
12
- static NSString *cachedVersion = nil;
13
- @synchronized(self) {
14
- if (instance == nil) {
15
- instance = [[HotUpdaterPrefs alloc] initWithAppVersion:appVersion];
16
- cachedVersion = appVersion;
17
- } else if (![cachedVersion isEqualToString:appVersion]) {
18
- NSString *oldSuiteName = [NSString stringWithFormat:@"HotUpdaterPrefs_%@", cachedVersion];
19
- [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:oldSuiteName];
20
- instance = [[HotUpdaterPrefs alloc] initWithAppVersion:appVersion];
21
- cachedVersion = appVersion;
22
- }
23
- }
24
- return instance;
25
- }
26
-
27
- - (instancetype)initWithAppVersion:(NSString *)appVersion {
28
- self = [super init];
29
- if (self) {
30
- _suiteName = [NSString stringWithFormat:@"HotUpdaterPrefs_%@", appVersion];
31
- _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:_suiteName];
32
- }
33
- return self;
34
- }
35
-
36
- - (NSString *)getItemForKey:(NSString *)key {
37
- return [self.userDefaults objectForKey:key];
38
- }
39
-
40
- - (void)setItem:(NSString *)value forKey:(NSString *)key {
41
- [self.userDefaults setObject:value forKey:key];
42
- [self.userDefaults synchronize];
43
- }
44
-
45
- @end
@@ -1,81 +0,0 @@
1
- /**
2
- * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
- *
4
- * Do not edit this file as changes may cause incorrect behavior and will be lost
5
- * once the code is regenerated.
6
- *
7
- * @generated by codegen project: GenerateModuleObjCpp
8
- *
9
- * We create an umbrella header (and corresponding implementation) here since
10
- * Cxx compilation in BUCK has a limitation: source-code producing genrule()s
11
- * must have a single output. More files => more genrule()s => slower builds.
12
- */
13
-
14
- #import "HotUpdaterSpec.h"
15
-
16
-
17
- @implementation NativeHotUpdaterSpecBase
18
-
19
-
20
- - (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper
21
- {
22
- _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback);
23
- }
24
- @end
25
-
26
-
27
- namespace facebook::react {
28
-
29
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_reload(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
30
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "reload", @selector(reload), args, count);
31
- }
32
-
33
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_updateBundle(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
34
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, PromiseKind, "updateBundle", @selector(updateBundle:zipUrl:resolve:reject:), args, count);
35
- }
36
-
37
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_getAppVersion(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
38
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, PromiseKind, "getAppVersion", @selector(getAppVersion:reject:), args, count);
39
- }
40
-
41
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_setChannel(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
42
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, PromiseKind, "setChannel", @selector(setChannel:resolve:reject:), args, count);
43
- }
44
-
45
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_addListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
46
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "addListener", @selector(addListener:), args, count);
47
- }
48
-
49
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_removeListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
50
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "removeListeners", @selector(removeListeners:), args, count);
51
- }
52
-
53
- static facebook::jsi::Value __hostFunction_NativeHotUpdaterSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
54
- return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, ObjectKind, "getConstants", @selector(getConstants), args, count);
55
- }
56
-
57
- NativeHotUpdaterSpecJSI::NativeHotUpdaterSpecJSI(const ObjCTurboModule::InitParams &params)
58
- : ObjCTurboModule(params) {
59
-
60
- methodMap_["reload"] = MethodMetadata {0, __hostFunction_NativeHotUpdaterSpecJSI_reload};
61
-
62
-
63
- methodMap_["updateBundle"] = MethodMetadata {2, __hostFunction_NativeHotUpdaterSpecJSI_updateBundle};
64
-
65
-
66
- methodMap_["getAppVersion"] = MethodMetadata {0, __hostFunction_NativeHotUpdaterSpecJSI_getAppVersion};
67
-
68
-
69
- methodMap_["setChannel"] = MethodMetadata {1, __hostFunction_NativeHotUpdaterSpecJSI_setChannel};
70
-
71
-
72
- methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeHotUpdaterSpecJSI_addListener};
73
-
74
-
75
- methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeHotUpdaterSpecJSI_removeListeners};
76
-
77
-
78
- methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeHotUpdaterSpecJSI_getConstants};
79
-
80
- }
81
- } // namespace facebook::react