react-native-update 10.43.3 → 10.45.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.
Files changed (41) hide show
  1. package/android/jni/Android.mk +0 -1
  2. package/android/lib/arm64-v8a/librnupdate.so +0 -0
  3. package/android/lib/armeabi-v7a/librnupdate.so +0 -0
  4. package/android/lib/x86/librnupdate.so +0 -0
  5. package/android/lib/x86_64/librnupdate.so +0 -0
  6. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +24 -12
  7. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +33 -9
  8. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +9 -1
  9. package/android/src/main/java/cn/reactnative/modules/update/StateSerialRunner.java +64 -0
  10. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +8 -4
  11. package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +13 -1
  12. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +8 -8
  13. package/cpp/patch_core/archive_patch_core.cpp +16 -0
  14. package/cpp/patch_core/archive_patch_core.h +5 -0
  15. package/cpp/patch_core/jni_util.h +56 -0
  16. package/cpp/patch_core/patch_core.cpp +16 -1
  17. package/cpp/patch_core/patch_core.h +6 -0
  18. package/cpp/patch_core/patch_core_android.cpp +4 -37
  19. package/cpp/patch_core/state_ops.h +24 -0
  20. package/cpp/patch_core/tests/patch_core_test.cpp +109 -2
  21. package/cpp/patch_core/update_core_android.cpp +43 -69
  22. package/harmony/pushy/src/main/cpp/pushy.cpp +163 -128
  23. package/harmony/pushy/src/main/ets/DownloadTask.ts +72 -19
  24. package/harmony/pushy/src/main/ets/NativePatchCore.ts +2 -6
  25. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +10 -10
  26. package/harmony/pushy/src/main/ets/UpdateContext.ts +26 -9
  27. package/harmony/pushy.har +0 -0
  28. package/ios/RCTPushy/RCTPushy.mm +142 -111
  29. package/ios/RCTPushy/RCTPushyDownloader.mm +41 -2
  30. package/package.json +7 -3
  31. package/src/client.ts +161 -101
  32. package/src/context.ts +21 -7
  33. package/src/core.ts +5 -1
  34. package/src/index.ts +7 -1
  35. package/src/provider.tsx +91 -56
  36. package/src/utils.ts +58 -18
  37. package/android/jni/DownloadTask.c +0 -56
  38. package/android/jni/cn_reactnative_modules_update_DownloadTask.h +0 -21
  39. package/harmony/pushy/src/main/cpp/pushy.c +0 -117
  40. package/harmony/pushy/src/main/cpp/pushy.h +0 -8
  41. package/src/__tests__/setup.ts +0 -44
package/src/provider.tsx CHANGED
@@ -2,6 +2,7 @@ import React, {
2
2
  ReactNode,
3
3
  useCallback,
4
4
  useEffect,
5
+ useMemo,
5
6
  useRef,
6
7
  useState,
7
8
  } from 'react';
@@ -24,10 +25,10 @@ import {
24
25
  ProgressData,
25
26
  UpdateTestPayload,
26
27
  } from './type';
27
- import { UpdateContext } from './context';
28
+ import { ProgressContext, UpdateContext } from './context';
28
29
  import { URL } from 'react-native-url-polyfill';
29
30
  import { resolveCheckResult } from './resolveCheckResult';
30
- import { assertWeb, log } from './utils';
31
+ import { assertWeb, log, noop } from './utils';
31
32
 
