react-native-update 10.39.0 → 10.40.0-beta.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.
- package/android/build.gradle +0 -6
- package/android/jni/Application.mk +1 -1
- package/android/lib/arm64-v8a/librnupdate.so +0 -0
- package/android/lib/armeabi-v7a/librnupdate.so +0 -0
- package/android/lib/x86/librnupdate.so +0 -0
- package/android/lib/x86_64/librnupdate.so +0 -0
- package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +314 -0
- package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +253 -586
- package/android/src/main/java/cn/reactnative/modules/update/NativeUpdateCore.java +1 -9
- package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +220 -0
- package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +9 -3
- package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +36 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +36 -26
- package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +39 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +74 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +143 -260
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleSupport.java +63 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +1 -5
- package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +26 -73
- package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +28 -242
- package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +89 -135
- package/harmony/pushy/src/main/cpp/PushyTurboModule.h +5 -5
- package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +7 -7
- package/harmony/pushy/src/main/ets/PushyPackage.ets +3 -9
- package/harmony/pushy/src/main/ets/PushyPackageCompat.ts +3 -9
- package/harmony/pushy/src/main/ets/PushyPackageFactory.ts +14 -0
- package/harmony/pushy/src/main/ets/PushyTurboModule.ts +124 -24
- package/harmony/pushy/src/main/ets/UpdateContext.ts +92 -70
- package/harmony/pushy.har +0 -0
- package/ios/Expo/ExpoPushyReactDelegateHandler.swift +6 -26
- package/ios/RCTPushy/RCTPushy.mm +315 -259
- package/ios/RCTPushy/RCTPushyDownloader.mm +52 -29
- package/package.json +2 -2
- package/react-native-update.podspec +3 -3
- package/harmony/pushy/src/main/ets/UpdateModuleImpl.ts +0 -123
- package/ios/ImportReact.h +0 -2
- package/ios/RCTPushy/HDiffPatch/HDiffPatch.h +0 -16
- package/ios/RCTPushy/HDiffPatch/HDiffPatch.mm +0 -35
- package/ios/RCTPushy/RCTPushyManager.h +0 -27
- package/ios/RCTPushy/RCTPushyManager.mm +0 -181
- package/ios/RCTPushy.xcodeproj/project.pbxproj +0 -479
- package/package/harmony/pushy.har +0 -0
- package/react-native-update-10.39.0-beta.3.tgz +0 -0
- package/scripts/prune-host-stl.sh +0 -6
package/android/build.gradle
CHANGED
|
@@ -162,11 +162,6 @@ android {
|
|
|
162
162
|
resValue("string", "pushy_build_time", "0")
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
-
|
|
166
|
-
packagingOptions {
|
|
167
|
-
exclude "**/libc++_shared.so"
|
|
168
|
-
}
|
|
169
|
-
|
|
170
165
|
lintOptions {
|
|
171
166
|
abortOnError false
|
|
172
167
|
}
|
|
@@ -181,7 +176,6 @@ repositories {
|
|
|
181
176
|
|
|
182
177
|
dependencies {
|
|
183
178
|
implementation 'com.facebook.react:react-native:+'
|
|
184
|
-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
|
|
185
179
|
}
|
|
186
180
|
if (isNewArchitectureEnabled()) {
|
|
187
181
|
react {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
+
}
|