react-native-update 8.1.0 → 9.0.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.
Files changed (37) hide show
  1. package/.github/workflows/e2e_android.yml +49 -0
  2. package/.github/workflows/e2e_ios.yml +182 -0
  3. package/.github/workflows/scripts/adb_all_emulators.sh +10 -0
  4. package/.github/workflows/scripts/database.rules +13 -0
  5. package/.github/workflows/scripts/firebase.json +39 -0
  6. package/.github/workflows/scripts/firestore.indexes.json +72 -0
  7. package/.github/workflows/scripts/firestore.rules +17 -0
  8. package/.github/workflows/scripts/functions/package.json +24 -0
  9. package/.github/workflows/scripts/functions/src/exports.ts +13 -0
  10. package/.github/workflows/scripts/functions/src/index.ts +12 -0
  11. package/.github/workflows/scripts/functions/src/sample-data.ts +80 -0
  12. package/.github/workflows/scripts/functions/src/testFunctionCustomRegion.ts +14 -0
  13. package/.github/workflows/scripts/functions/src/testFunctionDefaultRegion.ts +70 -0
  14. package/.github/workflows/scripts/functions/tsconfig.json +16 -0
  15. package/.github/workflows/scripts/start-firebase-emulator.bat +6 -0
  16. package/.github/workflows/scripts/start-firebase-emulator.sh +44 -0
  17. package/.github/workflows/scripts/storage.rules +21 -0
  18. package/README.md +8 -6
  19. package/android/build.gradle +22 -0
  20. package/android/jni/hpatch.c +4 -4
  21. package/android/jni/hpatch.h +3 -3
  22. package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +0 -2
  23. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +265 -0
  24. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +31 -20
  25. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +147 -0
  26. package/android/src/{main/java → oldarch}/cn/reactnative/modules/update/UpdateModule.java +6 -2
  27. package/e2e/jest.config.js +12 -0
  28. package/e2e/starter.test.js +23 -0
  29. package/ios/RCTPushy/{RCTPushy.m → RCTPushy.mm} +116 -44
  30. package/ios/pushy_build_time.txt +1 -1
  31. package/lib/NativeUpdate.js +51 -0
  32. package/lib/main.js +29 -23
  33. package/package.json +36 -2
  34. package/react-native-update.podspec +20 -2
  35. /package/ios/RCTPushy/HDiffPatch/{HDiffPatch.m → HDiffPatch.mm} +0 -0
  36. /package/ios/RCTPushy/{RCTPushyDownloader.m → RCTPushyDownloader.mm} +0 -0
  37. /package/ios/RCTPushy/{RCTPushyManager.m → RCTPushyManager.mm} +0 -0
@@ -0,0 +1,21 @@
1
+ rules_version = '2';
2
+ service firebase.storage {
3
+ match /b/{bucket}/o {
4
+ match /{document=**} {
5
+ allow read, write: if false;
6
+ }
7
+
8
+ match /writeOnly.jpeg {
9
+ allow read: if false;
10
+ allow write: if true;
11
+ }
12
+
13
+ match /playground/{document=**} {
14
+ allow read, write: if true;
15
+ }
16
+
17
+ match /react-native-firebase-testing/{document=**} {
18
+ allow read, write: if true;
19
+ }
20
+ }
21
+ }
package/README.md CHANGED
@@ -9,12 +9,13 @@
9
9
  ### 优势
10
10
 
11
11
  1. 基于阿里云高速 CDN 分发,对比其他服务器在国外的热更新服务,分发更稳定,更新成功率极高。
12
- 2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在 1-10KB 之间(其他全量热更新服务所需流量通常在 1-10MB 级别)。
13
- 3. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
14
- 4. 命令行工具&网页双端管理,版本发布过程简单便捷,完全可以集成 CI。
15
- 5. 支持崩溃回滚,安全可靠。
16
- 6. meta 信息及开放 API,提供更高扩展性。
17
- 7. 提供付费的专人技术支持。
12
+ 2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在几十 KB 级别(其他全量热更新服务所需流量通常在几十 MB 级别)。
13
+ 3. 始终跟进 RN 最新正式版本,第一时间提供支持。支持 hermes 字节码格式。(暂不支持新架构,会待其相对稳定后跟进)
14
+ 4. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
15
+ 5. 命令行工具 & 网页双端管理,版本发布过程简单便捷,完全可以集成 CI。
16
+ 6. 支持崩溃回滚,安全可靠。
17
+ 7. meta 信息及开放 API,提供更高扩展性。
18
+ 8. 提供付费的专人技术支持。
18
19
 