32
33
  export const UpdateProvider = ({
33
34
  client,
@@ -44,7 +45,6 @@ export const UpdateProvider = ({
44
45
  const updateInfoRef = useRef(updateInfo);
45
46
  const [progress, setProgress] = useState<ProgressData>();
46
47
  const [lastError, setLastError] = useState<Error>();
47
- const lastChecking = useRef(0);
48
48
 
49
49
  const throwErrorIfEnabled = useCallback(
50
50
  (e: Error) => {
@@ -108,7 +108,6 @@ export const UpdateProvider = ({
108
108
  if (!hash) {
109
109
  return false;
110
110
  }
111
- stateListener.current && stateListener.current.remove();
112
111
 
113
112
  if (
114
113
  options.afterDownloadUpdate &&
@@ -162,15 +161,12 @@ export const UpdateProvider = ({
162
161
 
163
162
  const checkUpdate = useCallback(
164
163
  async ({ extra }: { extra?: Partial<{ toHash: string }> } = {}) => {
165
- const now = Date.now();
166
- if (lastChecking.current && now - lastChecking.current < 1000) {
167
- client.notifyAfterCheckUpdate({ status: 'skipped' });
168
- return;
169
- }
170
- lastChecking.current = now;
164
+ // No throttle here: the client already dedupes checks via its 5s
165
+ // response cache, and a second throttle layer silently returned
166
+ // undefined, indistinguishable from a failed check.
171
167
  let rootInfo: CheckResult | undefined;
172
168
  try {
173
- rootInfo = { ...(await client.checkUpdate(extra)) };
169
+ rootInfo = await client.checkUpdate(extra);
174
170
  } catch (e: any) {
175
171
  setLastError(e);
176
172
  alertError(client.t('error_update_check_failed'), e.message);
@@ -178,6 +174,8 @@ export const UpdateProvider = ({
178
174
  return;
179
175
  }
180
176
  if (!rootInfo) {
177
+ // Check was skipped or failed with no cached result; keep the last
178
+ // known updateInfo instead of overwriting it with an empty object.
181
179
  return;
182
180
  }
183
181
  const info = resolveCheckResult(rootInfo);
@@ -198,7 +196,7 @@ export const UpdateProvider = ({
198
196
  if (downloadUrl && sharedState.apkStatus === null) {
199
197
  if (options.updateStrategy === 'silentAndNow') {
200
198
  if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) {
201
- downloadAndInstallApk(downloadUrl);
199
+ downloadAndInstallApk(downloadUrl).catch(noop);
202
200
  } else {
203
201
  Linking.openURL(downloadUrl);
204
202
  }
@@ -215,7 +213,7 @@ export const UpdateProvider = ({
215
213
  Platform.OS === 'android' &&
216
214
  downloadUrl.endsWith('.apk')
217
215
  ) {
218
- downloadAndInstallApk(downloadUrl);
216
+ downloadAndInstallApk(downloadUrl).catch(noop);
219
217
  } else {
220
218
  Linking.openURL(downloadUrl);
221
219
  }
@@ -229,7 +227,7 @@ export const UpdateProvider = ({
229
227
  options.updateStrategy === 'silentAndNow' ||
230
228
  options.updateStrategy === 'silentAndLater'
231
229
  ) {
232
- downloadUpdate(info);
230
+ downloadUpdate(info).catch(noop);
233
231
  return info;
234
232
  }
235
233
  alertUpdate(
@@ -244,7 +242,7 @@ export const UpdateProvider = ({
244
242
  text: client.t('alert_confirm'),
245
243
  style: 'default',
246
244
  onPress: () => {
247
- downloadUpdate();
245
+ downloadUpdate().catch(noop);
248
246
  },
249
247
  },
250
248
  ],
@@ -272,9 +270,10 @@ export const UpdateProvider = ({
272
270
  if (!assertWeb()) {
273
271
  return;
274
272
  }
275
- const { checkStrategy, dismissErrorAfter, autoMarkSuccess } = options;
273
+ const { checkStrategy, autoMarkSuccess } = options;
274
+ let markSuccessTimer: ReturnType<typeof setTimeout> | undefined;
276
275
  if (autoMarkSuccess) {
277
- setTimeout(() => {
276
+ markSuccessTimer = setTimeout(() => {
278
277
  markSuccess();
279
278
  }, 1000);
280
279
  }
@@ -283,26 +282,38 @@ export const UpdateProvider = ({
283
282
  'change',
284
283
  nextAppState => {
285
284
  if (nextAppState === 'active') {
286
- checkUpdate();
285
+ checkUpdate().catch(noop);
287
286
  }
288
287
  },
289
288
  );
290
289
  }
291
290
  if (checkStrategy === 'both' || checkStrategy === 'onAppStart') {
292
- checkUpdate();
293
- }
294
- let dismissErrorTimer: ReturnType<typeof setTimeout>;
295
- if (typeof dismissErrorAfter === 'number' && dismissErrorAfter > 0) {
296
- dismissErrorTimer = setTimeout(() => {
297
- dismissError();
298
- }, dismissErrorAfter);
291
+ checkUpdate().catch(noop);
299
292
  }
300
293
  return () => {
294
+ if (markSuccessTimer) {
295
+ clearTimeout(markSuccessTimer);
296
+ }
301
297
  stateListener.current && stateListener.current.remove();
302
- clearTimeout(dismissErrorTimer);
303
298
  };
304
299
  }, [checkUpdate, options, dismissError, markSuccess, client]);
305
300
 
301
+ useEffect(() => {
302
+ const { dismissErrorAfter } = options;
303
+ if (
304
+ lastError &&
305
+ typeof dismissErrorAfter === 'number' &&
306
+ dismissErrorAfter > 0
307
+ ) {
308
+ const dismissErrorTimer = setTimeout(() => {
309
+ dismissError();
310
+ }, dismissErrorAfter);
311
+ return () => {
312
+ clearTimeout(dismissErrorTimer);
313
+ };
314
+ }
315
+ }, [lastError, options, dismissError]);
316
+
306
317
  const parseTestPayload = useCallback(
307
318
  (payload: UpdateTestPayload) => {
308
319
  if (payload && payload.type && payload.type.startsWith('__rnPushy')) {
@@ -314,15 +325,19 @@ export const UpdateProvider = ({
314
325
  if (payload.type === '__rnPushyVersionHash') {
315
326
  const toHash = payload.data;
316
327
  sharedState.toHash = toHash;
317
- checkUpdate({ extra: { toHash } }).then(() => {
318
- if (updateInfoRef.current && updateInfoRef.current.upToDate) {
319
- Alert.alert(
320
- client.t('alert_info'),
321
- client.t('alert_no_update_wait'),
322
- );
323
- }
324
- options.logger = logger;
325
- });
328
+ checkUpdate({ extra: { toHash } })
329
+ .then(() => {
330
+ if (updateInfoRef.current && updateInfoRef.current.upToDate) {
331
+ Alert.alert(
332
+ client.t('alert_info'),
333
+ client.t('alert_no_update_wait'),
334
+ );
335
+ }
336
+ })
337
+ .catch(noop)
338
+ .finally(() => {
339
+ options.logger = logger;
340
+ });
326
341
  }
327
342
  return true;
328
343
  }
@@ -377,28 +392,48 @@ export const UpdateProvider = ({
377
392
  };
378
393
  }, [parseTestPayload]);
379
394
 
395
+ // progress lives in its own context (see context.ts), so this value only
396
+ // changes when the update state itself changes, not on every progress tick.
397
+ const contextValue = useMemo(
398
+ () => ({
399
+ checkUpdate,
400
+ switchVersion,
401
+ switchVersionLater,
402
+ dismissError,
403
+ updateInfo,
404
+ lastError,
405
+ markSuccess,
406
+ client,
407
+ downloadUpdate,
408
+ packageVersion,
409
+ currentHash: currentVersion,
410
+ downloadAndInstallApk,
411
+ getCurrentVersionInfo,
412
+ currentVersionInfo,
413
+ parseTestQrCode,
414
+ restartApp,
415
+ }),
416
+ [
417
+ checkUpdate,
418
+ switchVersion,
419
+ switchVersionLater,
420
+ dismissError,
421
+ updateInfo,
422
+ lastError,
423
+ markSuccess,
424
+ client,
425
+ downloadUpdate,
426
+ downloadAndInstallApk,
427
+ parseTestQrCode,
428
+ restartApp,
429
+ ],
430
+ );
431
+
380
432
  return (
381
- <UpdateContext.Provider
382
- value={{
383
- checkUpdate,
384
- switchVersion,
385
- switchVersionLater,
386
- dismissError,
387
- updateInfo,
388
- lastError,
389
- markSuccess,
390
- client,
391
- downloadUpdate,
392
- packageVersion,
393
- currentHash: currentVersion,
394
- progress,
395
- downloadAndInstallApk,
396
- getCurrentVersionInfo,
397
- currentVersionInfo,
398
- parseTestQrCode,
399
- restartApp,
400
- }}>
401
- {children}
433
+ <UpdateContext.Provider value={contextValue}>
434
+ <ProgressContext.Provider value={progress}>
435
+ {children}
436
+ </ProgressContext.Provider>
402
437
  </UpdateContext.Provider>
403
438
  );
404
439
  };
package/src/utils.ts CHANGED
@@ -22,6 +22,10 @@ export const DEFAULT_FETCH_TIMEOUT_MS = 5000;
22
22
 
23
23
  export function promiseAny<T>(promises: Promise<T>[]) {
24
24
  return new Promise<T>((resolve, reject) => {
25
+ if (!promises.length) {
26
+ reject(Error(i18n.t('error_all_promises_rejected')));
27
+ return;
28
+ }
25
29
  let count = 0;
26
30
 
27
31
  promises.forEach(promise => {
@@ -84,7 +88,7 @@ export function joinUrls(paths: string[], fileName?: string) {
84
88
  }
85
89
  }
86
90
 
87
- export const testUrls = async (urls?: string[]) => {
91
+ export const testUrls = async (urls?: string[]): Promise<string | null> => {
88
92
  if (!urls?.length) {
89
93
  return null;
90
94
  }
@@ -93,7 +97,7 @@ export const testUrls = async (urls?: string[]) => {
93
97
  const ret = await promiseAny(urls.map(ping));
94
98
  if (ret) {
95
99
  log('ping success, use url:', ret);
96
- return ret;
100
+ return ret as string;
97
101
  }
98
102
  } catch {}
99
103
  log('all ping failed, use first url:', urls[0]);
@@ -118,21 +122,50 @@ export const fetchWithTimeout = (
118
122
  params: Parameters<typeof fetch>[1],
119
123
  timeoutMs = DEFAULT_FETCH_TIMEOUT_MS,
120
124
  ): Promise<Response> => {
121
- let timeoutId: ReturnType<typeof setTimeout> | undefined;
122
-
123
- return Promise.race([
124
- enhancedFetch(url, params),
125
- new Promise<Response>((_, reject) => {
126
- timeoutId = setTimeout(() => {
127
- log('fetch timeout', url);
128
- reject(Error(i18n.t('error_ping_timeout')));
129
- }, timeoutMs);
130
- }),
131
- ]).finally(() => {
132
- if (timeoutId) {
125
+ // AbortController landed in the RN fetch polyfill around 0.60; we support
126
+ // older peers, so fall back to a plain timer race when it is unavailable
127
+ // (the losing fetch keeps running there — old runtimes can't do better).
128
+ if (typeof AbortController === 'undefined') {
129
+ let timeoutId: ReturnType<typeof setTimeout> | undefined;
130
+ return Promise.race([
131
+ enhancedFetch(url, params),
132
+ new Promise<Response>((_, reject) => {
133
+ timeoutId = setTimeout(() => {
134
+ log('fetch timeout', url);
135
+ reject(Error(i18n.t('error_ping_timeout')));
136
+ }, timeoutMs);
137
+ }),
138
+ ]).finally(() => {
139
+ if (timeoutId) {
140
+ clearTimeout(timeoutId);
141
+ }
142
+ });
143
+ }
144
+
145
+ // Abort the underlying request on timeout instead of racing a timer: with
146
+ // Promise.race the losing fetch kept running (and kept the connection busy)
147
+ // long after the caller had already moved on.
148
+ const controller = new AbortController();
149
+ const timeoutId = setTimeout(() => {
150
+ log('fetch timeout', url);
151
+ controller.abort();
152
+ }, timeoutMs);
153
+
154
+ return enhancedFetch(url, { ...params, signal: controller.signal })
155
+ .catch((e: any) => {
156
+ if (controller.signal.aborted) {
157
+ throw Error(i18n.t('error_ping_timeout'));
158
+ }
159
+ throw e;
160
+ })
161
+ .finally(() => {
133
162
  clearTimeout(timeoutId);
134
- }
135
- });
163
+ });
164
+ };
165
+
166
+ const isIdempotentRequest = (params: Parameters<typeof fetch>[1]) => {
167
+ const method = params?.method?.toUpperCase() ?? 'GET';
168
+ return method === 'GET' || method === 'HEAD';
136
169
  };
137
170
 
138
171
  export const enhancedFetch = async (
@@ -143,10 +176,17 @@ export const enhancedFetch = async (
143
176
  return fetch(url, params)
144
177
  .catch(e => {
145
178
  log('fetch error', url, e);
146
- if (isRetry) {
179
+ if (
180
+ isRetry ||
181
+ (params as any)?.signal?.aborted ||
182
+ !url.startsWith('https:') ||
183
+ // Never replay non-idempotent requests (e.g. the checkUpdate POST)
184
+ // over plaintext http: the server may have processed the original.
185
+ !isIdempotentRequest(params)
186
+ ) {
147
187
  throw e;
148
188
  }
149
189
  log('trying fallback to http');
150
- return enhancedFetch(url.replace('https', 'http'), params, true);
190
+ return enhancedFetch(url.replace(/^https:/, 'http:'), params, true);
151
191
  });
152
192
  };
@@ -1,56 +0,0 @@
1
- //
2
- // Created by DengYun on 3/31/16.
3
- //
4
-
5
- #include "cn_reactnative_modules_update_DownloadTask.h"
6
-
7
- #include "hpatch.h"
8
- #define _check(v,errInfo) do{ if (!(v)) { _isError=hpatch_TRUE; _errInfo=errInfo; goto _clear; } }while(0)
9
-
10
- JNIEXPORT jbyteArray JNICALL Java_cn_reactnative_modules_update_DownloadTask_hdiffPatch
11
- (JNIEnv *env, jobject self, jbyteArray origin, jbyteArray patch){
12
- hpatch_BOOL _isError=hpatch_FALSE;
13
- const char* _errInfo="";
14
-
15
- jbyte* originPtr = (*env)->GetByteArrayElements(env, origin, NULL);
16
- size_t originLength = (*env)->GetArrayLength(env, origin);
17
- jbyte* patchPtr = (*env)->GetByteArrayElements(env, patch, NULL);
18
- size_t patchLength = (*env)->GetArrayLength(env, patch);
19
- jbyteArray ret = NULL;
20
- jbyte* outPtr = NULL;
21
- size_t newsize = 0;
22
- hpatch_singleCompressedDiffInfo patInfo;
23
-
24
- _check(((originLength==0)||originPtr) && patchPtr && (patchLength>0),"Corrupt patch");
25
- _check(kHPatch_ok==hpatch_getInfo_by_mem(&patInfo,(const uint8_t*)patchPtr,patchLength),"Error info in hpatch");
26
- _check(originLength==patInfo.oldDataSize,"Error oldDataSize in hpatch");
27
- newsize=(size_t)patInfo.newDataSize;
28
- if (sizeof(size_t)!=sizeof(hpatch_StreamPos_t))
29
- _check(newsize==patInfo.newDataSize,"Error newDataSize in hpatch");
30
-
31
- ret = (*env)->NewByteArray(env,newsize);
32
- _check(ret,"Error JNIEnv::NewByteArray()");
33
- if (newsize>0) {
34
- outPtr = (*env)->GetByteArrayElements(env, ret, NULL);
35
- _check(outPtr,"Corrupt JNIEnv::GetByteArrayElements");
36
- }
37
-
38
- _check(kHPatch_ok==hpatch_by_mem((const uint8_t*)originPtr,originLength,(uint8_t*)outPtr,newsize,
39
- (const uint8_t*)patchPtr,patchLength,&patInfo),"hpacth");
40
-
41
- _clear:
42
- if (outPtr) (*env)->ReleaseByteArrayElements(env, ret, outPtr, (_isError?JNI_ABORT:0));
43
- if (originPtr) (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT);
44
- if (patchPtr) (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT);
45
- if (_isError){
46
- jclass newExcCls = NULL;
47
- if (ret){
48
- (*env)->DeleteLocalRef(env, ret);
49
- ret = NULL;
50
- }
51
- newExcCls = (*env)->FindClass(env, "java/lang/Error");
52
- if (newExcCls != NULL) // Unable to find the new exception class, give up.
53
- (*env)->ThrowNew(env, newExcCls, _errInfo);
54
- }
55
- return ret;
56
- }
@@ -1,21 +0,0 @@
1
- /* DO NOT EDIT THIS FILE - it is machine generated */
2
- #include <jni.h>
3
- /* Header for class cn_reactnative_modules_update_DownloadTask */
4
-
5
- #ifndef _Included_cn_reactnative_modules_update_DownloadTask
6
- #define _Included_cn_reactnative_modules_update_DownloadTask
7
- #ifdef __cplusplus
8
- extern "C" {
9
- #endif
10
- /*
11
- * Class: cn_reactnative_modules_update_DownloadTask
12
- * Method: hdiffPatch
13
- * Signature: ([B[B)[B
14
- */
15
- JNIEXPORT jbyteArray JNICALL Java_cn_reactnative_modules_update_DownloadTask_hdiffPatch
16
- (JNIEnv *, jclass, jbyteArray, jbyteArray);
17
-
18
- #ifdef __cplusplus
19
- }
20
- #endif
21
- #endif
@@ -1,117 +0,0 @@
1
- #include "pushy.h"
2
- #include "hpatch.h"
3
- #include <napi/native_api.h>
4
- #include <js_native_api.h>
5
- #include <js_native_api_types.h>
6
-
7
- #define _check(v,errInfo) do { \
8
- if (!(v)) { \
9
- _isError = hpatch_TRUE; \
10
- _errInfo = errInfo; \
11
- goto _clear; \
12
- } \
13
- } while(0)
14
-
15
- napi_value HdiffPatch(napi_env env, napi_callback_info info) {
16
- napi_status status;
17
- size_t argc = 2;
18
- napi_value args[2];
19
- hpatch_BOOL _isError = hpatch_FALSE;
20
- const char* _errInfo = "";
21
-
22
- // 获取参数
23
- status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
24
- if (status != napi_ok || argc < 2) {
25
- napi_throw_error(env, NULL, "Wrong number of arguments");
26
- return NULL;
27
- }
28
-
29
- // 获取origin buffer
30
- bool isTypedArray;
31
- status = napi_is_typedarray(env, args[0], &isTypedArray);
32
- if (status != napi_ok || !isTypedArray) {
33
- napi_throw_error(env, NULL, "First argument must be a TypedArray");
34
- return NULL;
35
- }
36
-
37
- uint8_t* originPtr;
38
- size_t originLength;
39
- status = napi_get_typedarray_info(env, args[0], NULL, &originLength,
40
- (void**)&originPtr, NULL, NULL);
41
- if (status != napi_ok) {
42
- napi_throw_error(env, NULL, "Failed to get origin buffer");
43
- return NULL;
44
- }
45
-
46
- // 获取patch buffer
47
- status = napi_is_typedarray(env, args[1], &isTypedArray);
48
- if (status != napi_ok || !isTypedArray) {
49
- napi_throw_error(env, NULL, "Second argument must be a TypedArray");
50
- return NULL;
51
- }
52
-
53
- uint8_t* patchPtr;
54
- size_t patchLength;
55
- status = napi_get_typedarray_info(env, args[1], NULL, &patchLength,
56
- (void**)&patchPtr, NULL, NULL);
57
- if (status != napi_ok) {
58
- napi_throw_error(env, NULL, "Failed to get patch buffer");
59
- return NULL;
60
- }
61
-
62
- // 执行patch操作
63
- hpatch_singleCompressedDiffInfo patInfo;
64
-
65
- _check(((originLength==0)||originPtr) && patchPtr && (patchLength>0), "Corrupt patch");
66
- _check(kHPatch_ok==hpatch_getInfo_by_mem(&patInfo, patchPtr, patchLength), "Error info in hpatch");
67
- _check(originLength==patInfo.oldDataSize, "Error oldDataSize in hpatch");
68
- size_t newsize = (size_t)patInfo.newDataSize;
69
- if (sizeof(size_t)!=sizeof(hpatch_StreamPos_t))
70
- _check(newsize==patInfo.newDataSize, "Error newDataSize in hpatch");
71
-
72
- // 创建结果buffer
73
- napi_value resultBuffer;
74
- uint8_t* outPtr;
75
- void* data;
76
-
77
- status = napi_create_arraybuffer(env, newsize, &data, &resultBuffer);
78
- if (status != napi_ok) {
79
- napi_throw_error(env, NULL, "Failed to create result buffer");
80
- return NULL;
81
- }
82
- outPtr = (uint8_t*)data;
83
-
84
- // 执行patch
85
- _check(kHPatch_ok==hpatch_by_mem(originPtr, originLength, outPtr, newsize,
86
- patchPtr, patchLength, &patInfo), "hpatch");
87
- return resultBuffer;
88
-
89
- _clear:
90
- if (_isError) {
91
- napi_throw_error(env, NULL, _errInfo);
92
- return NULL;
93
- }
94
- return NULL;
95
- }
96
-
97
- // 模块初始化
98
- napi_value Init(napi_env env, napi_value exports) {
99
- napi_status status;
100
- napi_value fn;
101
-
102
- status = napi_create_function(env, NULL, 0, HdiffPatch, NULL, &fn);
103
- if (status != napi_ok) {
104
- napi_throw_error(env, NULL, "Unable to wrap native function");
105
- return NULL;
106
- }
107
-
108
- status = napi_set_named_property(env, exports, "hdiffPatch", fn);
109
- if (status != napi_ok) {
110
- napi_throw_error(env, NULL, "Unable to populate exports");
111
- return NULL;
112
- }
113
-
114
- return exports;
115
- }
116
-
117
- NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
@@ -1,8 +0,0 @@
1
- #ifndef _DOWNLOAD_TASK_H_
2
- #define _DOWNLOAD_TASK_H_
3
-
4
- #include <napi/native_api.h>
5
-
6
- napi_value HdiffPatch(napi_env env, napi_callback_info info);
7
-
8
- #endif // _DOWNLOAD_TASK_H_
@@ -1,44 +0,0 @@
1
- import { mock } from 'bun:test';
2
-
3
- mock.module('react-native', () => {
4
- return {
5
- Platform: {
6
- OS: 'ios',
7
- Version: 13,
8
- },
9
- DeviceEventEmitter: {
10
- addListener: () => ({ remove: () => {} }),
11
- },
12
- NativeModules: {
13
- Pushy: {
14
- currentVersionInfo: '{}',
15
- downloadRootDir: '/tmp',
16
- packageVersion: '1.0.0',
17
- currentVersion: 'hash',
18
- isFirstTime: false,
19
- rolledBackVersion: '',
20
- buildTime: '2023-01-01',
21
- uuid: 'uuid',
22
- setLocalHashInfo: () => {},
23
- getLocalHashInfo: () => Promise.resolve('{}'),
24
- setUuid: () => {},
25
- },
26
- },
27
- NativeEventEmitter: class {
28
- addListener = () => ({ remove: () => {} });
29
- removeAllListeners = () => {};
30
- },
31
- };
32
- });
33
-
34
- mock.module('../i18n', () => {
35
- return {
36
- default: {
37
- t: (key: string, params?: any) => `${key}${params ? JSON.stringify(params) : ''}`,
38
- },
39
- };
40
- });
41
-
42
- mock.module('react-native/Libraries/Core/ReactNativeVersion', () => ({
43
- version: { major: 0, minor: 73, patch: 0 },
44
- }));