react-native-update 10.39.1 → 10.40.0-beta.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 (39) hide show
  1. package/android/build.gradle +0 -1
  2. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +314 -0
  3. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +253 -586
  4. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +220 -0
  5. package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +9 -3
  6. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +36 -0
  7. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +36 -26
  8. package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +39 -0
  9. package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +74 -0
  10. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +143 -260
  11. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleSupport.java +63 -0
  12. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +1 -5
  13. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +26 -73
  14. package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +28 -242
  15. package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +89 -135
  16. package/harmony/pushy/src/main/cpp/PushyTurboModule.h +5 -5
  17. package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +7 -7
  18. package/harmony/pushy/src/main/ets/PushyPackage.ets +3 -9
  19. package/harmony/pushy/src/main/ets/PushyPackageCompat.ts +3 -9
  20. package/harmony/pushy/src/main/ets/PushyPackageFactory.ts +14 -0
  21. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +124 -24
  22. package/harmony/pushy/src/main/ets/UpdateContext.ts +92 -70
  23. package/harmony/pushy.har +0 -0
  24. package/ios/Expo/ExpoPushyReactDelegateHandler.swift +6 -26
  25. package/ios/RCTPushy/RCTPushy.mm +315 -259
  26. package/ios/RCTPushy/RCTPushyDownloader.mm +52 -29
  27. package/package/harmony/pushy.har +0 -0
  28. package/package.json +11 -11
  29. package/react-native-update-10.40.0-beta.0.tgz +0 -0
  30. package/react-native-update.podspec +3 -3
  31. package/src/utils.ts +7 -1
  32. package/harmony/pushy/src/main/ets/UpdateModuleImpl.ts +0 -123
  33. package/ios/ImportReact.h +0 -2
  34. package/ios/RCTPushy/HDiffPatch/HDiffPatch.h +0 -16
  35. package/ios/RCTPushy/HDiffPatch/HDiffPatch.mm +0 -35
  36. package/ios/RCTPushy/RCTPushyManager.h +0 -27
  37. package/ios/RCTPushy/RCTPushyManager.mm +0 -181
  38. package/ios/RCTPushy.xcodeproj/project.pbxproj +0 -479
  39. package/react-native-update-10.39.0.tgz +0 -0
