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
|
@@ -1,198 +1,146 @@
|
|
|
1
1
|
package cn.reactnative.modules.update;
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
|
-
import android.
|
|
5
|
-
import android.
|
|
6
|
-
import android.content.res.Resources;
|
|
7
|
-
import android.os.AsyncTask;
|
|
8
|
-
import android.os.Build;
|
|
9
|
-
import android.util.DisplayMetrics;
|
|
4
|
+
import android.os.Handler;
|
|
5
|
+
import android.os.Looper;
|
|
10
6
|
import android.util.Log;
|
|
11
|
-
import android.util.TypedValue;
|
|
12
7
|
import com.facebook.react.bridge.Arguments;
|
|
13
8
|
import com.facebook.react.bridge.WritableMap;
|
|
14
|
-
|
|
15
|
-
import okhttp3.OkHttpClient;
|
|
16
|
-
import okhttp3.Request;
|
|
17
|
-
import okhttp3.Response;
|
|
18
|
-
import okhttp3.ResponseBody;
|
|
19
|
-
|
|
20
|
-
import org.json.JSONException;
|
|
21
|
-
import org.json.JSONObject;
|
|
22
|
-
import org.json.JSONTokener;
|
|
23
|
-
|
|
24
9
|
import java.io.ByteArrayOutputStream;
|
|
25
10
|
import java.io.File;
|
|
26
|
-
import java.io.FileInputStream;
|
|
27
|
-
import java.io.FileOutputStream;
|
|
28
11
|
import java.io.IOException;
|
|
29
12
|
import java.io.InputStream;
|
|
13
|
+
import java.nio.charset.StandardCharsets;
|
|
30
14
|
import java.util.ArrayList;
|
|
31
15
|
import java.util.Enumeration;
|
|
16
|
+
import java.util.HashMap;
|
|
32
17
|
import java.util.Iterator;
|
|
33
18
|
import java.util.zip.ZipEntry;
|
|
34
|
-
import
|
|
35
|
-
import
|
|
36
|
-
|
|
19
|
+
import okhttp3.OkHttpClient;
|
|
20
|
+
import okhttp3.Request;
|
|
21
|
+
import okhttp3.Response;
|
|
22
|
+
import okhttp3.ResponseBody;
|
|
37
23
|
import okio.BufferedSink;
|
|
38
24
|
import okio.BufferedSource;
|
|
39
25
|
import okio.Okio;
|
|
40
|
-
import
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
44
|
-
final int DOWNLOAD_CHUNK_SIZE = 4096;
|
|
45
|
-
|
|
46
|
-
Context context;
|
|
47
|
-
String hash;
|
|
26
|
+
import org.json.JSONException;
|
|
27
|
+
import org.json.JSONObject;
|
|
28
|
+
import org.json.JSONTokener;
|
|
48
29
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
30
|
+
class DownloadTask implements Runnable {
|
|
31
|
+
private static final int DOWNLOAD_CHUNK_SIZE = 4096;
|
|
32
|
+
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
|
|
52
33
|
|
|
53
34
|
static {
|
|
54
35
|
NativeUpdateCore.ensureLoaded();
|
|
55
36
|
}
|
|
56
37
|
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
File[] files = file.listFiles();
|
|
63
|
-
for (File f : files) {
|
|
64
|
-
String name = f.getName();
|
|
65
|
-
if (name.equals(".") || name.equals("..")) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
removeDirectory(f);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (file.exists() && !file.delete()) {
|
|
72
|
-
throw new IOException("Failed to delete directory");
|
|
73
|
-
}
|
|
38
|
+
private static final class PatchArchiveContents {
|
|
39
|
+
final ArrayList<String> entryNames = new ArrayList<String>();
|
|
40
|
+
final ArrayList<String> copyFroms = new ArrayList<String>();
|
|
41
|
+
final ArrayList<String> copyTos = new ArrayList<String>();
|
|
42
|
+
final ArrayList<String> deletes = new ArrayList<String>();
|
|
74
43
|
}
|
|
75
44
|
|
|
76
|
-
private
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
long contentLength = body.contentLength();
|
|
89
|
-
BufferedSource source = body.source();
|
|
45
|
+
private final Context context;
|
|
46
|
+
private final DownloadTaskParams params;
|
|
47
|
+
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
|
48
|
+
private final byte[] buffer = new byte[DOWNLOAD_CHUNK_SIZE];
|
|
49
|
+
private final BundledResourceCopier bundledResourceCopier;
|
|
50
|
+
private String hash;
|
|
51
|
+
|
|
52
|
+
DownloadTask(Context context, DownloadTaskParams params) {
|
|
53
|
+
this.context = context.getApplicationContext();
|
|
54
|
+
this.params = params;
|
|
55
|
+
this.bundledResourceCopier = new BundledResourceCopier(this.context);
|
|
56
|
+
}
|
|
90
57
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
58
|
+
private void postProgress(final long received, final long total) {
|
|
59
|
+
mainHandler.post(new Runnable() {
|
|
60
|
+
@Override
|
|
61
|
+
public void run() {
|
|
62
|
+
WritableMap progress = Arguments.createMap();
|
|
63
|
+
progress.putDouble("received", received);
|
|
64
|
+
progress.putDouble("total", total);
|
|
65
|
+
progress.putString("hash", hash);
|
|
66
|
+
UpdateEventEmitter.sendEvent("RCTPushyDownloadProgress", progress);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
94
70
|
|
|
95
|
-
|
|
71
|
+
private void downloadFile() throws IOException {
|
|
72
|
+
this.hash = params.hash;
|
|
73
|
+
String url = params.url;
|
|
74
|
+
File writePath = params.targetFile;
|
|
75
|
+
UpdateFileUtils.ensureParentDirectory(writePath);
|
|
76
|
+
Request request = new Request.Builder().url(url).build();
|
|
96
77
|
|
|
97
|
-
if (
|
|
98
|
-
|
|
78
|
+
if (writePath.exists() && !writePath.delete()) {
|
|
79
|
+
throw new IOException("Failed to replace existing file: " + writePath);
|
|
99
80
|
}
|
|
100
81
|
|
|
101
|
-
long bytesRead = 0;
|
|
102
|
-
long received = 0;
|
|
103
|
-
int currentPercentage = 0;
|
|
104
|
-
while ((bytesRead = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
|
|
105
|
-
received += bytesRead;
|
|
106
|
-
sink.emit();
|
|
107
|
-
|
|
108
|
-
int percentage = (int)(received * 100.0 / contentLength + 0.5);
|
|
109
|
-
if (percentage > currentPercentage) {
|
|
110
|
-
currentPercentage = percentage;
|
|
111
|
-
publishProgress(new long[]{received, contentLength});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (received != contentLength) {
|
|
115
|
-
throw new Error("Unexpected eof while reading downloaded update");
|
|
116
|
-
}
|
|
117
|
-
publishProgress(new long[]{received, contentLength});
|
|
118
|
-
sink.writeAll(source);
|
|
119
|
-
sink.close();
|
|
120
|
-
|
|
121
82
|
if (UpdateContext.DEBUG) {
|
|
122
|
-
Log.d(
|
|
83
|
+
Log.d(UpdateContext.TAG, "Downloading " + url);
|
|
123
84
|
}
|
|
124
|
-
}
|
|
125
85
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
params.putDouble("received", (values[0][0]));
|
|
131
|
-
params.putDouble("total", (values[0][1]));
|
|
132
|
-
params.putString("hash", this.hash);
|
|
133
|
-
sendEvent("RCTPushyDownloadProgress", params);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
byte[] buffer = new byte[1024*4];
|
|
86
|
+
try (Response response = HTTP_CLIENT.newCall(request).execute()) {
|
|
87
|
+
if (!response.isSuccessful()) {
|
|
88
|
+
throw new IOException("Server error: " + response.code() + " " + response.message());
|
|
89
|
+
}
|
|
137
90
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
String bundlePatchPath,
|
|
143
|
-
String bundleOutputPath,
|
|
144
|
-
String mergeSourceSubdir,
|
|
145
|
-
boolean enableMerge,
|
|
146
|
-
String[] copyFroms,
|
|
147
|
-
String[] copyTos,
|
|
148
|
-
String[] deletes
|
|
149
|
-
);
|
|
150
|
-
private static native void cleanupOldEntries(
|
|
151
|
-
String rootDir,
|
|
152
|
-
String keepCurrent,
|
|
153
|
-
String keepPrevious,
|
|
154
|
-
int maxAgeDays
|
|
155
|
-
);
|
|
156
|
-
private static native ArchivePatchPlanResult buildArchivePatchPlan(
|
|
157
|
-
int patchType,
|
|
158
|
-
String[] entryNames,
|
|
159
|
-
String[] copyFroms,
|
|
160
|
-
String[] copyTos,
|
|
161
|
-
String[] deletes
|
|
162
|
-
);
|
|
163
|
-
private static native CopyGroupResult[] buildCopyGroups(
|
|
164
|
-
String[] copyFroms,
|
|
165
|
-
String[] copyTos
|
|
166
|
-
);
|
|
91
|
+
ResponseBody body = response.body();
|
|
92
|
+
if (body == null) {
|
|
93
|
+
throw new IOException("Empty response body for " + url);
|
|
94
|
+
}
|
|
167
95
|
|
|
96
|
+
long contentLength = body.contentLength();
|
|
97
|
+
long bytesRead;
|
|
98
|
+
long received = 0;
|
|
99
|
+
int currentPercentage = 0;
|
|
168
100
|
|
|
169
|
-
|
|
170
|
-
|
|
101
|
+
try (
|
|
102
|
+
BufferedSource source = body.source();
|
|
103
|
+
BufferedSink sink = Okio.buffer(Okio.sink(writePath))
|
|
104
|
+
) {
|
|
105
|
+
while ((bytesRead = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
|
|
106
|
+
received += bytesRead;
|
|
107
|
+
sink.emit();
|
|
171
108
|
|
|
172
|
-
|
|
173
|
-
|
|
109
|
+
if (contentLength > 0) {
|
|
110
|
+
int percentage = (int) (received * 100.0 / contentLength + 0.5);
|
|
111
|
+
if (percentage > currentPercentage) {
|
|
112
|
+
currentPercentage = percentage;
|
|
113
|
+
postProgress(received, contentLength);
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
postProgress(received, contentLength);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
sink.flush();
|
|
120
|
+
}
|
|
174
121
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
122
|
+
if (contentLength >= 0 && received != contentLength) {
|
|
123
|
+
throw new IOException("Unexpected eof while reading downloaded update");
|
|
124
|
+
}
|
|
125
|
+
postProgress(received, contentLength);
|
|
178
126
|
}
|
|
179
127
|
|
|
180
|
-
|
|
181
|
-
|
|
128
|
+
if (UpdateContext.DEBUG) {
|
|
129
|
+
Log.d(UpdateContext.TAG, "Download finished");
|
|
130
|
+
}
|
|
182
131
|
}
|
|
183
132
|
|
|
184
|
-
private byte[] readBytes(InputStream
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
133
|
+
private byte[] readBytes(InputStream input) throws IOException {
|
|
134
|
+
try (
|
|
135
|
+
InputStream in = input;
|
|
136
|
+
ByteArrayOutputStream out = new ByteArrayOutputStream()
|
|
137
|
+
) {
|
|
138
|
+
int count;
|
|
139
|
+
while ((count = in.read(buffer)) != -1) {
|
|
140
|
+
out.write(buffer, 0, count);
|
|
141
|
+
}
|
|
142
|
+
return out.toByteArray();
|
|
191
143
|
}
|
|
192
|
-
|
|
193
|
-
fout.close();
|
|
194
|
-
zis.close();
|
|
195
|
-
return fout.toByteArray();
|
|
196
144
|
}
|
|
197
145
|
|
|
198
146
|
private void appendManifestEntries(
|
|
@@ -225,20 +173,8 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
225
173
|
}
|
|
226
174
|
|
|
227
175
|
private void copyBundledAssetToFile(String assetName, File destination) throws IOException {
|
|
228
|
-
InputStream in = context.getAssets().open(assetName)
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
private void copyInputStreamToFile(InputStream in, File destination) throws IOException {
|
|
233
|
-
FileOutputStream fout = new FileOutputStream(destination);
|
|
234
|
-
try {
|
|
235
|
-
int count;
|
|
236
|
-
while ((count = in.read(buffer)) != -1) {
|
|
237
|
-
fout.write(buffer, 0, count);
|
|
238
|
-
}
|
|
239
|
-
} finally {
|
|
240
|
-
fout.close();
|
|
241
|
-
in.close();
|
|
176
|
+
try (InputStream in = context.getAssets().open(assetName)) {
|
|
177
|
+
UpdateFileUtils.copyInputStreamToFile(in, destination);
|
|
242
178
|
}
|
|
243
179
|
}
|
|
244
180
|
|
|
@@ -270,368 +206,85 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
270
206
|
return copyList;
|
|
271
207
|
}
|
|
272
208
|
|
|
273
|
-
private
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
param.unzipDirectory.mkdirs();
|
|
278
|
-
|
|
279
|
-
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
280
|
-
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
281
|
-
while (entries.hasMoreElements()) {
|
|
282
|
-
ZipEntry ze = entries.nextElement();
|
|
283
|
-
|
|
284
|
-
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
zipFile.close();
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (UpdateContext.DEBUG) {
|
|
291
|
-
Log.d("react-native-update", "Unzip finished");
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Pattern to strip -vN version qualifiers from resource directory paths
|
|
296
|
-
// e.g., "res/drawable-xxhdpi-v4/img.png" → "res/drawable-xxhdpi/img.png"
|
|
297
|
-
private static final Pattern VERSION_QUALIFIER_PATTERN =
|
|
298
|
-
Pattern.compile("-v\\d+(?=/)");
|
|
299
|
-
// AAB internal paths are prefixed with "base/" (e.g., "base/res/drawable-xxhdpi/img.png")
|
|
300
|
-
// which does not exist in standard APK layout
|
|
301
|
-
private static final String AAB_BASE_PREFIX = "base/";
|
|
302
|
-
|
|
303
|
-
private String normalizeResPath(String path) {
|
|
304
|
-
String result = path;
|
|
305
|
-
if (result.startsWith(AAB_BASE_PREFIX)) {
|
|
306
|
-
result = result.substring(AAB_BASE_PREFIX.length());
|
|
307
|
-
}
|
|
308
|
-
return VERSION_QUALIFIER_PATTERN.matcher(result).replaceAll("");
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
private static class ResolvedResourceSource {
|
|
312
|
-
final int resourceId;
|
|
313
|
-
final String assetPath;
|
|
314
|
-
|
|
315
|
-
ResolvedResourceSource(int resourceId, String assetPath) {
|
|
316
|
-
this.resourceId = resourceId;
|
|
317
|
-
this.assetPath = assetPath;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
private String extractResourceType(String directoryName) {
|
|
322
|
-
int qualifierIndex = directoryName.indexOf('-');
|
|
323
|
-
if (qualifierIndex == -1) {
|
|
324
|
-
return directoryName;
|
|
325
|
-
}
|
|
326
|
-
return directoryName.substring(0, qualifierIndex);
|
|
327
|
-
}
|
|
209
|
+
private PatchArchiveContents extractPatchArchive(File archiveFile, File unzipDirectory)
|
|
210
|
+
throws IOException, JSONException {
|
|
211
|
+
UpdateFileUtils.removeDirectory(unzipDirectory);
|
|
212
|
+
UpdateFileUtils.ensureDirectory(unzipDirectory);
|
|
328
213
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
214
|
+
PatchArchiveContents contents = new PatchArchiveContents();
|
|
215
|
+
try (SafeZipFile zipFile = new SafeZipFile(archiveFile)) {
|
|
216
|
+
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
217
|
+
while (entries.hasMoreElements()) {
|
|
218
|
+
ZipEntry entry = entries.nextElement();
|
|
219
|
+
String name = entry.getName();
|
|
220
|
+
contents.entryNames.add(name);
|
|
221
|
+
|
|
222
|
+
if (name.equals("__diff.json")) {
|
|
223
|
+
byte[] bytes = readBytes(zipFile.getInputStream(entry));
|
|
224
|
+
String json = new String(bytes, StandardCharsets.UTF_8);
|
|
225
|
+
JSONObject manifest = (JSONObject) new JSONTokener(json).nextValue();
|
|
226
|
+
appendManifestEntries(
|
|
227
|
+
manifest,
|
|
228
|
+
contents.copyFroms,
|
|
229
|
+
contents.copyTos,
|
|
230
|
+
contents.deletes
|
|
231
|
+
);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
339
234
|
|
|
340
|
-
|
|
341
|
-
String[] qualifiers = directoryName.split("-");
|
|
342
|
-
for (String qualifier : qualifiers) {
|
|
343
|
-
if ("ldpi".equals(qualifier)) {
|
|
344
|
-
return DisplayMetrics.DENSITY_LOW;
|
|
345
|
-
}
|
|
346
|
-
if ("mdpi".equals(qualifier)) {
|
|
347
|
-
return DisplayMetrics.DENSITY_MEDIUM;
|
|
348
|
-
}
|
|
349
|
-
if ("hdpi".equals(qualifier)) {
|
|
350
|
-
return DisplayMetrics.DENSITY_HIGH;
|
|
351
|
-
}
|
|
352
|
-
if ("xhdpi".equals(qualifier)) {
|
|
353
|
-
return DisplayMetrics.DENSITY_XHIGH;
|
|
354
|
-
}
|
|
355
|
-
if ("xxhdpi".equals(qualifier)) {
|
|
356
|
-
return DisplayMetrics.DENSITY_XXHIGH;
|
|
357
|
-
}
|
|
358
|
-
if ("xxxhdpi".equals(qualifier)) {
|
|
359
|
-
return DisplayMetrics.DENSITY_XXXHIGH;
|
|
360
|
-
}
|
|
361
|
-
if ("tvdpi".equals(qualifier)) {
|
|
362
|
-
return DisplayMetrics.DENSITY_TV;
|
|
235
|
+
zipFile.unzipToPath(entry, unzipDirectory);
|
|
363
236
|
}
|
|
364
237
|
}
|
|
365
|
-
return
|
|
238
|
+
return contents;
|
|
366
239
|
}
|
|
367
240
|
|
|
368
|
-
private
|
|
369
|
-
|
|
370
|
-
if (normalizedPath.startsWith("res/")) {
|
|
371
|
-
normalizedPath = normalizedPath.substring("res/".length());
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
int slash = normalizedPath.indexOf('/');
|
|
375
|
-
if (slash == -1 || slash == normalizedPath.length() - 1) {
|
|
376
|
-
return null;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
String directoryName = normalizedPath.substring(0, slash);
|
|
380
|
-
String fileName = normalizedPath.substring(slash + 1);
|
|
381
|
-
String resourceType = extractResourceType(directoryName);
|
|
382
|
-
String resourceName = extractResourceName(fileName);
|
|
383
|
-
if (resourceType == null || resourceType.isEmpty() || resourceName.isEmpty()) {
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
241
|
+
private void doFullPatch() throws IOException {
|
|
242
|
+
downloadFile();
|
|
386
243
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (resourceId == 0) {
|
|
390
|
-
return null;
|
|
391
|
-
}
|
|
244
|
+
UpdateFileUtils.removeDirectory(params.unzipDirectory);
|
|
245
|
+
UpdateFileUtils.ensureDirectory(params.unzipDirectory);
|
|
392
246
|
|
|
393
|
-
|
|
394
|
-
try {
|
|
395
|
-
Integer density = parseDensityQualifier(directoryName);
|
|
396
|
-
if (density != null) {
|
|
397
|
-
resources.getValueForDensity(resourceId, density, typedValue, true);
|
|
398
|
-
} else {
|
|
399
|
-
resources.getValue(resourceId, typedValue, true);
|
|
400
|
-
}
|
|
401
|
-
} catch (Resources.NotFoundException e) {
|
|
402
|
-
if (UpdateContext.DEBUG) {
|
|
403
|
-
Log.d("react-native-update", "Failed to resolve resource value for " + resourcePath + ": " + e.getMessage());
|
|
404
|
-
}
|
|
405
|
-
return null;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (typedValue.string == null) {
|
|
409
|
-
return null;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
String assetPath = typedValue.string.toString();
|
|
413
|
-
if (assetPath.startsWith("/")) {
|
|
414
|
-
assetPath = assetPath.substring(1);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (UpdateContext.DEBUG) {
|
|
418
|
-
Log.d("react-native-update", "Resolved resource path " + resourcePath + " -> " + assetPath);
|
|
419
|
-
}
|
|
420
|
-
return new ResolvedResourceSource(resourceId, assetPath);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
private InputStream openResolvedResourceStream(ResolvedResourceSource source) throws IOException {
|
|
424
|
-
try {
|
|
425
|
-
return context.getResources().openRawResource(source.resourceId);
|
|
426
|
-
} catch (Resources.NotFoundException e) {
|
|
427
|
-
throw new IOException("Unable to open resolved resource: " + source.assetPath, e);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
private void copyFromResource(HashMap<String, ArrayList<File> > resToCopy) throws IOException {
|
|
432
|
-
if (UpdateContext.DEBUG) {
|
|
433
|
-
Log.d("react-native-update", "copyFromResource called, resToCopy size: " + resToCopy.size());
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// 收集所有 APK 路径(包括基础 APK 和所有 split APK)
|
|
437
|
-
ArrayList<String> apkPaths = new ArrayList<>();
|
|
438
|
-
apkPaths.add(context.getPackageResourcePath());
|
|
439
|
-
|
|
440
|
-
// 获取所有 split APK 路径(用于资源分割的情况)
|
|
441
|
-
try {
|
|
442
|
-
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
|
|
443
|
-
context.getPackageName(), 0);
|
|
444
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && appInfo.splitSourceDirs != null) {
|
|
445
|
-
for (String splitPath : appInfo.splitSourceDirs) {
|
|
446
|
-
apkPaths.add(splitPath);
|
|
447
|
-
if (UpdateContext.DEBUG) {
|
|
448
|
-
Log.d("react-native-update", "Found split APK: " + splitPath);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
} catch (PackageManager.NameNotFoundException e) {
|
|
453
|
-
if (UpdateContext.DEBUG) {
|
|
454
|
-
Log.w("react-native-update", "Failed to get application info: " + e.getMessage());
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// 第一遍:从所有 APK 中收集所有可用的 zip 条目
|
|
459
|
-
HashMap<String, ZipEntry> availableEntries = new HashMap<>();
|
|
460
|
-
HashMap<String, SafeZipFile> zipFileMap = new HashMap<>(); // 保存每个路径对应的 ZipFile
|
|
461
|
-
HashMap<String, SafeZipFile> entryToZipFileMap = new HashMap<>(); // 保存每个条目对应的 ZipFile
|
|
462
|
-
|
|
463
|
-
for (String apkPath : apkPaths) {
|
|
464
|
-
SafeZipFile zipFile = new SafeZipFile(new File(apkPath));
|
|
465
|
-
zipFileMap.put(apkPath, zipFile);
|
|
247
|
+
try (SafeZipFile zipFile = new SafeZipFile(params.targetFile)) {
|
|
466
248
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
467
249
|
while (entries.hasMoreElements()) {
|
|
468
|
-
|
|
469
|
-
String entryName = ze.getName();
|
|
470
|
-
// 如果条目已存在,保留第一个(基础 APK 优先)
|
|
471
|
-
if (!availableEntries.containsKey(entryName)) {
|
|
472
|
-
availableEntries.put(entryName, ze);
|
|
473
|
-
entryToZipFileMap.put(entryName, zipFile);
|
|
474
|
-
}
|
|
250
|
+
zipFile.unzipToPath(entries.nextElement(), params.unzipDirectory);
|
|
475
251
|
}
|
|
476
252
|
}
|
|
477
|
-
|
|
478
|
-
// 构建规范化路径映射,用于 APK ↔ AAB 版本限定符无关匹配
|
|
479
|
-
// 例如 "res/drawable-xxhdpi-v4/img.png" → "res/drawable-xxhdpi/img.png"
|
|
480
|
-
HashMap<String, String> normalizedEntryMap = new HashMap<>();
|
|
481
|
-
for (String entryName : availableEntries.keySet()) {
|
|
482
|
-
String normalized = normalizeResPath(entryName);
|
|
483
|
-
normalizedEntryMap.putIfAbsent(normalized, entryName);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// 使用基础 APK 的 ZipFile 作为主要操作对象
|
|
487
|
-
SafeZipFile zipFile = zipFileMap.get(context.getPackageResourcePath());
|
|
488
|
-
|
|
489
|
-
// 处理所有需要复制的文件
|
|
490
|
-
HashMap<String, ArrayList<File>> remainingFiles = new HashMap<>(resToCopy);
|
|
491
|
-
|
|
492
|
-
for (String fromPath : new ArrayList<>(remainingFiles.keySet())) {
|
|
493
|
-
if (UpdateContext.DEBUG) {
|
|
494
|
-
Log.d("react-native-update", "Processing fromPath: " + fromPath);
|
|
495
|
-
}
|
|
496
|
-
ArrayList<File> targets = remainingFiles.get(fromPath);
|
|
497
|
-
if (targets == null || targets.isEmpty()) {
|
|
498
|
-
continue;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
ZipEntry ze = availableEntries.get(fromPath);
|
|
502
|
-
String actualSourcePath = fromPath;
|
|
503
|
-
ResolvedResourceSource resolvedResource = null;
|
|
504
|
-
|
|
505
|
-
// 如果精确匹配找不到,尝试版本限定符无关匹配(APK ↔ AAB 兼容)
|
|
506
|
-
// 例如 __diff.json 中的 "res/drawable-xxhdpi-v4/img.png" 匹配设备上的 "res/drawable-xxhdpi/img.png"
|
|
507
|
-
if (ze == null) {
|
|
508
|
-
String normalizedFrom = normalizeResPath(fromPath);
|
|
509
|
-
String actualEntry = normalizedEntryMap.get(normalizedFrom);
|
|
510
|
-
if (actualEntry != null) {
|
|
511
|
-
ze = availableEntries.get(actualEntry);
|
|
512
|
-
actualSourcePath = actualEntry;
|
|
513
|
-
if (UpdateContext.DEBUG) {
|
|
514
|
-
Log.d("react-native-update", "Normalized match: " + fromPath + " -> " + actualEntry);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
253
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (ze == null) {
|
|
522
|
-
resolvedResource = resolveBundledResource(fromPath);
|
|
523
|
-
if (resolvedResource != null) {
|
|
524
|
-
actualSourcePath = resolvedResource.assetPath;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
if (ze != null || resolvedResource != null) {
|
|
529
|
-
File lastTarget = null;
|
|
530
|
-
for (File target: targets) {
|
|
531
|
-
if (UpdateContext.DEBUG) {
|
|
532
|
-
Log.d("react-native-update", "Copying from resource " + actualSourcePath + " to " + target);
|
|
533
|
-
}
|
|
534
|
-
try {
|
|
535
|
-
// 确保目标文件的父目录存在
|
|
536
|
-
File parentDir = target.getParentFile();
|
|
537
|
-
if (parentDir != null && !parentDir.exists()) {
|
|
538
|
-
parentDir.mkdirs();
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
if (lastTarget != null) {
|
|
542
|
-
copyFile(lastTarget, target);
|
|
543
|
-
} else {
|
|
544
|
-
if (ze != null) {
|
|
545
|
-
// 从保存的映射中获取包含该条目的 ZipFile
|
|
546
|
-
SafeZipFile sourceZipFile = entryToZipFileMap.get(actualSourcePath);
|
|
547
|
-
if (sourceZipFile == null) {
|
|
548
|
-
sourceZipFile = zipFile; // 回退到基础 APK
|
|
549
|
-
}
|
|
550
|
-
sourceZipFile.unzipToFile(ze, target);
|
|
551
|
-
} else {
|
|
552
|
-
InputStream in = openResolvedResourceStream(resolvedResource);
|
|
553
|
-
copyInputStreamToFile(in, target);
|
|
554
|
-
}
|
|
555
|
-
lastTarget = target;
|
|
556
|
-
}
|
|
557
|
-
} catch (IOException e) {
|
|
558
|
-
if (UpdateContext.DEBUG) {
|
|
559
|
-
Log.w("react-native-update", "Failed to copy resource " + actualSourcePath + " to " + target + ": " + e.getMessage());
|
|
560
|
-
}
|
|
561
|
-
// 继续处理下一个目标
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
remainingFiles.remove(fromPath);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// 处理剩余的文件(如果还有的话)
|
|
569
|
-
if (!remainingFiles.isEmpty() && UpdateContext.DEBUG) {
|
|
570
|
-
for (String fromPath : remainingFiles.keySet()) {
|
|
571
|
-
Log.w("react-native-update", "Resource not found and no fallback available: " + fromPath);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// 关闭所有 ZipFile
|
|
576
|
-
for (SafeZipFile zf : zipFileMap.values()) {
|
|
577
|
-
zf.close();
|
|
254
|
+
if (UpdateContext.DEBUG) {
|
|
255
|
+
Log.d(UpdateContext.TAG, "Unzip finished");
|
|
578
256
|
}
|
|
579
257
|
}
|
|
580
258
|
|
|
581
|
-
private void doPatchFromApk(
|
|
582
|
-
downloadFile(
|
|
583
|
-
|
|
584
|
-
removeDirectory(param.unzipDirectory);
|
|
585
|
-
param.unzipDirectory.mkdirs();
|
|
586
|
-
ArrayList<String> entryNames = new ArrayList<String>();
|
|
587
|
-
ArrayList<String> copyFroms = new ArrayList<String>();
|
|
588
|
-
ArrayList<String> copyTos = new ArrayList<String>();
|
|
589
|
-
ArrayList<String> deletes = new ArrayList<String>();
|
|
590
|
-
|
|
591
|
-
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
592
|
-
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
593
|
-
while (entries.hasMoreElements()) {
|
|
594
|
-
ZipEntry ze = entries.nextElement();
|
|
595
|
-
String fn = ze.getName();
|
|
596
|
-
entryNames.add(fn);
|
|
597
|
-
|
|
598
|
-
if (fn.equals("__diff.json")) {
|
|
599
|
-
// copy files from assets
|
|
600
|
-
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
|
601
|
-
String json = new String(bytes, "UTF-8");
|
|
602
|
-
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
|
603
|
-
appendManifestEntries(obj, copyFroms, copyTos, deletes);
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
zipFile.close();
|
|
259
|
+
private void doPatchFromApk() throws IOException, JSONException {
|
|
260
|
+
downloadFile();
|
|
261
|
+
PatchArchiveContents contents = extractPatchArchive(params.targetFile, params.unzipDirectory);
|
|
610
262
|
|
|
611
263
|
buildArchivePatchPlan(
|
|
612
264
|
DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK,
|
|
613
|
-
entryNames.toArray(new String[0]),
|
|
614
|
-
copyFroms.toArray(new String[0]),
|
|
615
|
-
copyTos.toArray(new String[0]),
|
|
616
|
-
deletes.toArray(new String[0])
|
|
265
|
+
contents.entryNames.toArray(new String[0]),
|
|
266
|
+
contents.copyFroms.toArray(new String[0]),
|
|
267
|
+
contents.copyTos.toArray(new String[0]),
|
|
268
|
+
contents.deletes.toArray(new String[0])
|
|
617
269
|
);
|
|
270
|
+
|
|
618
271
|
HashMap<String, ArrayList<File>> copyList = buildCopyList(
|
|
619
|
-
|
|
272
|
+
params.unzipDirectory,
|
|
620
273
|
buildCopyGroups(
|
|
621
|
-
copyFroms.toArray(new String[0]),
|
|
622
|
-
copyTos.toArray(new String[0])
|
|
274
|
+
contents.copyFroms.toArray(new String[0]),
|
|
275
|
+
contents.copyTos.toArray(new String[0])
|
|
623
276
|
)
|
|
624
277
|
);
|
|
625
278
|
|
|
626
|
-
File originBundleFile = new File(
|
|
279
|
+
File originBundleFile = new File(params.unzipDirectory, ".origin.bundle");
|
|
627
280
|
copyBundledAssetToFile("index.android.bundle", originBundleFile);
|
|
628
281
|
try {
|
|
629
282
|
applyPatchFromFileSource(
|
|
630
|
-
|
|
631
|
-
|
|
283
|
+
params.unzipDirectory.getAbsolutePath(),
|
|
284
|
+
params.unzipDirectory.getAbsolutePath(),
|
|
632
285
|
originBundleFile.getAbsolutePath(),
|
|
633
|
-
new File(
|
|
634
|
-
new File(
|
|
286
|
+
new File(params.unzipDirectory, "index.bundlejs.patch").getAbsolutePath(),
|
|
287
|
+
new File(params.unzipDirectory, "index.bundlejs").getAbsolutePath(),
|
|
635
288
|
"",
|
|
636
289
|
false,
|
|
637
290
|
new String[0],
|
|
@@ -643,144 +296,158 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
643
296
|
}
|
|
644
297
|
|
|
645
298
|
if (UpdateContext.DEBUG) {
|
|
646
|
-
Log.d(
|
|
299
|
+
Log.d(UpdateContext.TAG, "copyList size: " + copyList.size());
|
|
647
300
|
for (String from : copyList.keySet()) {
|
|
648
|
-
Log.d(
|
|
301
|
+
Log.d(
|
|
302
|
+
UpdateContext.TAG,
|
|
303
|
+
"copyList entry: " + from + " -> " + copyList.get(from).size() + " targets"
|
|
304
|
+
);
|
|
649
305
|
}
|
|
650
306
|
}
|
|
651
307
|
|
|
652
|
-
copyFromResource(copyList);
|
|
308
|
+
bundledResourceCopier.copyFromResource(copyList);
|
|
653
309
|
|
|
654
310
|
if (UpdateContext.DEBUG) {
|
|
655
|
-
Log.d(
|
|
311
|
+
Log.d(UpdateContext.TAG, "Unzip finished");
|
|
656
312
|
}
|
|
657
|
-
|
|
658
313
|
}
|
|
659
314
|
|
|
660
|
-
private void doPatchFromPpk(
|
|
661
|
-
downloadFile(
|
|
662
|
-
|
|
663
|
-
removeDirectory(param.unzipDirectory);
|
|
664
|
-
param.unzipDirectory.mkdirs();
|
|
665
|
-
|
|
666
|
-
ArrayList<String> entryNames = new ArrayList<String>();
|
|
667
|
-
ArrayList<String> copyFroms = new ArrayList<String>();
|
|
668
|
-
ArrayList<String> copyTos = new ArrayList<String>();
|
|
669
|
-
ArrayList<String> deletes = new ArrayList<String>();
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
673
|
-
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
674
|
-
while (entries.hasMoreElements()) {
|
|
675
|
-
ZipEntry ze = entries.nextElement();
|
|
676
|
-
String fn = ze.getName();
|
|
677
|
-
entryNames.add(fn);
|
|
678
|
-
|
|
679
|
-
if (fn.equals("__diff.json")) {
|
|
680
|
-
// copy files from assets
|
|
681
|
-
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
|
682
|
-
String json = new String(bytes, "UTF-8");
|
|
683
|
-
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
|
684
|
-
appendManifestEntries(obj, copyFroms, copyTos, deletes);
|
|
685
|
-
continue;
|
|
686
|
-
}
|
|
687
|
-
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
zipFile.close();
|
|
315
|
+
private void doPatchFromPpk() throws IOException, JSONException {
|
|
316
|
+
downloadFile();
|
|
317
|
+
PatchArchiveContents contents = extractPatchArchive(params.targetFile, params.unzipDirectory);
|
|
691
318
|
|
|
692
319
|
ArchivePatchPlanResult plan = buildArchivePatchPlan(
|
|
693
320
|
DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK,
|
|
694
|
-
entryNames.toArray(new String[0]),
|
|
695
|
-
copyFroms.toArray(new String[0]),
|
|
696
|
-
copyTos.toArray(new String[0]),
|
|
697
|
-
deletes.toArray(new String[0])
|
|
321
|
+
contents.entryNames.toArray(new String[0]),
|
|
322
|
+
contents.copyFroms.toArray(new String[0]),
|
|
323
|
+
contents.copyTos.toArray(new String[0]),
|
|
324
|
+
contents.deletes.toArray(new String[0])
|
|
698
325
|
);
|
|
699
326
|
|
|
700
327
|
applyPatchFromFileSource(
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
new File(
|
|
704
|
-
new File(
|
|
705
|
-
new File(
|
|
328
|
+
params.originDirectory.getAbsolutePath(),
|
|
329
|
+
params.unzipDirectory.getAbsolutePath(),
|
|
330
|
+
new File(params.originDirectory, "index.bundlejs").getAbsolutePath(),
|
|
331
|
+
new File(params.unzipDirectory, "index.bundlejs.patch").getAbsolutePath(),
|
|
332
|
+
new File(params.unzipDirectory, "index.bundlejs").getAbsolutePath(),
|
|
706
333
|
plan.mergeSourceSubdir,
|
|
707
334
|
plan.enableMerge,
|
|
708
|
-
copyFroms.toArray(new String[0]),
|
|
709
|
-
copyTos.toArray(new String[0]),
|
|
710
|
-
deletes.toArray(new String[0])
|
|
335
|
+
contents.copyFroms.toArray(new String[0]),
|
|
336
|
+
contents.copyTos.toArray(new String[0]),
|
|
337
|
+
contents.deletes.toArray(new String[0])
|
|
711
338
|
);
|
|
712
339
|
|
|
713
340
|
if (UpdateContext.DEBUG) {
|
|
714
|
-
Log.d(
|
|
341
|
+
Log.d(UpdateContext.TAG, "Unzip finished");
|
|
715
342
|
}
|
|
716
343
|
}
|
|
717
|
-
|
|
344
|
+
|
|
345
|
+
private void doCleanUp() {
|
|
718
346
|
if (UpdateContext.DEBUG) {
|
|
719
|
-
Log.d(
|
|
347
|
+
Log.d(UpdateContext.TAG, "Start cleaning up");
|
|
720
348
|
}
|
|
721
349
|
cleanupOldEntries(
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
350
|
+
params.unzipDirectory.getAbsolutePath(),
|
|
351
|
+
params.hash,
|
|
352
|
+
params.originHash,
|
|
725
353
|
7
|
|
726
354
|
);
|
|
727
355
|
}
|
|
728
356
|
|
|
357
|
+
private void cleanUpAfterFailure(int taskType) {
|
|
358
|
+
switch (taskType) {
|
|
359
|
+
case DownloadTaskParams.TASK_TYPE_PATCH_FULL:
|
|
360
|
+
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK:
|
|
361
|
+
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK:
|
|
362
|
+
try {
|
|
363
|
+
UpdateFileUtils.removeDirectory(params.unzipDirectory);
|
|
364
|
+
} catch (IOException ioException) {
|
|
365
|
+
Log.e(UpdateContext.TAG, "Failed to clean patched directory", ioException);
|
|
366
|
+
}
|
|
367
|
+
break;
|
|
368
|
+
case DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD:
|
|
369
|
+
if (
|
|
370
|
+
params.targetFile.exists()
|
|
371
|
+
&& !params.targetFile.delete()
|
|
372
|
+
&& UpdateContext.DEBUG
|
|
373
|
+
) {
|
|
374
|
+
Log.w(UpdateContext.TAG, "Failed to clean partial download " + params.targetFile);
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
default:
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
729
382
|
@Override
|
|
730
|
-
|
|
731
|
-
int taskType = params
|
|
383
|
+
public void run() {
|
|
384
|
+
int taskType = params.type;
|
|
732
385
|
try {
|
|
733
386
|
switch (taskType) {
|
|
734
387
|
case DownloadTaskParams.TASK_TYPE_PATCH_FULL:
|
|
735
|
-
doFullPatch(
|
|
388
|
+
doFullPatch();
|
|
736
389
|
break;
|
|
737
390
|
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK:
|
|
738
|
-
doPatchFromApk(
|
|
391
|
+
doPatchFromApk();
|
|
739
392
|
break;
|
|
740
393
|
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK:
|
|
741
|
-
doPatchFromPpk(
|
|
394
|
+
doPatchFromPpk();
|
|
742
395
|
break;
|
|
743
396
|
case DownloadTaskParams.TASK_TYPE_CLEANUP:
|
|
744
|
-
doCleanUp(
|
|
397
|
+
doCleanUp();
|
|
745
398
|
break;
|
|
746
399
|
case DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD:
|
|
747
|
-
downloadFile(
|
|
400
|
+
downloadFile();
|
|
748
401
|
break;
|
|
749
402
|
default:
|
|
750
403
|
break;
|
|
751
404
|
}
|
|
752
|
-
|
|
753
|
-
|
|
405
|
+
|
|
406
|
+
if (params.listener != null) {
|
|
407
|
+
params.listener.onDownloadCompleted(params);
|
|
754
408
|
}
|
|
755
|
-
} catch (Throwable
|
|
409
|
+
} catch (Throwable error) {
|
|
756
410
|
if (UpdateContext.DEBUG) {
|
|
757
|
-
e.
|
|
411
|
+
Log.e(UpdateContext.TAG, "download task failed", error);
|
|
758
412
|
}
|
|
759
|
-
|
|
760
|
-
case DownloadTaskParams.TASK_TYPE_PATCH_FULL:
|
|
761
|
-
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK:
|
|
762
|
-
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK:
|
|
763
|
-
try {
|
|
764
|
-
removeDirectory(params[0].unzipDirectory);
|
|
765
|
-
} catch (IOException ioException) {
|
|
766
|
-
ioException.printStackTrace();
|
|
767
|
-
}
|
|
768
|
-
break;
|
|
769
|
-
case DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD:
|
|
770
|
-
// if (targetToClean.exists()) {
|
|
771
|
-
params[0].targetFile.delete();
|
|
772
|
-
// }
|
|
773
|
-
break;
|
|
774
|
-
default:
|
|
775
|
-
break;
|
|
776
|
-
}
|
|
777
|
-
Log.e("react-native-update", "download task failed", e);
|
|
413
|
+
cleanUpAfterFailure(taskType);
|
|
778
414
|
|
|
779
|
-
if (params
|
|
780
|
-
params
|
|
415
|
+
if (params.listener != null) {
|
|
416
|
+
params.listener.onDownloadFailed(error);
|
|
781
417
|
}
|
|
782
418
|
}
|
|
783
|
-
return null;
|
|
784
419
|
}
|
|
785
420
|
|
|
421
|
+
private static native void applyPatchFromFileSource(
|
|
422
|
+
String sourceRoot,
|
|
423
|
+
String targetRoot,
|
|
424
|
+
String originBundlePath,
|
|
425
|
+
String bundlePatchPath,
|
|
426
|
+
String bundleOutputPath,
|
|
427
|
+
String mergeSourceSubdir,
|
|
428
|
+
boolean enableMerge,
|
|
429
|
+
String[] copyFroms,
|
|
430
|
+
String[] copyTos,
|
|
431
|
+
String[] deletes
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
private static native void cleanupOldEntries(
|
|
435
|
+
String rootDir,
|
|
436
|
+
String keepCurrent,
|
|
437
|
+
String keepPrevious,
|
|
438
|
+
int maxAgeDays
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
private static native ArchivePatchPlanResult buildArchivePatchPlan(
|
|
442
|
+
int patchType,
|
|
443
|
+
String[] entryNames,
|
|
444
|
+
String[] copyFroms,
|
|
445
|
+
String[] copyTos,
|
|
446
|
+
String[] deletes
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
private static native CopyGroupResult[] buildCopyGroups(
|
|
450
|
+
String[] copyFroms,
|
|
451
|
+
String[] copyTos
|
|
452
|
+
);
|
|
786
453
|
}
|