19
20
  ### 本地开发
20
21
 
@@ -32,3 +33,4 @@ $ yarn start
32
33
  本组件由[React Native 中文网](https://reactnative.cn/)独家发布,如有定制需求可以[联系我们](https://reactnative.cn/about.html#content)。
33
34
 
34
35
  关于此插件发现任何问题,可以前往[Issues](https://github.com/reactnativecn/react-native-pushy/issues)发帖提问。
36
+
@@ -5,7 +5,15 @@ def safeExtGet(prop, fallback) {
5
5
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
6
6
  }
7
7
 
8
+ def isNewArchitectureEnabled() {
9
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
10
+ }
11
+
8
12
  apply plugin: 'com.android.library'
13
+ if (isNewArchitectureEnabled()) {
14
+ apply plugin: 'com.facebook.react'
15
+ }
16
+
9
17
 
10
18
  android {
11
19
  compileSdkVersion safeExtGet('compileSdkVersion', 28)
@@ -17,11 +25,17 @@ android {
17
25
  versionCode 1
18
26
  versionName "1.0"
19
27
  consumerProguardFiles "proguard.pro"
28
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
20
29
  }
21
30
  sourceSets {
22
31
  main {
23
32
  // let gradle pack the shared library into apk
24
33
  jniLibs.srcDirs = ['./lib']
34
+ if (isNewArchitectureEnabled()) {
35
+ java.srcDirs += ['src/newarch']
36
+ } else {
37
+ java.srcDirs += ['src/oldarch']
38
+ }
25
39
  }
26
40
  }
27
41
 
@@ -44,4 +58,12 @@ repositories {
44
58
 
45
59
  dependencies {
46
60
  implementation 'com.facebook.react:react-native:+'
61
+ implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
62
+ }
63
+ if (isNewArchitectureEnabled()) {
64
+ react {
65
+ jsRootDir = file("../lib/")
66
+ libraryName = "update"
67
+ codegenJavaPackageName = "cn.reactnative.modules.update"
68
+ }
47
69
  }
@@ -24,7 +24,7 @@ int hpatch_getInfo_by_mem(hpatch_singleCompressedDiffInfo* out_patinfo,
24
24
  mem_as_hStreamInput(&patStream,pat,pat+patsize);
25
25
  if (!getSingleCompressedDiffInfo(out_patinfo,&patStream,0))
26
26
  return kHPatch_error_info;//data error;
27
- return kHPatch_ok; //ok
27
+ return kHPatch_ok; //ok
28
28
  }
29
29
 
30
30
  static hpatch_TDecompress* getDecompressPlugin(const char* compressType){
@@ -68,7 +68,7 @@ static int hpatch_by_stream(const hpatch_TStreamInput* old,hpatch_BOOL isLoadOld
68
68
  _check(decompressPlugin,kHPatch_error_compressType);
69
69
  }
70
70
  }
71
- {// mem
71
+ {// mem
72
72
  size_t mem_size;
73
73
  size_t oldSize=(size_t)old->streamSize;
74
74
  isLoadOldAllToMem=isLoadOldAllToMem&&(old->streamSize<=kMaxLoadMemOldSize);
@@ -76,7 +76,7 @@ static int hpatch_by_stream(const hpatch_TStreamInput* old,hpatch_BOOL isLoadOld
76
76
  mem_size=temp_cache_size+(isLoadOldAllToMem?oldSize:0);
77
77
  temp_cache=malloc(mem_size);
78
78
  _check(temp_cache,kHPatch_error_malloc);
79
- if (isLoadOldAllToMem){//load old to mem
79
+ if (isLoadOldAllToMem){//load old to mem
80
80
  uint8_t* oldMem=temp_cache+temp_cache_size;
81
81
  _check(old->read(old,0,oldMem,oldMem+oldSize),kHPatch_error_old_fread);
82
82
  mem_as_hStreamInput(&_old,oldMem,oldMem+oldSize);
@@ -95,7 +95,7 @@ _clear:
95
95
  }
96
96
 
97
97
  int hpatch_by_mem(const uint8_t* old,size_t oldsize,uint8_t* newBuf,size_t newsize,
98
- const uint8_t* pat,size_t patsize,const hpatch_singleCompressedDiffInfo* patInfo){
98
+ const uint8_t* pat,size_t patsize,const hpatch_singleCompressedDiffInfo* patInfo){
99
99
  hpatch_TStreamInput oldStream;
100
100
  hpatch_TStreamInput patStream;
101
101
  hpatch_TStreamOutput newStream;
@@ -1,5 +1,5 @@
1
- // hpatch.h
2
- // import HDiffPatch, support patchData created by "hdiffz -SD -c-lzma2 oldfile newfile patchfile"
1
+ // hpatch.h
2
+ // import HDiffPatch, support patchData created by "hdiffz -SD -c-lzma2 oldfile newfile patchfile"
3
3
  // Copyright 2021 housisong, All rights reserved
4
4
 
5
5
  #ifndef HDIFFPATCH_PATCH_H
@@ -41,4 +41,4 @@ int hpatch_by_file(const char* oldfile, const char* newfile, const char* patchfi
41
41
  #ifdef __cplusplus
42
42
  }
43
43
  #endif
44
- #endif //HDIFFPATCH_PATCH_H
44
+ #endif //HDIFFPATCH_PATCH_H
@@ -1,7 +1,5 @@
1
1
  package cn.reactnative.modules.update;
2
2
 
3
- import android.content.Context;
4
-
5
3
  import java.io.File;
6
4
 
7
5
  /**
@@ -0,0 +1,265 @@
1
+ package cn.reactnative.modules.update;
2
+
3
+ import android.app.Activity;
4
+ import android.app.Application;
5
+ import android.util.Log;
6
+ import com.facebook.react.ReactApplication;
7
+ import com.facebook.react.ReactInstanceManager;
8
+ import com.facebook.react.bridge.JSBundleLoader;
9
+ import com.facebook.react.bridge.Promise;
10
+ import com.facebook.react.bridge.ReactApplicationContext;
11
+ import com.facebook.react.bridge.ReadableMap;
12
+ import com.facebook.react.bridge.UiThreadUtil;
13
+ import com.fasterxml.jackson.databind.ObjectMapper;
14
+
15
+ import org.json.JSONObject;
16
+
17
+ import java.io.File;
18
+ import java.io.IOException;
19
+ import java.lang.reflect.Field;
20
+ import java.util.HashMap;
21
+ import java.util.Map;
22
+ import java.util.Optional;
23
+ import java.util.regex.Matcher;
24
+ import java.util.regex.Pattern;
25
+
26
+ public class UpdateModuleImpl {
27
+
28
+ public static final String NAME = "Pushy";
29
+
30
+ public static void downloadFullUpdate(UpdateContext updateContext, ReadableMap options, Promise promise) {
31
+ String url = options.getString("updateUrl");
32
+ String hash = options.getString("hash");
33
+ updateContext.downloadFullUpdate(url, hash, new UpdateContext.DownloadFileListener() {
34
+ @Override
35
+ public void onDownloadCompleted(DownloadTaskParams params) {
36
+ promise.resolve(null);
37
+ }
38
+
39
+ @Override
40
+ public void onDownloadFailed(Throwable error) {
41
+ promise.reject(error);
42
+ }
43
+ });
44
+ }
45
+
46
+ public static void downloadAndInstallApk(UpdateContext updateContext, ReadableMap options, Promise promise) {
47
+ String url = options.getString("url");
48
+ String hash = options.getString("hash");
49
+ String target = options.getString("target");
50
+ updateContext.downloadFile(url, hash, target, new UpdateContext.DownloadFileListener() {
51
+ @Override
52
+ public void onDownloadCompleted(DownloadTaskParams params) {
53
+ UpdateModule.installApk(params.targetFile);
54
+ promise.resolve(null);
55
+ }
56
+
57
+ @Override
58
+ public void onDownloadFailed(Throwable error) {
59
+ promise.reject(error);
60
+ }
61
+ });
62
+ }
63
+
64
+ public static void installApk(String url) {
65
+ File toInstall = new File(url);
66
+ UpdateModule.installApk(toInstall);
67
+ }
68
+
69
+ public static void downloadPatchFromPackage(UpdateContext updateContext, ReadableMap options, Promise promise) {
70
+ String url = options.getString("updateUrl");
71
+ String hash = options.getString("hash");
72
+ updateContext.downloadPatchFromApk(url, hash, new UpdateContext.DownloadFileListener() {
73
+ @Override
74
+ public void onDownloadCompleted(DownloadTaskParams params) {
75
+ promise.resolve(null);
76
+ }
77
+
78
+ @Override
79
+ public void onDownloadFailed(Throwable error) {
80
+ promise.reject(error);
81
+ }
82
+ });
83
+ }
84
+
85
+ public static void downloadPatchFromPpk(UpdateContext updateContext, ReadableMap options, Promise promise) {
86
+ try {
87
+ String url = options.getString("updateUrl");
88
+ String hash = options.getString("hash");
89
+
90
+ String originHash = options.getString("originHash");
91
+
92
+ updateContext.downloadPatchFromPpk(url, hash, originHash, new UpdateContext.DownloadFileListener() {
93
+ @Override
94
+ public void onDownloadCompleted(DownloadTaskParams params) {
95
+ promise.resolve(null);
96
+ }
97
+
98
+ @Override
99
+ public void onDownloadFailed(Throwable error) {
100
+ promise.reject(error);
101
+ }
102
+ });
103
+ }catch (Exception e){
104
+ promise.reject("执行报错:"+e.getMessage());
105
+ }
106
+ }
107
+
108
+ public static void reloadUpdate(UpdateContext updateContext, ReactApplicationContext mContext, ReadableMap options,Promise promise) {
109
+ final String hash = options.getString("hash");
110
+
111
+ if(hash==null || hash.isEmpty()){
112
+ promise.reject("hash不能为空");
113
+ return;
114
+ }
115
+ UiThreadUtil.runOnUiThread(new Runnable() {
116
+ @Override
117
+ public void run() {
118
+ try {
119
+ updateContext.switchVersion(hash);
120
+ Activity activity = mContext.getCurrentActivity();
121
+ Application application = activity.getApplication();
122
+ ReactInstanceManager instanceManager = updateContext.getCustomReactInstanceManager();
123
+
124
+ if (instanceManager == null) {
125
+ instanceManager = ((ReactApplication) application).getReactNativeHost().getReactInstanceManager();
126
+ }
127
+
128
+ try {
129
+ JSBundleLoader loader = JSBundleLoader.createFileLoader(UpdateContext.getBundleUrl(application));
130
+ Field loadField = instanceManager.getClass().getDeclaredField("mBundleLoader");
131
+ loadField.setAccessible(true);
132
+ loadField.set(instanceManager, loader);
133
+ } catch (Throwable err) {
134
+ promise.reject("pushy:"+err.getMessage());
135
+ Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile");
136
+ jsBundleField.setAccessible(true);
137
+ jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application));
138
+ }
139
+
140
+ try {
141
+ instanceManager.recreateReactContextInBackground();
142
+ promise.resolve(true);
143
+ } catch (Throwable err) {
144
+ promise.reject("pushy:"+err.getMessage());
145
+ activity.recreate();
146
+ }
147
+
148
+ } catch (Throwable err) {
149
+ promise.reject("pushy:switchVersion failed"+err.getMessage());
150
+ Log.e("pushy", "switchVersion failed", err);
151
+ }
152
+ }
153
+ });
154
+ }
155
+
156
+
157
+ public static void setNeedUpdate(UpdateContext updateContext, ReadableMap options,Promise promise) {
158
+ try {
159
+ final String hash = options.getString("hash");
160
+ if(hash==null || hash.isEmpty()){
161
+ promise.reject("hash不能为空");
162
+ return;
163
+ }
164
+ UiThreadUtil.runOnUiThread(new Runnable() {
165
+ @Override
166
+ public void run() {
167
+ try {
168
+ updateContext.switchVersion(hash);
169
+ promise.resolve(true);
170
+ } catch (Throwable err) {
171
+ promise.reject("switchVersionLater failed:"+err.getMessage());
172
+ Log.e("pushy", "switchVersionLater failed", err);
173
+ }
174
+ }
175
+ });
176
+ }catch (Exception e){
177
+ promise.reject("执行报错:"+e.getMessage());
178
+ }
179
+ }
180
+
181
+ public static void markSuccess(UpdateContext updateContext,Promise promise) {
182
+ try {
183
+ UiThreadUtil.runOnUiThread(new Runnable() {
184
+ @Override
185
+ public void run() {
186
+ updateContext.markSuccess();
187
+ promise.resolve(true);
188
+ }
189
+ });
190
+ }catch (Exception e){
191
+ promise.reject("执行报错:"+e.getMessage());
192
+ }
193
+ }
194
+
195
+ public static void setBlockUpdate(UpdateContext updateContext, ReadableMap options,Promise promise) {
196
+ try {
197
+ final int until = options.getInt("until");
198
+ final String reason = options.getString("reason");
199
+ UiThreadUtil.runOnUiThread(new Runnable() {
200
+ @Override
201
+ public void run() {
202
+ updateContext.setBlockUpdate(until, reason);
203
+ }
204
+ });
205
+ promise.resolve(true);
206
+ }catch (Exception e){
207
+ promise.reject("执行报错:"+e.getMessage());
208
+ }
209
+
210
+ }
211
+
212
+ public static void setUuid(UpdateContext updateContext, String uuid, Promise promise) {
213
+ try {
214
+ UiThreadUtil.runOnUiThread(new Runnable() {
215
+ @Override
216
+ public void run() {
217
+ updateContext.setKv("uuid", uuid);
218
+ promise.resolve(true);
219
+ }
220
+ });
221
+ }catch (Exception e){
222
+ promise.reject("执行报错:"+e.getMessage());
223
+ }
224
+
225
+ }
226
+
227
+ public static boolean check(String json) {
228
+ ObjectMapper mapper = new ObjectMapper();
229
+ try {
230
+ mapper.readValue(json, Map.class);
231
+ System.out.println("String can be converted to Map");
232
+ return true;
233
+ } catch (IOException e) {
234
+ System.out.println("String cannot be converted to Map");
235
+ return false;
236
+ }
237
+ }
238
+
239
+
240
+ public static void setLocalHashInfo(UpdateContext updateContext, final String hash, final String info, Promise promise) {
241
+ UiThreadUtil.runOnUiThread(new Runnable() {
242
+ @Override
243
+ public void run() {
244
+ if(!check(info)){
245
+ updateContext.setKv("hash_" + hash, info);
246
+ promise.reject("校验报错:json字符串格式错误");
247
+ }else {
248
+ updateContext.setKv("hash_" + hash, info);
249
+ promise.resolve(true);
250
+ }
251
+ }
252
+ });
253
+ }
254
+
255
+ public static void getLocalHashInfo(UpdateContext updateContext, final String hash, Promise promise) {
256
+ String value = updateContext.getKv("hash_" + hash);
257
+ if(check(value)){
258
+ promise.resolve(value);
259
+ }else {
260
+ promise.reject("校验报错:json字符串格式错误");
261
+ }
262
+
263
+ }
264
+
265
+ }
@@ -1,34 +1,45 @@
1
1
  package cn.reactnative.modules.update;
2
2
 
3
- import com.facebook.react.ReactPackage;
4
- import com.facebook.react.bridge.JavaScriptModule;
3
+ import androidx.annotation.Nullable;
4
+ import com.facebook.react.TurboReactPackage;
5
5
  import com.facebook.react.bridge.NativeModule;
6
6
  import com.facebook.react.bridge.ReactApplicationContext;
7
- import com.facebook.react.uimanager.ViewManager;
8
-
9
- import java.util.Arrays;
10
- import java.util.Collections;
11
- import java.util.List;
7
+ import com.facebook.react.module.model.ReactModuleInfo;
8
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
9
+ import java.util.HashMap;
10
+ import java.util.Map;
12
11
 
13
12
  /**
14
13
  * Created by tdzl2003 on 3/31/16.
15
14
  */
16
- public class UpdatePackage implements ReactPackage {
17
-
15
+ public class UpdatePackage extends TurboReactPackage {
16
+ @Nullable
18
17
  @Override
19
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
20
- return Arrays.asList(new NativeModule[]{
21
- // Modules from third-party
22
- new UpdateModule(reactContext),
23
- });
24
- }
25
-
26
- public List<Class<? extends JavaScriptModule>> createJSModules() {
27
- return Collections.emptyList();
18
+ public NativeModule getModule(String name, ReactApplicationContext reactContext) {
19
+ if (name.equals(UpdateModuleImpl.NAME)) {
20
+ return new UpdateModule(reactContext);
21
+ } else {
22
+ return null;
23
+ }
28
24
  }
29
25
 
30
26
  @Override
31
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
32
- return Collections.emptyList();
27
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
28
+ return () -> {
29
+ final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
30
+ boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
31
+ moduleInfos.put(
32
+ UpdateModuleImpl.NAME,
33
+ new ReactModuleInfo(
34
+ UpdateModuleImpl.NAME,
35
+ UpdateModuleImpl.NAME,
36
+ false, // canOverrideExistingModule
37
+ false, // needsEagerInit
38
+ true, // hasConstants
39
+ false, // isCxxModule
40
+ isTurboModule // isTurboModule
41
+ ));
42
+ return moduleInfos;
43
+ };
33
44
  }
34
45
  }
@@ -0,0 +1,147 @@
1
+ package cn.reactnative.modules.update;
2
+
3
+ import static androidx.core.content.FileProvider.getUriForFile;
4
+ import android.content.Intent;
5
+ import android.net.Uri;
6
+ import android.os.Build;
7
+ import com.facebook.react.bridge.Promise;
8
+ import com.facebook.react.bridge.ReactApplicationContext;
9
+ import com.facebook.react.bridge.ReactContext;
10
+ import com.facebook.react.bridge.ReadableMap;
11
+ import com.facebook.react.bridge.WritableMap;
12
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
13
+ import java.io.File;
14
+ import java.util.HashMap;
15
+ import java.util.Map;
16
+
17
+ public class UpdateModule extends NativeUpdateSpec {
18
+ UpdateContext updateContext;
19
+ public static ReactApplicationContext mContext;
20
+ public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
21
+ super(reactContext);
22
+ this.updateContext = updateContext;
23
+ mContext = reactContext;
24
+ }
25
+
26
+ public UpdateModule(ReactApplicationContext reactContext) {
27
+ this(reactContext, new UpdateContext(reactContext.getApplicationContext()));
28
+ }
29
+
30
+ @Override
31
+ protected Map<String, Object> getTypedExportedConstants() {
32
+ final Map<String, Object> constants = new HashMap<>();
33
+ constants.put("downloadRootDir", updateContext.getRootDir());
34
+ constants.put("packageVersion", updateContext.getPackageVersion());
35
+ constants.put("currentVersion", updateContext.getCurrentVersion());
36
+ constants.put("buildTime", updateContext.getBuildTime());
37
+ constants.put("isUsingBundleUrl", updateContext.getIsUsingBundleUrl());
38
+ boolean isFirstTime = updateContext.isFirstTime();
39
+ constants.put("isFirstTime", isFirstTime);
40
+ if (isFirstTime) {
41
+ updateContext.clearFirstTime();
42
+ }
43
+ String rolledBackVersion = updateContext.rolledBackVersion();
44
+ constants.put("rolledBackVersion", rolledBackVersion);
45
+ if (rolledBackVersion != null) {
46
+ updateContext.clearRollbackMark();
47
+ }
48
+ constants.put("blockUpdate", updateContext.getBlockUpdate());
49
+ constants.put("uuid", updateContext.getKv("uuid"));
50
+ return constants;
51
+ }
52
+
53
+ @Override
54
+ public String getName() {
55
+ return UpdateModuleImpl.NAME;
56
+ }
57
+
58
+ @Override
59
+ public void downloadFullUpdate(ReadableMap options, final Promise promise) {
60
+ UpdateModuleImpl.downloadFullUpdate(this.updateContext,options,promise);
61
+ }
62
+
63
+ @Override
64
+ public void downloadAndInstallApk(ReadableMap options, final Promise promise) {
65
+ UpdateModuleImpl.downloadAndInstallApk(this.updateContext,options,promise);
66
+ }
67
+
68
+ public static void installApk(File toInstall) {
69
+ Uri apkUri;
70
+ Intent intent;
71
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
72
+ apkUri = getUriForFile(mContext, mContext.getPackageName() + ".pushy.fileprovider", toInstall);
73
+ intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
74
+ intent.setData(apkUri);
75
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
76
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
77
+ } else {
78
+ apkUri = Uri.fromFile(toInstall);
79
+ intent = new Intent(Intent.ACTION_VIEW);
80
+ intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
81
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
82
+ }
83
+ mContext.startActivity(intent);
84
+ }
85
+
86
+ @Override
87
+ public void downloadPatchFromPackage(ReadableMap options, final Promise promise) {
88
+ UpdateModuleImpl.downloadPatchFromPackage(updateContext,options,promise);
89
+ }
90
+
91
+ @Override
92
+ public void downloadPatchFromPpk(ReadableMap options, final Promise promise) {
93
+ UpdateModuleImpl.downloadPatchFromPpk(updateContext,options,promise);
94
+ }
95
+
96
+ @Override
97
+ public void reloadUpdate(ReadableMap options,Promise promise) {
98
+ UpdateModuleImpl.reloadUpdate(updateContext, mContext, options,promise);
99
+ }
100
+
101
+ @Override
102
+ public void setNeedUpdate(ReadableMap options,Promise promise) {
103
+ UpdateModuleImpl.setNeedUpdate(updateContext, options,promise);
104
+ }
105
+
106
+ @Override
107
+ public void markSuccess(Promise promise) {
108
+ UpdateModuleImpl.markSuccess(updateContext,promise);
109
+ }
110
+
111
+ @Override
112
+ public void setBlockUpdate(ReadableMap options,Promise promise) {
113
+ UpdateModuleImpl.setBlockUpdate(updateContext,options,promise);
114
+ }
115
+
116
+ @Override
117
+ public void setUuid(final String uuid, Promise promise) {
118
+ UpdateModuleImpl.setUuid(updateContext,uuid,promise);
119
+ }
120
+
121
+ @Override
122
+ public void setLocalHashInfo(final String hash, final String info, final Promise promise) {
123
+ UpdateModuleImpl.setLocalHashInfo(updateContext,hash,info,promise);
124
+ }
125
+
126
+ @Override
127
+ public void getLocalHashInfo(final String hash, final Promise promise) {
128
+ UpdateModuleImpl.getLocalHashInfo(updateContext,hash,promise);
129
+ }
130
+
131
+ @Override
132
+ public void addListener(String eventName) {
133
+ // Set up any upstream listeners or background tasks as necessary
134
+ }
135
+
136
+ @Override
137
+ public void removeListeners(double count) {
138
+ // Remove upstream listeners, stop unnecessary background tasks
139
+ }
140
+
141
+
142
+ /* 发送事件*/
143
+ public static void sendEvent(String eventName, WritableMap params) {
144
+ ((ReactContext) mContext).getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName,
145
+ params);
146
+ }
147
+ }
@@ -66,7 +66,7 @@ public class UpdateModule extends ReactContextBaseJavaModule {
66
66
 
67
67
  @Override
68
68
  public String getName() {
69
- return "RCTPushy";
69
+ return UpdateModuleImpl.NAME;
70
70
  }
71
71
 
72
72
  @ReactMethod
@@ -169,7 +169,7 @@ public class UpdateModule extends ReactContextBaseJavaModule {
169
169
  }
170
170
 
171
171
  @ReactMethod
172
- public void reloadUpdate(ReadableMap options) {
172
+ public void reloadUpdate(ReadableMap options, final Promise promise) {
173
173
  final String hash = options.getString("hash");
174
174
 
175
175
  UiThreadUtil.runOnUiThread(new Runnable() {
@@ -191,6 +191,7 @@ public class UpdateModule extends ReactContextBaseJavaModule {
191
191
  loadField.setAccessible(true);
192
192
  loadField.set(instanceManager, loader);
193
193
  } catch (Throwable err) {
194
+ promise.reject(err);
194
195
  Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile");
195
196
  jsBundleField.setAccessible(true);
196
197
  jsBundleField.set(instanceManager, UpdateContext.getBundleUrl(application));
@@ -198,11 +199,14 @@ public class UpdateModule extends ReactContextBaseJavaModule {
198
199
 
199
200
  try {
200
201
  instanceManager.recreateReactContextInBackground();
202
+ promise.resolve(null);
201
203
  } catch (Throwable err) {
202
204
  activity.recreate();
205
+ promise.reject(err);
203
206
  }
204
207
 
205
208
  } catch (Throwable err) {
209
+ promise.reject(err);
206
210
  Log.e("pushy", "switchVersion failed", err);
207
211
  }
208
212
  }
@@ -0,0 +1,12 @@
1
+ /** @type {import('@jest/types').Config.InitialOptions} */
2
+ module.exports = {
3
+ rootDir: '..',
4
+ testMatch: ['<rootDir>/e2e/**/*.test.js'],
5
+ testTimeout: 120000,
6
+ maxWorkers: 1,
7
+ globalSetup: 'detox/runners/jest/globalSetup',
8
+ globalTeardown: 'detox/runners/jest/globalTeardown',
9
+ reporters: ['detox/runners/jest/reporter'],
10
+ testEnvironment: 'detox/runners/jest/testEnvironment',
11
+ verbose: true,
12
+ };