@@ -176,7 +176,6 @@ repositories {
176
176
 
177
177
  dependencies {
178
178
  implementation 'com.facebook.react:react-native:+'
179
- implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
180
179
  }
181
180
  if (isNewArchitectureEnabled()) {
182
181
  react {
@@ -0,0 +1,314 @@
1
+ package cn.reactnative.modules.update;
2
+
3
+ import android.content.Context;
4
+ import android.content.pm.ApplicationInfo;
5
+ import android.content.pm.PackageManager;
6
+ import android.content.res.Resources;
7
+ import android.os.Build;
8
+ import android.util.DisplayMetrics;
9
+ import android.util.Log;
10
+ import android.util.TypedValue;
11
+ import java.io.File;
12
+ import java.io.IOException;
13
+ import java.io.InputStream;
14
+ import java.util.ArrayList;
15
+ import java.util.Enumeration;
16
+ import java.util.HashMap;
17
+ import java.util.zip.ZipEntry;
18
+ import java.util.regex.Pattern;
19
+
20
+ final class BundledResourceCopier {
21
+ private static final Pattern VERSION_QUALIFIER_PATTERN = Pattern.compile("-v\\d+(?=/)");
22
+ private static final String AAB_BASE_PREFIX = "base/";
23
+
24
+ private final Context context;
25
+
26
+ private static final class ResolvedResourceSource {
27
+ final int resourceId;
28
+ final String assetPath;
29
+
30
+ ResolvedResourceSource(int resourceId, String assetPath) {
31
+ this.resourceId = resourceId;
32
+ this.assetPath = assetPath;
33
+ }
34
+ }
35
+
36
+ BundledResourceCopier(Context context) {
37
+ this.context = context.getApplicationContext();
38
+ }
39
+
40
+ void copyFromResource(HashMap<String, ArrayList<File>> resToCopy) throws IOException {
41
+ if (UpdateContext.DEBUG) {
42
+ Log.d(UpdateContext.TAG, "copyFromResource called, resToCopy size: " + resToCopy.size());
43
+ }
44
+
45
+ ArrayList<String> apkPaths = collectApkPaths();
46
+ HashMap<String, ZipEntry> availableEntries = new HashMap<String, ZipEntry>();
47
+ HashMap<String, SafeZipFile> zipFileMap = new HashMap<String, SafeZipFile>();
48
+ HashMap<String, SafeZipFile> entryToZipFileMap = new HashMap<String, SafeZipFile>();
49
+
50
+ try {
51
+ for (String apkPath : apkPaths) {
52
+ SafeZipFile zipFile = new SafeZipFile(new File(apkPath));
53
+ zipFileMap.put(apkPath, zipFile);
54
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
55
+ while (entries.hasMoreElements()) {
56
+ ZipEntry ze = entries.nextElement();
57
+ String entryName = ze.getName();
58
+ if (!availableEntries.containsKey(entryName)) {
59
+ availableEntries.put(entryName, ze);
60
+ entryToZipFileMap.put(entryName, zipFile);
61
+ }
62
+ }
63
+ }
64
+
65
+ HashMap<String, String> normalizedEntryMap = new HashMap<String, String>();
66
+ for (String entryName : availableEntries.keySet()) {
67
+ String normalized = normalizeResPath(entryName);
68
+ normalizedEntryMap.putIfAbsent(normalized, entryName);
69
+ }
70
+
71
+ SafeZipFile baseZipFile = zipFileMap.get(context.getPackageResourcePath());
72
+ HashMap<String, ArrayList<File>> remainingFiles =
73
+ new HashMap<String, ArrayList<File>>(resToCopy);
74
+
75
+ for (String fromPath : new ArrayList<String>(remainingFiles.keySet())) {
76
+ if (UpdateContext.DEBUG) {
77
+ Log.d(UpdateContext.TAG, "Processing fromPath: " + fromPath);
78
+ }
79
+
80
+ ArrayList<File> targets = remainingFiles.get(fromPath);
81
+ if (targets == null || targets.isEmpty()) {
82
+ continue;
83
+ }
84
+
85
+ ZipEntry entry = availableEntries.get(fromPath);
86
+ String actualSourcePath = fromPath;
87
+ ResolvedResourceSource resolvedResource = null;
88
+
89
+ if (entry == null) {
90
+ String normalizedFrom = normalizeResPath(fromPath);
91
+ String actualEntry = normalizedEntryMap.get(normalizedFrom);
92
+ if (actualEntry != null) {
93
+ entry = availableEntries.get(actualEntry);
94
+ actualSourcePath = actualEntry;
95
+ if (UpdateContext.DEBUG) {
96
+ Log.d(UpdateContext.TAG, "Normalized match: " + fromPath + " -> " + actualEntry);
97
+ }
98
+ }
99
+ }
100
+
101
+ if (entry == null) {
102
+ resolvedResource = resolveBundledResource(fromPath);
103
+ if (resolvedResource != null) {
104
+ actualSourcePath = resolvedResource.assetPath;
105
+ }
106
+ }
107
+
108
+ if (entry == null && resolvedResource == null) {
109
+ continue;
110
+ }
111
+
112
+ File lastTarget = null;
113
+ for (File target : targets) {
114
+ if (UpdateContext.DEBUG) {
115
+ Log.d(UpdateContext.TAG, "Copying from resource " + actualSourcePath + " to " + target);
116
+ }
117
+ try {
118
+ if (lastTarget != null) {
119
+ UpdateFileUtils.copyFile(lastTarget, target);
120
+ } else if (entry != null) {
121
+ SafeZipFile sourceZipFile = entryToZipFileMap.get(actualSourcePath);
122
+ if (sourceZipFile == null) {
123
+ sourceZipFile = baseZipFile;
124
+ }
125
+ sourceZipFile.unzipToFile(entry, target);
126
+ } else {
127
+ InputStream in = openResolvedResourceStream(resolvedResource);
128
+ UpdateFileUtils.copyInputStreamToFile(in, target);
129
+ }
130
+ lastTarget = target;
131
+ } catch (IOException e) {
132
+ if (UpdateContext.DEBUG) {
133
+ Log.w(
134
+ UpdateContext.TAG,
135
+ "Failed to copy resource "
136
+ + actualSourcePath
137
+ + " to "
138
+ + target
139
+ + ": "
140
+ + e.getMessage()
141
+ );
142
+ }
143
+ }
144
+ }
145
+ remainingFiles.remove(fromPath);
146
+ }
147
+
148
+ if (!remainingFiles.isEmpty() && UpdateContext.DEBUG) {
149
+ for (String fromPath : remainingFiles.keySet()) {
150
+ Log.w(UpdateContext.TAG, "Resource not found and no fallback available: " + fromPath);
151
+ }
152
+ }
153
+ } finally {
154
+ closeZipFiles(zipFileMap);
155
+ }
156
+ }
157
+
158
+ private String normalizeResPath(String path) {
159
+ String result = path;
160
+ if (result.startsWith(AAB_BASE_PREFIX)) {
161
+ result = result.substring(AAB_BASE_PREFIX.length());
162
+ }
163
+ return VERSION_QUALIFIER_PATTERN.matcher(result).replaceAll("");
164
+ }
165
+
166
+ private String extractResourceType(String directoryName) {
167
+ int qualifierIndex = directoryName.indexOf('-');
168
+ if (qualifierIndex == -1) {
169
+ return directoryName;
170
+ }
171
+ return directoryName.substring(0, qualifierIndex);
172
+ }
173
+
174
+ private String extractResourceName(String fileName) {
175
+ if (fileName.endsWith(".9.png")) {
176
+ return fileName.substring(0, fileName.length() - ".9.png".length());
177
+ }
178
+ int extensionIndex = fileName.lastIndexOf('.');
179
+ if (extensionIndex == -1) {
180
+ return fileName;
181
+ }
182
+ return fileName.substring(0, extensionIndex);
183
+ }
184
+
185
+ private Integer parseDensityQualifier(String directoryName) {
186
+ String[] qualifiers = directoryName.split("-");
187
+ for (String qualifier : qualifiers) {
188
+ if ("ldpi".equals(qualifier)) {
189
+ return DisplayMetrics.DENSITY_LOW;
190
+ }
191
+ if ("mdpi".equals(qualifier)) {
192
+ return DisplayMetrics.DENSITY_MEDIUM;
193
+ }
194
+ if ("hdpi".equals(qualifier)) {
195
+ return DisplayMetrics.DENSITY_HIGH;
196
+ }
197
+ if ("xhdpi".equals(qualifier)) {
198
+ return DisplayMetrics.DENSITY_XHIGH;
199
+ }
200
+ if ("xxhdpi".equals(qualifier)) {
201
+ return DisplayMetrics.DENSITY_XXHIGH;
202
+ }
203
+ if ("xxxhdpi".equals(qualifier)) {
204
+ return DisplayMetrics.DENSITY_XXXHIGH;
205
+ }
206
+ if ("tvdpi".equals(qualifier)) {
207
+ return DisplayMetrics.DENSITY_TV;
208
+ }
209
+ }
210
+ return null;
211
+ }
212
+
213
+ private ResolvedResourceSource resolveBundledResource(String resourcePath) {
214
+ String normalizedPath = normalizeResPath(resourcePath);
215
+ if (normalizedPath.startsWith("res/")) {
216
+ normalizedPath = normalizedPath.substring("res/".length());
217
+ }
218
+
219
+ int slash = normalizedPath.indexOf('/');
220
+ if (slash == -1 || slash == normalizedPath.length() - 1) {
221
+ return null;
222
+ }
223
+
224
+ String directoryName = normalizedPath.substring(0, slash);
225
+ String fileName = normalizedPath.substring(slash + 1);
226
+ String resourceType = extractResourceType(directoryName);
227
+ String resourceName = extractResourceName(fileName);
228
+ if (resourceType == null || resourceType.isEmpty() || resourceName.isEmpty()) {
229
+ return null;
230
+ }
231
+
232
+ Resources resources = context.getResources();
233
+ int resourceId = resources.getIdentifier(resourceName, resourceType, context.getPackageName());
234
+ if (resourceId == 0) {
235
+ return null;
236
+ }
237
+
238
+ TypedValue typedValue = new TypedValue();
239
+ try {
240
+ Integer density = parseDensityQualifier(directoryName);
241
+ if (density != null) {
242
+ resources.getValueForDensity(resourceId, density, typedValue, true);
243
+ } else {
244
+ resources.getValue(resourceId, typedValue, true);
245
+ }
246
+ } catch (Resources.NotFoundException e) {
247
+ if (UpdateContext.DEBUG) {
248
+ Log.d(
249
+ UpdateContext.TAG,
250
+ "Failed to resolve resource value for " + resourcePath + ": " + e.getMessage()
251
+ );
252
+ }
253
+ return null;
254
+ }
255
+
256
+ if (typedValue.string == null) {
257
+ return null;
258
+ }
259
+
260
+ String assetPath = typedValue.string.toString();
261
+ if (assetPath.startsWith("/")) {
262
+ assetPath = assetPath.substring(1);
263
+ }
264
+
265
+ if (UpdateContext.DEBUG) {
266
+ Log.d(UpdateContext.TAG, "Resolved resource path " + resourcePath + " -> " + assetPath);
267
+ }
268
+ return new ResolvedResourceSource(resourceId, assetPath);
269
+ }
270
+
271
+ private InputStream openResolvedResourceStream(ResolvedResourceSource source) throws IOException {
272
+ try {
273
+ return context.getResources().openRawResource(source.resourceId);
274
+ } catch (Resources.NotFoundException e) {
275
+ throw new IOException("Unable to open resolved resource: " + source.assetPath, e);
276
+ }
277
+ }
278
+
279
+ private ArrayList<String> collectApkPaths() {
280
+ ArrayList<String> apkPaths = new ArrayList<String>();
281
+ apkPaths.add(context.getPackageResourcePath());
282
+
283
+ try {
284
+ ApplicationInfo appInfo =
285
+ context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
286
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && appInfo.splitSourceDirs != null) {
287
+ for (String splitPath : appInfo.splitSourceDirs) {
288
+ apkPaths.add(splitPath);
289
+ if (UpdateContext.DEBUG) {
290
+ Log.d(UpdateContext.TAG, "Found split APK: " + splitPath);
291
+ }
292
+ }
293
+ }
294
+ } catch (PackageManager.NameNotFoundException e) {
295
+ if (UpdateContext.DEBUG) {
296
+ Log.w(UpdateContext.TAG, "Failed to get application info: " + e.getMessage());
297
+ }
298
+ }
299
+
300
+ return apkPaths;
301
+ }
302
+
303
+ private void closeZipFiles(HashMap<String, SafeZipFile> zipFileMap) {
304
+ for (SafeZipFile zipFile : zipFileMap.values()) {
305
+ try {
306
+ zipFile.close();
307
+ } catch (IOException e) {
308
+ if (UpdateContext.DEBUG) {
309
+ Log.w(UpdateContext.TAG, "Failed to close zip file", e);
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }