@bravemobile/react-native-code-push 13.1.0-beta.0 → 13.1.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.
- package/README.md +3 -1
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +8 -4
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java +9 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java +7 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressEventDispatcher.java +25 -4
- package/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerBinaryPatchTest.java +4 -0
- package/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerDownloadTest.java +40 -0
- package/android/app/src/test/java/com/microsoft/codepush/react/DownloadProgressEventDispatcherTest.java +80 -0
- package/ios/CodePush/CodePush.mm +8 -0
- package/ios/CodePush/CodePushDownloadHandler.m +6 -0
- package/package.json +1 -1
- package/typings/react-native-code-push.d.ts +3 -1
package/README.md
CHANGED
|
@@ -304,8 +304,10 @@ Please refer to the [CodePushOptions](https://github.com/Soomgo-Mobile/react-nat
|
|
|
304
304
|
A `"fallback"` is not a failed update: the update is downloaded in full instead and installed as usual, so the result
|
|
305
305
|
is there to be observed and nothing more. The library neither stores it nor sends it anywhere - an app that wants it in
|
|
306
306
|
its telemetry sends it itself. A callback that throws never fails the update - the error is only logged to the console.
|
|
307
|
+
A fallback also shows in `downloadProgressCallback`: the full download reports a second progress stream that counts
|
|
308
|
+
`receivedBytes` from zero again, against its own, larger `totalBytes`.
|
|
307
309
|
|
|
308
|
-
Register
|
|
310
|
+
Register `onBinaryPatchResult` on `CodePush({ ... })` like the callbacks above and it covers every sync, whatever the `checkFrequency` is
|
|
309
311
|
and including the `CodePush.sync()` calls you make yourself.
|
|
310
312
|
|
|
311
313
|
```typescript
|
|
@@ -338,7 +338,6 @@ public class CodePushNativeModule extends NativeCodePushSpec {
|
|
|
338
338
|
JSONObject mutableUpdatePackage = CodePushUtils.convertReadableToJsonObject(updatePackage);
|
|
339
339
|
JSONObject binaryPatchResult = mUpdateManager.downloadPackage(mutableUpdatePackage, mCodePush.getAssetsBundleFileName(), new DownloadProgressCallback() {
|
|
340
340
|
private volatile boolean hasScheduledNextFrame = false;
|
|
341
|
-
private volatile DownloadProgress latestDownloadProgress = null;
|
|
342
341
|
private final DownloadProgressEventDispatcher progressEventDispatcher = new DownloadProgressEventDispatcher(
|
|
343
342
|
new DownloadProgressEventDispatcher.EventEmitter() {
|
|
344
343
|
@Override
|
|
@@ -347,16 +346,21 @@ public class CodePushNativeModule extends NativeCodePushSpec {
|
|
|
347
346
|
}
|
|
348
347
|
});
|
|
349
348
|
|
|
349
|
+
@Override
|
|
350
|
+
public void onDownloadStart() {
|
|
351
|
+
progressEventDispatcher.reset();
|
|
352
|
+
}
|
|
353
|
+
|
|
350
354
|
@Override
|
|
351
355
|
public void call(DownloadProgress downloadProgress) {
|
|
352
356
|
if (!notifyProgress || downloadProgress == null) {
|
|
353
357
|
return;
|
|
354
358
|
}
|
|
355
359
|
|
|
356
|
-
|
|
360
|
+
progressEventDispatcher.record(downloadProgress);
|
|
357
361
|
// If the download is completed, synchronously send the last event.
|
|
358
362
|
if (downloadProgress.isCompleted()) {
|
|
359
|
-
progressEventDispatcher.
|
|
363
|
+
progressEventDispatcher.dispatchLatest();
|
|
360
364
|
return;
|
|
361
365
|
}
|
|
362
366
|
|
|
@@ -372,7 +376,7 @@ public class CodePushNativeModule extends NativeCodePushSpec {
|
|
|
372
376
|
@Override
|
|
373
377
|
public void doFrame(long frameTimeNanos) {
|
|
374
378
|
try {
|
|
375
|
-
progressEventDispatcher.
|
|
379
|
+
progressEventDispatcher.dispatchLatest();
|
|
376
380
|
} finally {
|
|
377
381
|
hasScheduledNextFrame = false;
|
|
378
382
|
}
|
|
@@ -275,9 +275,18 @@ public class CodePushUpdateManager {
|
|
|
275
275
|
connection.setRequestProperty("Accept-Encoding", "identity");
|
|
276
276
|
bin = new BufferedInputStream(connection.getInputStream());
|
|
277
277
|
|
|
278
|
+
// Announced only once the response is flowing, so a connection that fails to
|
|
279
|
+
// open never announces an empty stream.
|
|
280
|
+
progressCallback.onDownloadStart();
|
|
278
281
|
long totalBytes = connection.getContentLength();
|
|
279
282
|
long receivedBytes = 0;
|
|
280
283
|
|
|
284
|
+
if (totalBytes > 0) {
|
|
285
|
+
// The zero-received event hands the listener this download's total up front,
|
|
286
|
+
// so a fallback download shows as restarting rather than running backwards.
|
|
287
|
+
progressCallback.call(new DownloadProgress(totalBytes, 0));
|
|
288
|
+
}
|
|
289
|
+
|
|
281
290
|
File downloadFolder = new File(getCodePushPath());
|
|
282
291
|
downloadFolder.mkdirs();
|
|
283
292
|
downloadFile = new File(downloadFolder, CodePushConstants.DOWNLOAD_FILE_NAME);
|
package/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
package com.microsoft.codepush.react;
|
|
2
2
|
|
|
3
3
|
interface DownloadProgressCallback {
|
|
4
|
+
/**
|
|
5
|
+
* A download is starting its own progress stream: received bytes count from zero again,
|
|
6
|
+
* against this download's own total. A binary patch fallback makes this happen twice
|
|
7
|
+
* within one downloaded update.
|
|
8
|
+
*/
|
|
9
|
+
void onDownloadStart();
|
|
10
|
+
|
|
4
11
|
void call(DownloadProgress downloadProgress);
|
|
5
12
|
}
|
package/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressEventDispatcher.java
CHANGED
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
package com.microsoft.codepush.react;
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Serializes progress events from the download thread and the UI frame callback into one
|
|
5
|
+
* monotonic stream per download: whatever order the two threads dispatch in, the JS side
|
|
6
|
+
* never sees the same download run backwards. The latest progress lives here rather than
|
|
7
|
+
* with the caller so that reading it and dispatching it happen under one lock.
|
|
8
|
+
*/
|
|
3
9
|
class DownloadProgressEventDispatcher {
|
|
4
10
|
interface EventEmitter {
|
|
5
11
|
void emit(DownloadProgress downloadProgress);
|
|
6
12
|
}
|
|
7
13
|
|
|
8
14
|
private final EventEmitter mEventEmitter;
|
|
15
|
+
private DownloadProgress mLatestDownloadProgress = null;
|
|
9
16
|
private long mLastDispatchedBytes = -1;
|
|
10
17
|
|
|
11
18
|
DownloadProgressEventDispatcher(EventEmitter eventEmitter) {
|
|
12
19
|
mEventEmitter = eventEmitter;
|
|
13
20
|
}
|
|
14
21
|
|
|
15
|
-
synchronized void
|
|
16
|
-
|
|
22
|
+
synchronized void record(DownloadProgress downloadProgress) {
|
|
23
|
+
mLatestDownloadProgress = downloadProgress;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
synchronized void dispatchLatest() {
|
|
27
|
+
if (mLatestDownloadProgress == null || mLatestDownloadProgress.getReceivedBytes() <= mLastDispatchedBytes) {
|
|
17
28
|
return;
|
|
18
29
|
}
|
|
19
30
|
|
|
20
|
-
mEventEmitter.emit(
|
|
21
|
-
mLastDispatchedBytes =
|
|
31
|
+
mEventEmitter.emit(mLatestDownloadProgress);
|
|
32
|
+
mLastDispatchedBytes = mLatestDownloadProgress.getReceivedBytes();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Forgets the download dispatched so far. The next download counts its bytes from zero,
|
|
37
|
+
* and without the reset the monotonic guard would swallow its events as the previous
|
|
38
|
+
* download running backwards.
|
|
39
|
+
*/
|
|
40
|
+
synchronized void reset() {
|
|
41
|
+
mLatestDownloadProgress = null;
|
|
42
|
+
mLastDispatchedBytes = -1;
|
|
22
43
|
}
|
|
23
44
|
}
|
|
@@ -146,6 +146,10 @@ public class CodePushUpdateManagerBinaryPatchTest {
|
|
|
146
146
|
|
|
147
147
|
private static DownloadProgressCallback ignoreProgress() {
|
|
148
148
|
return new DownloadProgressCallback() {
|
|
149
|
+
@Override
|
|
150
|
+
public void onDownloadStart() {
|
|
151
|
+
}
|
|
152
|
+
|
|
149
153
|
@Override
|
|
150
154
|
public void call(DownloadProgress downloadProgress) {
|
|
151
155
|
}
|
|
@@ -161,6 +161,42 @@ public class CodePushUpdateManagerDownloadTest {
|
|
|
161
161
|
assertFallbackResult(patchResult, BinaryPatchResult.REASON_PACKAGE_VERIFICATION_FAILED);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
@Test
|
|
165
|
+
public void announcesEachDownloadOfAFallbackAsItsOwnProgressStream() throws IOException {
|
|
166
|
+
byte[] fullArchive = zipOf(fullArchiveContents());
|
|
167
|
+
String patchUrl = serve("/patch.zip", ERROR_PAGE);
|
|
168
|
+
String fullUrl = serve("/full.zip", fullArchive);
|
|
169
|
+
final List<List<Long>> streams = new ArrayList<>();
|
|
170
|
+
final List<Long> completedBytes = new ArrayList<>();
|
|
171
|
+
|
|
172
|
+
updateManager(applierWriting(TARGET_BUNDLE)).downloadPackage(
|
|
173
|
+
updatePackage(fullUrl, patchUrl), BUNDLE_FILE_NAME, new DownloadProgressCallback() {
|
|
174
|
+
@Override
|
|
175
|
+
public void onDownloadStart() {
|
|
176
|
+
streams.add(new ArrayList<Long>());
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@Override
|
|
180
|
+
public void call(DownloadProgress downloadProgress) {
|
|
181
|
+
streams.get(streams.size() - 1).add(downloadProgress.getReceivedBytes());
|
|
182
|
+
if (downloadProgress.isCompleted()) {
|
|
183
|
+
completedBytes.add(downloadProgress.getReceivedBytes());
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
assertEquals("each download announces a stream of its own", 2, streams.size());
|
|
189
|
+
for (List<Long> stream : streams) {
|
|
190
|
+
assertEquals("a stream opens by putting its total on the table at zero received",
|
|
191
|
+
Long.valueOf(0), stream.get(0));
|
|
192
|
+
for (int i = 1; i < stream.size(); i++) {
|
|
193
|
+
assertTrue("a stream never runs backwards", stream.get(i) >= stream.get(i - 1));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
assertEquals("both downloads complete at the size of the body they served",
|
|
197
|
+
Arrays.asList((long) ERROR_PAGE.length, (long) fullArchive.length), completedBytes);
|
|
198
|
+
}
|
|
199
|
+
|
|
164
200
|
/** The result of a download the update had to be downloaded in full for. */
|
|
165
201
|
private static void assertFallbackResult(JSONObject patchResult, String expectedReason) {
|
|
166
202
|
assertEquals("fallback", patchResult.optString("status", null));
|
|
@@ -393,6 +429,10 @@ public class CodePushUpdateManagerDownloadTest {
|
|
|
393
429
|
|
|
394
430
|
private static DownloadProgressCallback ignoreProgress() {
|
|
395
431
|
return new DownloadProgressCallback() {
|
|
432
|
+
@Override
|
|
433
|
+
public void onDownloadStart() {
|
|
434
|
+
}
|
|
435
|
+
|
|
396
436
|
@Override
|
|
397
437
|
public void call(DownloadProgress downloadProgress) {
|
|
398
438
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
package com.microsoft.codepush.react;
|
|
2
|
+
|
|
3
|
+
import static org.junit.Assert.assertEquals;
|
|
4
|
+
|
|
5
|
+
import org.junit.Test;
|
|
6
|
+
|
|
7
|
+
import java.util.ArrayList;
|
|
8
|
+
import java.util.Arrays;
|
|
9
|
+
import java.util.Collections;
|
|
10
|
+
import java.util.List;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The dispatcher is the seam between the download thread and the UI frame callback. These
|
|
14
|
+
* pin the property the two threads rely on: per download, the JS side sees one monotonic
|
|
15
|
+
* stream, and after a reset the next download's stream starts fresh instead of being
|
|
16
|
+
* mistaken for the previous one running backwards.
|
|
17
|
+
*/
|
|
18
|
+
public class DownloadProgressEventDispatcherTest {
|
|
19
|
+
|
|
20
|
+
private final List<Long> mEmittedBytes = new ArrayList<>();
|
|
21
|
+
private final DownloadProgressEventDispatcher mDispatcher = new DownloadProgressEventDispatcher(
|
|
22
|
+
new DownloadProgressEventDispatcher.EventEmitter() {
|
|
23
|
+
@Override
|
|
24
|
+
public void emit(DownloadProgress downloadProgress) {
|
|
25
|
+
mEmittedBytes.add(downloadProgress.getReceivedBytes());
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
@Test
|
|
30
|
+
public void aFrameCallbackWithNothingRecordedEmitsNothing() {
|
|
31
|
+
mDispatcher.dispatchLatest();
|
|
32
|
+
|
|
33
|
+
assertEquals(Collections.emptyList(), mEmittedBytes);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Test
|
|
37
|
+
public void emitsOnlyTheLatestRecordedProgress() {
|
|
38
|
+
mDispatcher.record(new DownloadProgress(100, 60));
|
|
39
|
+
mDispatcher.record(new DownloadProgress(100, 80));
|
|
40
|
+
|
|
41
|
+
mDispatcher.dispatchLatest();
|
|
42
|
+
|
|
43
|
+
assertEquals(Arrays.asList(80L), mEmittedBytes);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Test
|
|
47
|
+
public void aFrameCallbackFiringAfterTheCompletionEventEmitsNothingMore() {
|
|
48
|
+
mDispatcher.record(new DownloadProgress(100, 90));
|
|
49
|
+
mDispatcher.dispatchLatest();
|
|
50
|
+
mDispatcher.record(new DownloadProgress(100, 100));
|
|
51
|
+
mDispatcher.dispatchLatest();
|
|
52
|
+
|
|
53
|
+
// The frame callback that was already scheduled when the download completed.
|
|
54
|
+
mDispatcher.dispatchLatest();
|
|
55
|
+
|
|
56
|
+
assertEquals(Arrays.asList(90L, 100L), mEmittedBytes);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Test
|
|
60
|
+
public void aResetLetsTheNextDownloadCountFromZeroAgain() {
|
|
61
|
+
mDispatcher.record(new DownloadProgress(100, 100));
|
|
62
|
+
mDispatcher.dispatchLatest();
|
|
63
|
+
|
|
64
|
+
mDispatcher.reset();
|
|
65
|
+
mDispatcher.record(new DownloadProgress(5000, 10));
|
|
66
|
+
mDispatcher.dispatchLatest();
|
|
67
|
+
|
|
68
|
+
assertEquals(Arrays.asList(100L, 10L), mEmittedBytes);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Test
|
|
72
|
+
public void progressRecordedBeforeAResetIsNotEmittedAfterIt() {
|
|
73
|
+
mDispatcher.record(new DownloadProgress(100, 100));
|
|
74
|
+
|
|
75
|
+
mDispatcher.reset();
|
|
76
|
+
mDispatcher.dispatchLatest();
|
|
77
|
+
|
|
78
|
+
assertEquals(Collections.emptyList(), mEmittedBytes);
|
|
79
|
+
}
|
|
80
|
+
}
|
package/ios/CodePush/CodePush.mm
CHANGED
|
@@ -739,6 +739,14 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage
|
|
|
739
739
|
operationQueue:_methodQueue
|
|
740
740
|
// The download is progressing forward
|
|
741
741
|
progressCallback:^(long long expectedContentLength, long long receivedContentLength) {
|
|
742
|
+
// Received bytes only run backwards when a new download starts a stream of its
|
|
743
|
+
// own - the full archive after a binary patch fallback. The pause left over
|
|
744
|
+
// from the finished patch download would swallow that whole stream, so frame
|
|
745
|
+
// observation resumes here and the throttle forgets the previous stream.
|
|
746
|
+
if (notifyProgress && receivedContentLength < _latestReceivedConentLength) {
|
|
747
|
+
self.paused = NO;
|
|
748
|
+
_lastProgressEventTime = 0;
|
|
749
|
+
}
|
|
742
750
|
// Update the download progress so that the frame observer can notify the JS side
|
|
743
751
|
_latestExpectedContentLength = expectedContentLength;
|
|
744
752
|
_latestReceivedConentLength = receivedContentLength;
|
|
@@ -61,6 +61,12 @@ failCallback:(void (^)(NSError *err))failCallback {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
self.expectedContentLength = response.expectedContentLength;
|
|
64
|
+
if (self.expectedContentLength > 0) {
|
|
65
|
+
// Each download opens its own progress stream. The zero-received event hands the
|
|
66
|
+
// listener the new total up front, so the full download after a binary patch
|
|
67
|
+
// fallback shows as restarting rather than running backwards.
|
|
68
|
+
self.progressCallback(self.expectedContentLength, 0);
|
|
69
|
+
}
|
|
64
70
|
[self.outputFileStream open];
|
|
65
71
|
}
|
|
66
72
|
|
package/package.json
CHANGED
|
@@ -162,7 +162,9 @@ export interface CodePushOptions extends SyncOptions {
|
|
|
162
162
|
|
|
163
163
|
export interface DownloadProgress {
|
|
164
164
|
/**
|
|
165
|
-
* The total number of bytes expected to be received for this update
|
|
165
|
+
* The total number of bytes expected to be received for this download. An update
|
|
166
|
+
* published with a binary patch can be downloaded twice: when applying the patch
|
|
167
|
+
* fails, the full archive is downloaded as a second stream with its own total.
|
|
166
168
|
*/
|
|
167
169
|
totalBytes: number;
|
|
168
170
|
|