react-native-ota-hot-update 1.1.5 → 1.1.7

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.
@@ -15,6 +15,9 @@ import java.io.FileInputStream;
15
15
  import java.io.FileOutputStream;
16
16
  import java.io.InputStream;
17
17
  import java.io.OutputStream;
18
+ import java.text.SimpleDateFormat;
19
+ import java.util.Date;
20
+ import java.util.Locale;
18
21
  import java.util.zip.ZipEntry;
19
22
  import java.util.zip.ZipInputStream;
20
23
  import androidx.annotation.NonNull;
@@ -39,13 +42,14 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
39
42
  // Finally, delete the empty directory or file
40
43
  return directory.delete();
41
44
  }
42
- private boolean deleteOldBundleIfneeded() {
45
+ private boolean deleteOldBundleIfneeded(String pathKey) {
46
+ String pathName = pathKey != null ? pathKey : Common.INSTANCE.getPREVIOUS_PATH();
43
47
  SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
44
- String path = sharedPrefs.getString(Common.INSTANCE.getPATH());
48
+ String path = sharedPrefs.getString(pathName);
45
49
  File file = new File(path);
46
50
  if (file.exists() && file.isFile()) {
47
51
  boolean isDeleted = deleteDirectory(file.getParentFile());
48
- sharedPrefs.clear();
52
+ sharedPrefs.putString(pathName, "");
49
53
  return isDeleted;
50
54
  } else {
51
55
  return false;
@@ -53,7 +57,8 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
53
57
  }
54
58
  private String unzip(File zipFile, String extension) {
55
59
  File destDir = zipFile.getParentFile(); // Directory of the zip file
56
-
60
+ String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
61
+ String topLevelFolder = null;
57
62
  String bundleFilePath = null;
58
63
  if (!destDir.exists()) {
59
64
  destDir.mkdirs();
@@ -65,6 +70,12 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
65
70
  ZipEntry zipEntry;
66
71
  while ((zipEntry = zis.getNextEntry()) != null) {
67
72
  File newFile = new File(destDir, zipEntry.getName());
73
+ if (topLevelFolder == null) {
74
+ String[] parts = zipEntry.getName().split("/");
75
+ if (parts.length > 1) {
76
+ topLevelFolder = parts[0];
77
+ }
78
+ }
68
79
  if (zipEntry.isDirectory()) {
69
80
  newFile.mkdirs();
70
81
  } else {
@@ -87,6 +98,14 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
87
98
  } catch (Exception e) {
88
99
  return null;
89
100
  }
101
+ if (topLevelFolder != null) {
102
+ File extractedFolder = new File(destDir, topLevelFolder);
103
+ File renameFolder = new File(destDir, "output_" + timestamp);
104
+ if (extractedFolder.exists()) {
105
+ extractedFolder.renameTo(renameFolder);
106
+ bundleFilePath = bundleFilePath.replace(extractedFolder.getAbsolutePath(), renameFolder.getAbsolutePath());
107
+ }
108
+ }
90
109
  return bundleFilePath;
91
110
  }
92
111
 
@@ -95,12 +114,16 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
95
114
  if (path != null) {
96
115
  File file = new File(path);
97
116
  if (file.exists() && file.isFile()) {
98
- deleteOldBundleIfneeded();
117
+ deleteOldBundleIfneeded(null);
99
118
  String fileUnzip = unzip(file, extension != null ? extension : ".bundle");
100
119
  if (fileUnzip != null) {
101
120
  Log.d("setupBundlePath: ", fileUnzip);
102
121
  file.delete();
103
122
  SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
123
+ String oldPath = sharedPrefs.getString(Common.INSTANCE.getPATH());
124
+ if (!oldPath.equals("")) {
125
+ sharedPrefs.putString(Common.INSTANCE.getPREVIOUS_PATH(), oldPath);
126
+ }
104
127
  sharedPrefs.putString(Common.INSTANCE.getPATH(), fileUnzip);
105
128
  PackageInfo info = OtaHotUpdate.packageInfo(getReactApplicationContext());
106
129
  String latestVer = null;
@@ -126,10 +149,11 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
126
149
 
127
150
  @ReactMethod
128
151
  public void deleteBundle(Promise promise) {
129
- boolean isDeleted = deleteOldBundleIfneeded();
152
+ boolean isDeleted = deleteOldBundleIfneeded(null);
153
+ boolean isDeletedOld = deleteOldBundleIfneeded(Common.INSTANCE.getPATH());
130
154
  SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
131
155
  sharedPrefs.putString(Common.INSTANCE.getVERSION(), "0");
132
- promise.resolve(isDeleted);
156
+ promise.resolve(isDeleted && isDeletedOld);
133
157
  }
134
158
  @ReactMethod
135
159
  public void restart() {
@@ -147,6 +171,24 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
147
171
  }
148
172
  }
149
173
  @ReactMethod
174
+ public void rollbackToPreviousBundle(Promise promise) {
175
+ SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
176
+ String oldPath = sharedPrefs.getString(Common.INSTANCE.getPREVIOUS_PATH());
177
+ if (!oldPath.equals("")) {
178
+ boolean isDeleted = deleteOldBundleIfneeded(Common.INSTANCE.getPATH());
179
+ if (isDeleted) {
180
+ sharedPrefs.putString(Common.INSTANCE.getPATH(), oldPath);
181
+ sharedPrefs.putString(Common.INSTANCE.getPREVIOUS_PATH(), "");
182
+ promise.resolve(true);
183
+ } else {
184
+ promise.resolve(false);
185
+ }
186
+ } else {
187
+ promise.resolve(false);
188
+ }
189
+
190
+ }
191
+ @ReactMethod
150
192
  public void getCurrentVersion(Promise promise) {
151
193
  SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
152
194
  String version = sharedPrefs.getString(Common.INSTANCE.getVERSION());
@@ -159,13 +201,13 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
159
201
  }
160
202
  @ReactMethod
161
203
  public void setCurrentVersion(String version, Promise promise) {
162
- SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
163
- sharedPrefs.putString(Common.INSTANCE.getVERSION(), version);
164
- promise.resolve(true);
204
+ SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
205
+ sharedPrefs.putString(Common.INSTANCE.getVERSION(), version);
206
+ promise.resolve(true);
165
207
  }
166
208
 
167
209
  @ReactMethod
168
- public void setExactBundlePath(String path, Promise promise) {
210
+ public void setExactBundlePath(String path, Promise promise) {
169
211
  SharedPrefs sharedPrefs = new SharedPrefs(getReactApplicationContext());
170
212
  sharedPrefs.putString(Common.INSTANCE.getPATH(), path);
171
213
  PackageInfo info = OtaHotUpdate.packageInfo(getReactApplicationContext());
@@ -175,7 +217,7 @@ public class HotUpdateModule extends ReactContextBaseJavaModule {
175
217
  }
176
218
  sharedPrefs.putString(Common.INSTANCE.getCURRENT_VERSION_NAME(), latestVer);
177
219
  promise.resolve(true);
178
- }
220
+ }
179
221
 
180
222
  @NonNull
181
223
  @Override
package/ios/RNhotupdate.m CHANGED
@@ -11,13 +11,14 @@ RCT_EXPORT_MODULE()
11
11
  return [fileManager fileExistsAtPath:path];
12
12
  }
13
13
 
14
- - (BOOL)removeBundleIfNeeded {
14
+ - (BOOL)removeBundleIfNeeded:(NSString *)pathKey {
15
+ NSString *keyToUse = pathKey ? pathKey : @"OLD_PATH";
15
16
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
16
- NSString *retrievedString = [defaults stringForKey:@"PATH"];
17
+ NSString *retrievedString = [defaults stringForKey:keyToUse];
17
18
  NSError *error = nil;
18
19
  if (retrievedString && [self isFilePathValid:retrievedString]) {
19
20
  BOOL isDeleted = [self deleteAllContentsOfParentDirectoryOfFile:retrievedString error:&error];
20
- [defaults removeObjectForKey:@"PATH"];
21
+ [defaults removeObjectForKey:keyToUse];
21
22
  [defaults synchronize];
22
23
  return isDeleted;
23
24
  } else {
@@ -130,6 +131,34 @@ RCT_EXPORT_MODULE()
130
131
 
131
132
  return nil;
132
133
  }
134
+ - (NSString *)renameExtractedFolderInDirectory:(NSString *)directoryPath {
135
+ NSFileManager *fileManager = [NSFileManager defaultManager];
136
+ NSError *error = nil;
137
+
138
+ // Get the contents of the extracted directory
139
+ NSArray *contents = [fileManager contentsOfDirectoryAtPath:directoryPath error:&error];
140
+ if (error || contents.count != 1) {
141
+ NSLog(@"Error retrieving extracted folder or unexpected structure: %@", error.localizedDescription);
142
+ return nil;
143
+ }
144
+
145
+ // Get the original extracted folder name (assuming only one folder exists)
146
+ NSString *originalFolderName = contents.firstObject;
147
+ NSString *originalFolderPath = [directoryPath stringByAppendingPathComponent:originalFolderName];
148
+
149
+ // Generate new folder name with timestamp
150
+ NSString *timestamp = [NSString stringWithFormat:@"output_%ld", (long)[[NSDate date] timeIntervalSince1970]];
151
+ NSString *newFolderPath = [directoryPath stringByAppendingPathComponent:timestamp];
152
+
153
+ // Rename the extracted folder
154
+ if (![fileManager moveItemAtPath:originalFolderPath toPath:newFolderPath error:&error]) {
155
+ NSLog(@"Failed to rename folder: %@", error.localizedDescription);
156
+ return nil;
157
+ }
158
+
159
+ NSLog(@"Renamed extracted folder to: %@", newFolderPath);
160
+ return newFolderPath;
161
+ }
133
162
  - (NSString *)unzipFileAtPath:(NSString *)zipFilePath extension:(NSString *)extension {
134
163
  // Define the directory where the files will be extracted
135
164
  NSString *extractedFolderPath = [[zipFilePath stringByDeletingPathExtension] stringByAppendingPathExtension:@"unzip"];
@@ -153,8 +182,13 @@ RCT_EXPORT_MODULE()
153
182
  NSLog(@"Failed to unzip file");
154
183
  return nil;
155
184
  }
185
+ // Try renaming the extracted folder
186
+ NSString *renamedFolderPath = [self renameExtractedFolderInDirectory:extractedFolderPath];
187
+
188
+ // If renaming fails, use the original extracted folder path
189
+ NSString *finalFolderPath = renamedFolderPath ? renamedFolderPath : extractedFolderPath;
156
190
  // Find .jsbundle files in the extracted directory
157
- NSString *jsbundleFilePath = [self searchForJsBundleInDirectory:extractedFolderPath extension:extension];
191
+ NSString *jsbundleFilePath = [self searchForJsBundleInDirectory:finalFolderPath extension:extension];
158
192
 
159
193
  // Delete the zip file after extraction
160
194
  NSError *removeError = nil;
@@ -170,12 +204,16 @@ RCT_EXPORT_MODULE()
170
204
  // Expose setupBundlePath method to JavaScript
171
205
  RCT_EXPORT_METHOD(setupBundlePath:(NSString *)path extension:(NSString *)extension withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject) {
172
206
  if ([self isFilePathValid:path]) {
173
- [self removeBundleIfNeeded];
207
+ [self removeBundleIfNeeded:nil];
174
208
  //Unzip file
175
209
  NSString *extractedFilePath = [self unzipFileAtPath:path extension:(extension != nil) ? extension : @".jsbundle"];
176
210
  if (extractedFilePath) {
177
211
  NSLog(@"file extraction----- %@", extractedFilePath);
178
212
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
213
+ NSString *oldPath = [defaults stringForKey:@"PATH"];
214
+ if (oldPath) {
215
+ [defaults setObject:oldPath forKey:@"OLD_PATH"];
216
+ }
179
217
  [defaults setObject:extractedFilePath forKey:@"PATH"];
180
218
  [defaults setObject:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] forKey:@"VERSION_NAME"];
181
219
  [defaults synchronize];
@@ -190,10 +228,34 @@ RCT_EXPORT_METHOD(setupBundlePath:(NSString *)path extension:(NSString *)extensi
190
228
 
191
229
  // Expose deleteBundle method to JavaScript
192
230
  RCT_EXPORT_METHOD(deleteBundle:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject) {
193
- BOOL isDeleted = [self removeBundleIfNeeded];
194
- resolve(@(isDeleted));
231
+ BOOL isDeleted = [self removeBundleIfNeeded:@"PATH"];
232
+ BOOL isDeletedOld = [self removeBundleIfNeeded:nil];
233
+ if (isDeleted && isDeletedOld) {
234
+ resolve(@(YES));
235
+ } else {
236
+ resolve(@(NO));
237
+ }
238
+ }
239
+ // Expose deleteBundle method to JavaScript
240
+ RCT_EXPORT_METHOD(rollbackToPreviousBundle:(double)i
241
+ resolve:(RCTPromiseResolveBlock)resolve
242
+ reject:(RCTPromiseRejectBlock)reject) {
243
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
244
+ NSString *oldPath = [defaults stringForKey:@"OLD_PATH"];
245
+ if (oldPath && [self isFilePathValid:oldPath]) {
246
+ BOOL isDeleted = [self removeBundleIfNeeded:@"PATH"];
247
+ if (isDeleted) {
248
+ [defaults setObject:oldPath forKey:@"PATH"];
249
+ [defaults removeObjectForKey:@"OLD_PATH"];
250
+ [defaults synchronize];
251
+ resolve(@(YES));
252
+ } else {
253
+ resolve(@(NO));
254
+ }
255
+ } else {
256
+ resolve(@(NO));
257
+ }
195
258
  }
196
-
197
259
  RCT_EXPORT_METHOD(getCurrentVersion:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject) {
198
260
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
199
261
  NSString *version = [defaults stringForKey:@"VERSION"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ota-hot-update",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Hot update for react native",
5
5
  "main": "src/index",
6
6
  "repository": "https://github.com/vantuan88291/react-native-ota-hot-update",
@@ -12,7 +12,7 @@
12
12
  "homepage": "https://github.com/vantuan88291/react-native-ota-hot-update",
13
13
  "dependencies": {
14
14
  "buffer": "^6.0.3",
15
- "isomorphic-git": "git+https://github.com/vantuan88291/isomorphic-git.git"
15
+ "isomorphic-git": "1.27.3"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "react-native": ">=0.63.4",
package/src/index.tsx CHANGED
@@ -46,6 +46,9 @@ function deleteBundlePath(): Promise<boolean> {
46
46
  function getCurrentVersion(): Promise<string> {
47
47
  return RNhotupdate.getCurrentVersion();
48
48
  }
49
+ function rollbackToPreviousBundle(): Promise<boolean> {
50
+ return RNhotupdate.rollbackToPreviousBundle();
51
+ }
49
52
  async function getVersionAsNumber() {
50
53
  const rawVersion = await getCurrentVersion();
51
54
  return +rawVersion;
@@ -168,6 +171,7 @@ export default {
168
171
  resetApp,
169
172
  getCurrentVersion: getVersionAsNumber,
170
173
  setCurrentVersion,
174
+ rollbackToPreviousBundle,
171
175
  git: {
172
176
  checkForGitUpdate,
173
177
  ...git,