@bravemobile/react-native-code-push 12.4.1 → 13.0.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/CodePush.podspec +14 -1
- package/README.md +3 -0
- package/android/app/build.gradle +7 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +45 -10
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +67 -86
- package/cli/dist/functions/runHermesEmitBinaryCommand.js +50 -26
- package/cli/functions/runHermesEmitBinaryCommand.ts +55 -25
- package/ios/CodePush/CodePush.h +40 -8
- package/ios/CodePush/{CodePush.m → CodePush.mm} +61 -62
- package/ios/CodePush.xcodeproj/project.pbxproj +6 -6
- package/package.json +19 -2
- package/react-native.config.js +3 -1
- package/src/CodePush.js +144 -93
- package/src/native/NativeCodePush.ts +162 -0
- package/src/package-mixins.js +4 -9
- package/src/specs/NativeCodePush.ts +43 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java +0 -102
- package/src/AlertAdapter.js +0 -24
package/CodePush.podspec
CHANGED
|
@@ -14,7 +14,7 @@ Pod::Spec.new do |s|
|
|
|
14
14
|
s.tvos.deployment_target = '15.5'
|
|
15
15
|
s.preserve_paths = '*.js'
|
|
16
16
|
s.library = 'z'
|
|
17
|
-
s.source_files = 'ios/CodePush/*.{h,m}'
|
|
17
|
+
s.source_files = 'ios/CodePush/*.{h,m,mm}'
|
|
18
18
|
s.public_header_files = ['ios/CodePush/CodePush.h']
|
|
19
19
|
|
|
20
20
|
# Note: Even though there are copy/pasted versions of some of these dependencies in the repo,
|
|
@@ -22,4 +22,17 @@ Pod::Spec.new do |s|
|
|
|
22
22
|
# linked properly at a parent workspace level.
|
|
23
23
|
s.dependency 'React-Core'
|
|
24
24
|
s.dependency 'SSZipArchive', '~> 2.5.5'
|
|
25
|
+
|
|
26
|
+
if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
|
27
|
+
s.compiler_flags = '-DRCT_NEW_ARCH_ENABLED=1'
|
|
28
|
+
s.pod_target_xcconfig = {
|
|
29
|
+
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
|
|
30
|
+
'HEADER_SEARCH_PATHS' => "\"$(PODS_ROOT)/Headers/Public/ReactCodegen\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCodegen/ReactCodegen.framework/Headers\""
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
s.dependency 'ReactCodegen'
|
|
34
|
+
s.dependency 'RCTRequired'
|
|
35
|
+
s.dependency 'RCTTypeSafety'
|
|
36
|
+
s.dependency 'ReactCommon/turbomodule/core'
|
|
37
|
+
end
|
|
25
38
|
end
|
package/README.md
CHANGED
|
@@ -13,6 +13,9 @@ Supports React Native 0.77 ~ 0.86.
|
|
|
13
13
|
> [!NOTE]
|
|
14
14
|
> If you are using React Native 0.76 or lower, please use version `12.0.2` of this library.
|
|
15
15
|
|
|
16
|
+
> [!IMPORTANT]
|
|
17
|
+
> `13.0.0` migrates the native module to TurboModule. A `13.0.0` binary only runs OTA bundles built with `13.0.0` or later, so ship a new binary version and start its release history fresh when you upgrade.
|
|
18
|
+
|
|
16
19
|
(Tested on the React Native CLI template apps)
|
|
17
20
|
|
|
18
21
|
### ✅ Requirements
|
package/android/app/build.gradle
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
apply plugin: "com.android.library"
|
|
2
|
+
apply plugin: "com.facebook.react"
|
|
2
3
|
|
|
3
4
|
def DEFAULT_COMPILE_SDK_VERSION = 26
|
|
4
5
|
def DEFAULT_BUILD_TOOLS_VERSION = "26.0.3"
|
|
5
6
|
def DEFAULT_TARGET_SDK_VERSION = 26
|
|
6
7
|
def DEFAULT_MIN_SDK_VERSION = 16
|
|
7
8
|
|
|
9
|
+
react {
|
|
10
|
+
jsRootDir = file("../..")
|
|
11
|
+
libraryName = "RNCodePushSpec"
|
|
12
|
+
codegenJavaPackageName = "com.microsoft.codepush.react"
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
android {
|
|
9
16
|
namespace "com.microsoft.codepush.react"
|
|
10
17
|
|
|
@@ -4,18 +4,25 @@ import android.content.Context;
|
|
|
4
4
|
import android.content.pm.PackageInfo;
|
|
5
5
|
import android.content.pm.PackageManager;
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import androidx.annotation.NonNull;
|
|
8
|
+
import androidx.annotation.Nullable;
|
|
9
|
+
|
|
10
|
+
import com.facebook.react.TurboReactPackage;
|
|
8
11
|
import com.facebook.react.bridge.NativeModule;
|
|
9
12
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
13
|
+
import com.facebook.react.module.model.ReactModuleInfo;
|
|
14
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
|
10
15
|
import com.facebook.react.uimanager.ViewManager;
|
|
11
16
|
|
|
12
17
|
import org.json.JSONException;
|
|
13
18
|
import org.json.JSONObject;
|
|
14
19
|
|
|
15
20
|
import java.util.ArrayList;
|
|
21
|
+
import java.util.HashMap;
|
|
16
22
|
import java.util.List;
|
|
23
|
+
import java.util.Map;
|
|
17
24
|
|
|
18
|
-
public class CodePush
|
|
25
|
+
public class CodePush extends TurboReactPackage {
|
|
19
26
|
|
|
20
27
|
private static boolean sIsRunningBinaryVersion = false;
|
|
21
28
|
private static boolean sNeedToReportRollback = false;
|
|
@@ -300,17 +307,45 @@ public class CodePush implements ReactPackage {
|
|
|
300
307
|
}
|
|
301
308
|
|
|
302
309
|
@Override
|
|
303
|
-
public
|
|
304
|
-
|
|
305
|
-
|
|
310
|
+
public @Nullable NativeModule getModule(String name, ReactApplicationContext reactApplicationContext) {
|
|
311
|
+
if (!CodePushNativeModule.NAME.equals(name)) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return new CodePushNativeModule(
|
|
316
|
+
reactApplicationContext,
|
|
317
|
+
this,
|
|
318
|
+
mUpdateManager,
|
|
319
|
+
mTelemetryManager,
|
|
320
|
+
mSettingsManager
|
|
321
|
+
);
|
|
322
|
+
}
|
|
306
323
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
324
|
+
@Override
|
|
325
|
+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
|
|
326
|
+
return new ReactModuleInfoProvider() {
|
|
327
|
+
@Override
|
|
328
|
+
public Map<String, ReactModuleInfo> getReactModuleInfos() {
|
|
329
|
+
Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
|
|
330
|
+
reactModuleInfoMap.put(
|
|
331
|
+
CodePushNativeModule.NAME,
|
|
332
|
+
new ReactModuleInfo(
|
|
333
|
+
CodePushNativeModule.NAME,
|
|
334
|
+
CodePushNativeModule.class.getName(),
|
|
335
|
+
false,
|
|
336
|
+
false,
|
|
337
|
+
false,
|
|
338
|
+
false,
|
|
339
|
+
true
|
|
340
|
+
)
|
|
341
|
+
);
|
|
342
|
+
return reactModuleInfoMap;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
311
345
|
}
|
|
346
|
+
|
|
312
347
|
@Override
|
|
313
|
-
public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
|
|
348
|
+
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
|
|
314
349
|
return new ArrayList<>();
|
|
315
350
|
}
|
|
316
351
|
}
|
|
@@ -2,7 +2,6 @@ package com.microsoft.codepush.react;
|
|
|
2
2
|
|
|
3
3
|
import android.app.Activity;
|
|
4
4
|
import android.content.SharedPreferences;
|
|
5
|
-
import android.os.AsyncTask;
|
|
6
5
|
import android.os.Handler;
|
|
7
6
|
import android.os.Looper;
|
|
8
7
|
import android.view.View;
|
|
@@ -20,11 +19,11 @@ import com.facebook.react.bridge.JSBundleLoader;
|
|
|
20
19
|
import com.facebook.react.bridge.LifecycleEventListener;
|
|
21
20
|
import com.facebook.react.bridge.Promise;
|
|
22
21
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
23
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
24
22
|
import com.facebook.react.bridge.ReactMethod;
|
|
25
23
|
import com.facebook.react.bridge.ReadableMap;
|
|
26
24
|
import com.facebook.react.bridge.WritableMap;
|
|
27
25
|
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
|
|
26
|
+
import com.facebook.react.module.annotations.ReactModule;
|
|
28
27
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
29
28
|
import com.facebook.react.modules.core.ReactChoreographer;
|
|
30
29
|
import com.facebook.react.runtime.ReactHostDelegate;
|
|
@@ -37,15 +36,19 @@ import java.io.IOException;
|
|
|
37
36
|
import java.lang.reflect.Field;
|
|
38
37
|
import java.util.ArrayList;
|
|
39
38
|
import java.util.Date;
|
|
40
|
-
import java.util.HashMap;
|
|
41
|
-
import java.util.Map;
|
|
42
39
|
import java.util.UUID;
|
|
40
|
+
import java.util.concurrent.ExecutorService;
|
|
41
|
+
import java.util.concurrent.Executors;
|
|
42
|
+
|
|
43
|
+
@ReactModule(name = CodePushNativeModule.NAME)
|
|
44
|
+
public class CodePushNativeModule extends NativeCodePushSpec {
|
|
45
|
+
public static final String NAME = "CodePush";
|
|
43
46
|
|
|
44
|
-
public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
45
47
|
private String mBinaryContentsHash = null;
|
|
46
48
|
private String mClientUniqueId = null;
|
|
47
49
|
private LifecycleEventListener mLifecycleEventListener = null;
|
|
48
50
|
private int mMinimumBackgroundDuration = 0;
|
|
51
|
+
private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor();
|
|
49
52
|
|
|
50
53
|
private CodePush mCodePush;
|
|
51
54
|
private SettingsManager mSettingsManager;
|
|
@@ -76,24 +79,15 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
@Override
|
|
79
|
-
public
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
constants.put("codePushInstallModeImmediate", CodePushInstallMode.IMMEDIATE.getValue());
|
|
83
|
-
constants.put("codePushInstallModeOnNextRestart", CodePushInstallMode.ON_NEXT_RESTART.getValue());
|
|
84
|
-
constants.put("codePushInstallModeOnNextResume", CodePushInstallMode.ON_NEXT_RESUME.getValue());
|
|
85
|
-
constants.put("codePushInstallModeOnNextSuspend", CodePushInstallMode.ON_NEXT_SUSPEND.getValue());
|
|
86
|
-
|
|
87
|
-
constants.put("codePushUpdateStateRunning", CodePushUpdateState.RUNNING.getValue());
|
|
88
|
-
constants.put("codePushUpdateStatePending", CodePushUpdateState.PENDING.getValue());
|
|
89
|
-
constants.put("codePushUpdateStateLatest", CodePushUpdateState.LATEST.getValue());
|
|
90
|
-
|
|
91
|
-
return constants;
|
|
82
|
+
public String getName() {
|
|
83
|
+
return NAME;
|
|
92
84
|
}
|
|
93
85
|
|
|
94
86
|
@Override
|
|
95
|
-
public
|
|
96
|
-
|
|
87
|
+
public void invalidate() {
|
|
88
|
+
clearLifecycleEventListener();
|
|
89
|
+
mBackgroundExecutor.shutdownNow();
|
|
90
|
+
super.invalidate();
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
private void loadBundleLegacy() {
|
|
@@ -265,6 +259,21 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
265
259
|
return null;
|
|
266
260
|
}
|
|
267
261
|
|
|
262
|
+
private void executeInBackground(Runnable runnable) {
|
|
263
|
+
mBackgroundExecutor.execute(runnable);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private void emitDownloadProgressEvent(DownloadProgress downloadProgress) {
|
|
267
|
+
if (mEventEmitterCallback != null) {
|
|
268
|
+
emitOnDownloadProgress(downloadProgress.createWritableMap());
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
getReactApplicationContext()
|
|
273
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
274
|
+
.emit(CodePushConstants.DOWNLOAD_PROGRESS_EVENT_NAME, downloadProgress.createWritableMap());
|
|
275
|
+
}
|
|
276
|
+
|
|
268
277
|
private void restartAppInternal(boolean onlyIfUpdateIsPending) {
|
|
269
278
|
if (this._restartInProgress) {
|
|
270
279
|
CodePushUtils.log("Restart request queued until the current restart is completed");
|
|
@@ -292,7 +301,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
292
301
|
}
|
|
293
302
|
|
|
294
303
|
@ReactMethod
|
|
295
|
-
public void allow(
|
|
304
|
+
public void allow() {
|
|
296
305
|
CodePushUtils.log("Re-allowing restarts");
|
|
297
306
|
this._allowed = true;
|
|
298
307
|
|
|
@@ -302,42 +311,29 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
302
311
|
this._restartQueue.remove(0);
|
|
303
312
|
this.restartAppInternal(buf);
|
|
304
313
|
}
|
|
305
|
-
|
|
306
|
-
promise.resolve(null);
|
|
307
|
-
return;
|
|
308
314
|
}
|
|
309
315
|
|
|
310
316
|
@ReactMethod
|
|
311
|
-
public void clearPendingRestart(
|
|
317
|
+
public void clearPendingRestart() {
|
|
312
318
|
this._restartQueue.clear();
|
|
313
|
-
promise.resolve(null);
|
|
314
|
-
return;
|
|
315
319
|
}
|
|
316
320
|
|
|
317
321
|
@ReactMethod
|
|
318
|
-
public void disallow(
|
|
322
|
+
public void disallow() {
|
|
319
323
|
CodePushUtils.log("Disallowing restarts");
|
|
320
324
|
this._allowed = false;
|
|
321
|
-
promise.resolve(null);
|
|
322
|
-
return;
|
|
323
325
|
}
|
|
324
326
|
|
|
325
327
|
@ReactMethod
|
|
326
|
-
public void restartApp(boolean onlyIfUpdateIsPending
|
|
327
|
-
|
|
328
|
-
restartAppInternal(onlyIfUpdateIsPending);
|
|
329
|
-
promise.resolve(null);
|
|
330
|
-
} catch(CodePushUnknownException e) {
|
|
331
|
-
CodePushUtils.log(e);
|
|
332
|
-
promise.reject(e);
|
|
333
|
-
}
|
|
328
|
+
public void restartApp(boolean onlyIfUpdateIsPending) {
|
|
329
|
+
restartAppInternal(onlyIfUpdateIsPending);
|
|
334
330
|
}
|
|
335
331
|
|
|
336
332
|
@ReactMethod
|
|
337
333
|
public void downloadUpdate(final ReadableMap updatePackage, final boolean notifyProgress, final Promise promise) {
|
|
338
|
-
|
|
334
|
+
executeInBackground(new Runnable() {
|
|
339
335
|
@Override
|
|
340
|
-
|
|
336
|
+
public void run() {
|
|
341
337
|
try {
|
|
342
338
|
JSONObject mutableUpdatePackage = CodePushUtils.convertReadableToJsonObject(updatePackage);
|
|
343
339
|
mUpdateManager.downloadPackage(mutableUpdatePackage, mCodePush.getAssetsBundleFileName(), new DownloadProgressCallback() {
|
|
@@ -347,9 +343,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
347
343
|
new DownloadProgressEventDispatcher.EventEmitter() {
|
|
348
344
|
@Override
|
|
349
345
|
public void emit(DownloadProgress downloadProgress) {
|
|
350
|
-
|
|
351
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
352
|
-
.emit(CodePushConstants.DOWNLOAD_PROGRESS_EVENT_NAME, downloadProgress.createWritableMap());
|
|
346
|
+
emitDownloadProgressEvent(downloadProgress);
|
|
353
347
|
}
|
|
354
348
|
});
|
|
355
349
|
|
|
@@ -399,12 +393,8 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
399
393
|
CodePushUtils.log(e);
|
|
400
394
|
promise.reject(e);
|
|
401
395
|
}
|
|
402
|
-
|
|
403
|
-
return null;
|
|
404
396
|
}
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
397
|
+
});
|
|
408
398
|
}
|
|
409
399
|
|
|
410
400
|
@ReactMethod
|
|
@@ -429,16 +419,17 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
429
419
|
}
|
|
430
420
|
|
|
431
421
|
@ReactMethod
|
|
432
|
-
public void getUpdateMetadata(final
|
|
433
|
-
|
|
422
|
+
public void getUpdateMetadata(final double updateStateValue, final Promise promise) {
|
|
423
|
+
executeInBackground(new Runnable() {
|
|
434
424
|
@Override
|
|
435
|
-
|
|
425
|
+
public void run() {
|
|
436
426
|
try {
|
|
427
|
+
int updateState = (int) updateStateValue;
|
|
437
428
|
JSONObject currentPackage = mUpdateManager.getCurrentPackage();
|
|
438
429
|
|
|
439
430
|
if (currentPackage == null) {
|
|
440
431
|
promise.resolve(null);
|
|
441
|
-
return
|
|
432
|
+
return;
|
|
442
433
|
}
|
|
443
434
|
|
|
444
435
|
Boolean currentUpdateIsPending = false;
|
|
@@ -459,7 +450,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
459
450
|
|
|
460
451
|
if (previousPackage == null) {
|
|
461
452
|
promise.resolve(null);
|
|
462
|
-
return
|
|
453
|
+
return;
|
|
463
454
|
}
|
|
464
455
|
|
|
465
456
|
promise.resolve(CodePushUtils.convertJsonObjectToWritable(previousPackage));
|
|
@@ -488,19 +479,15 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
488
479
|
CodePushUtils.log(e);
|
|
489
480
|
promise.reject(e);
|
|
490
481
|
}
|
|
491
|
-
|
|
492
|
-
return null;
|
|
493
482
|
}
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
483
|
+
});
|
|
497
484
|
}
|
|
498
485
|
|
|
499
486
|
@ReactMethod
|
|
500
487
|
public void getNewStatusReport(final Promise promise) {
|
|
501
|
-
|
|
488
|
+
executeInBackground(new Runnable() {
|
|
502
489
|
@Override
|
|
503
|
-
|
|
490
|
+
public void run() {
|
|
504
491
|
try {
|
|
505
492
|
if (mCodePush.needToReportRollback()) {
|
|
506
493
|
mCodePush.setNeedToReportRollback(false);
|
|
@@ -512,7 +499,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
512
499
|
WritableMap failedStatusReport = mTelemetryManager.getRollbackReport(lastFailedPackage);
|
|
513
500
|
if (failedStatusReport != null) {
|
|
514
501
|
promise.resolve(failedStatusReport);
|
|
515
|
-
return
|
|
502
|
+
return;
|
|
516
503
|
}
|
|
517
504
|
} catch (JSONException e) {
|
|
518
505
|
throw new CodePushUnknownException("Unable to read failed updates information stored in SharedPreferences.", e);
|
|
@@ -524,41 +511,40 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
524
511
|
WritableMap newPackageStatusReport = mTelemetryManager.getUpdateReport(CodePushUtils.convertJsonObjectToWritable(currentPackage));
|
|
525
512
|
if (newPackageStatusReport != null) {
|
|
526
513
|
promise.resolve(newPackageStatusReport);
|
|
527
|
-
return
|
|
514
|
+
return;
|
|
528
515
|
}
|
|
529
516
|
}
|
|
530
517
|
} else if (mCodePush.isRunningBinaryVersion()) {
|
|
531
518
|
WritableMap newAppVersionStatusReport = mTelemetryManager.getBinaryUpdateReport(mCodePush.getAppVersion());
|
|
532
519
|
if (newAppVersionStatusReport != null) {
|
|
533
520
|
promise.resolve(newAppVersionStatusReport);
|
|
534
|
-
return
|
|
521
|
+
return;
|
|
535
522
|
}
|
|
536
523
|
} else {
|
|
537
524
|
WritableMap retryStatusReport = mTelemetryManager.getRetryStatusReport();
|
|
538
525
|
if (retryStatusReport != null) {
|
|
539
526
|
promise.resolve(retryStatusReport);
|
|
540
|
-
return
|
|
527
|
+
return;
|
|
541
528
|
}
|
|
542
529
|
}
|
|
543
530
|
|
|
544
|
-
promise.resolve(
|
|
531
|
+
promise.resolve(null);
|
|
545
532
|
} catch(CodePushUnknownException e) {
|
|
546
533
|
CodePushUtils.log(e);
|
|
547
534
|
promise.reject(e);
|
|
548
535
|
}
|
|
549
|
-
return null;
|
|
550
536
|
}
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
537
|
+
});
|
|
554
538
|
}
|
|
555
539
|
|
|
556
540
|
@ReactMethod
|
|
557
|
-
public void installUpdate(final ReadableMap updatePackage, final
|
|
558
|
-
|
|
541
|
+
public void installUpdate(final ReadableMap updatePackage, final double installModeValue, final double minimumBackgroundDurationValue, final Promise promise) {
|
|
542
|
+
executeInBackground(new Runnable() {
|
|
559
543
|
@Override
|
|
560
|
-
|
|
544
|
+
public void run() {
|
|
561
545
|
try {
|
|
546
|
+
int installMode = (int) installModeValue;
|
|
547
|
+
int minimumBackgroundDuration = (int) minimumBackgroundDurationValue;
|
|
562
548
|
mUpdateManager.installPackage(CodePushUtils.convertReadableToJsonObject(updatePackage), mSettingsManager.isPendingUpdate(null));
|
|
563
549
|
|
|
564
550
|
String pendingHash = CodePushUtils.tryGetString(updatePackage, CodePushConstants.PACKAGE_HASH_KEY);
|
|
@@ -568,13 +554,12 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
568
554
|
mSettingsManager.savePendingUpdate(pendingHash, /* isLoading */false);
|
|
569
555
|
}
|
|
570
556
|
|
|
571
|
-
if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue()
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
557
|
+
if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue()
|
|
558
|
+
// We also add the resume listener if the installMode is IMMEDIATE, because
|
|
559
|
+
// if the current activity is backgrounded, we want to reload the bundle when
|
|
560
|
+
// it comes back into the foreground.
|
|
561
|
+
|| installMode == CodePushInstallMode.IMMEDIATE.getValue()
|
|
562
|
+
|| installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
|
|
578
563
|
// Store the minimum duration on the native module as an instance
|
|
579
564
|
// variable instead of relying on a closure below, so that any
|
|
580
565
|
// subsequent resume-based installs could override it.
|
|
@@ -628,17 +613,13 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
628
613
|
}
|
|
629
614
|
}
|
|
630
615
|
|
|
631
|
-
promise.resolve(
|
|
616
|
+
promise.resolve(null);
|
|
632
617
|
} catch(CodePushUnknownException e) {
|
|
633
618
|
CodePushUtils.log(e);
|
|
634
619
|
promise.reject(e);
|
|
635
620
|
}
|
|
636
|
-
|
|
637
|
-
return null;
|
|
638
621
|
}
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
622
|
+
});
|
|
642
623
|
}
|
|
643
624
|
|
|
644
625
|
@ReactMethod
|
|
@@ -695,7 +676,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
695
676
|
public void notifyApplicationReady(Promise promise) {
|
|
696
677
|
try {
|
|
697
678
|
mSettingsManager.removePendingUpdate();
|
|
698
|
-
promise.resolve(
|
|
679
|
+
promise.resolve(null);
|
|
699
680
|
} catch(CodePushUnknownException e) {
|
|
700
681
|
CodePushUtils.log(e);
|
|
701
682
|
promise.reject(e);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import childProcess from "child_process";
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import path from "path";
|
|
7
|
+
import { createRequire } from "node:module";
|
|
7
8
|
import shell from "shelljs";
|
|
8
9
|
/**
|
|
9
10
|
* Run Hermes compile CLI command
|
|
@@ -12,9 +13,10 @@ import shell from "shelljs";
|
|
|
12
13
|
* @param outputPath {string} Path to output .hbc file
|
|
13
14
|
* @param sourcemapOutput {string} Path to output sourcemap file (Warning: if sourcemapOutput points to the outputPath, the sourcemap will be included in the CodePush bundle and increase the deployment size)
|
|
14
15
|
* @param extraHermesFlags {string[]} Additional options to pass to `hermesc` command
|
|
16
|
+
* @param projectRoot {string} Root directory of the target app project used to resolve the app's React Native module and locate the matching Hermes compiler. Defaults to the current working directory.
|
|
15
17
|
* @return {Promise<void>}
|
|
16
18
|
*/
|
|
17
|
-
export async function runHermesEmitBinaryCommand(bundleName, outputPath, sourcemapOutput, extraHermesFlags = []) {
|
|
19
|
+
export async function runHermesEmitBinaryCommand(bundleName, outputPath, sourcemapOutput, extraHermesFlags = [], projectRoot = process.cwd()) {
|
|
18
20
|
const hermesArgs = [
|
|
19
21
|
'-emit-binary',
|
|
20
22
|
'-out',
|
|
@@ -28,7 +30,7 @@ export async function runHermesEmitBinaryCommand(bundleName, outputPath, sourcem
|
|
|
28
30
|
console.log('Converting JS bundle to byte code via Hermes, running command:\n');
|
|
29
31
|
return new Promise((resolve, reject) => {
|
|
30
32
|
try {
|
|
31
|
-
const hermesCommand = getHermesCommand();
|
|
33
|
+
const hermesCommand = getHermesCommand(projectRoot);
|
|
32
34
|
const disableAllWarningsArg = '-w';
|
|
33
35
|
shell.exec(`${hermesCommand} ${hermesArgs.join(' ')} ${disableAllWarningsArg}`);
|
|
34
36
|
// Copy HBC bundle to overwrite JS bundle
|
|
@@ -47,7 +49,7 @@ export async function runHermesEmitBinaryCommand(bundleName, outputPath, sourcem
|
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
51
|
// compose-source-maps.js file path
|
|
50
|
-
const composeSourceMapsPath = getComposeSourceMapsPath();
|
|
52
|
+
const composeSourceMapsPath = getComposeSourceMapsPath(projectRoot);
|
|
51
53
|
if (composeSourceMapsPath === null) {
|
|
52
54
|
throw new Error('react-native compose-source-maps.js scripts is not found');
|
|
53
55
|
}
|
|
@@ -87,7 +89,7 @@ export async function runHermesEmitBinaryCommand(bundleName, outputPath, sourcem
|
|
|
87
89
|
});
|
|
88
90
|
});
|
|
89
91
|
}
|
|
90
|
-
function getHermesCommand() {
|
|
92
|
+
function getHermesCommand(projectRoot) {
|
|
91
93
|
const fileExists = (file) => {
|
|
92
94
|
try {
|
|
93
95
|
return fs.statSync(file).isFile();
|
|
@@ -96,7 +98,7 @@ function getHermesCommand() {
|
|
|
96
98
|
return false;
|
|
97
99
|
}
|
|
98
100
|
};
|
|
99
|
-
const hermescExecutable = path.join(getHermesCompilerPath(), getHermesOSBin(), getHermesOSExe());
|
|
101
|
+
const hermescExecutable = path.join(getHermesCompilerPath(projectRoot), getHermesOSBin(), getHermesOSExe());
|
|
100
102
|
if (fileExists(hermescExecutable)) {
|
|
101
103
|
return hermescExecutable;
|
|
102
104
|
}
|
|
@@ -124,45 +126,67 @@ function getHermesOSExe() {
|
|
|
124
126
|
return hermesExecutableName;
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
|
-
function getComposeSourceMapsPath() {
|
|
129
|
+
function getComposeSourceMapsPath(projectRoot) {
|
|
128
130
|
// detect if compose-source-maps.js script exists
|
|
129
|
-
const composeSourceMaps = path.join(getReactNativePackagePath(), 'scripts', 'compose-source-maps.js');
|
|
131
|
+
const composeSourceMaps = path.join(getReactNativePackagePath(projectRoot), 'scripts', 'compose-source-maps.js');
|
|
130
132
|
if (fs.existsSync(composeSourceMaps)) {
|
|
131
133
|
return composeSourceMaps;
|
|
132
134
|
}
|
|
133
135
|
return null;
|
|
134
136
|
}
|
|
135
|
-
function getReactNativePackagePath() {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
"require.resolve('react-native/package.json')",
|
|
139
|
-
]);
|
|
140
|
-
const packagePath = path.dirname(result.stdout.toString());
|
|
141
|
-
if (result.status === 0 && directoryExistsSync(packagePath)) {
|
|
137
|
+
function getReactNativePackagePath(projectRoot) {
|
|
138
|
+
const packagePath = resolvePackageRoot(projectRoot, 'react-native');
|
|
139
|
+
if (packagePath !== null) {
|
|
142
140
|
return packagePath;
|
|
143
141
|
}
|
|
144
|
-
return path.join('node_modules', 'react-native');
|
|
142
|
+
return path.join(projectRoot, 'node_modules', 'react-native');
|
|
145
143
|
}
|
|
146
|
-
function getHermescDirPathInHermesCompilerPackage() {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
]);
|
|
151
|
-
const packagePath = path.dirname(result.stdout.toString());
|
|
152
|
-
const hermescDirPath = path.join(packagePath, 'hermesc');
|
|
153
|
-
if (result.status === 0 && directoryExistsSync(hermescDirPath)) {
|
|
144
|
+
function getHermescDirPathInHermesCompilerPackage(projectRoot) {
|
|
145
|
+
const reactNativePackagePath = getReactNativePackagePath(projectRoot);
|
|
146
|
+
const hermescDirPath = path.join(path.dirname(reactNativePackagePath), 'hermes-compiler', 'hermesc');
|
|
147
|
+
if (directoryExistsSync(hermescDirPath)) {
|
|
154
148
|
return hermescDirPath;
|
|
155
149
|
}
|
|
156
150
|
return null;
|
|
157
151
|
}
|
|
158
|
-
function getHermesCompilerPath() {
|
|
159
|
-
const hermescDirPath = getHermescDirPathInHermesCompilerPackage();
|
|
152
|
+
function getHermesCompilerPath(projectRoot) {
|
|
153
|
+
const hermescDirPath = getHermescDirPathInHermesCompilerPackage(projectRoot);
|
|
160
154
|
if (hermescDirPath) {
|
|
161
155
|
// Since react-native 0.83, Hermes compiler executables are in 'hermes-compiler' package
|
|
162
156
|
return hermescDirPath;
|
|
163
157
|
}
|
|
164
158
|
else {
|
|
165
|
-
return path.join(getReactNativePackagePath(), 'sdks', 'hermesc');
|
|
159
|
+
return path.join(getReactNativePackagePath(projectRoot), 'sdks', 'hermesc');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function resolvePackageRoot(projectRoot, packageName) {
|
|
163
|
+
try {
|
|
164
|
+
const projectRequire = createRequire(path.join(projectRoot, 'package.json'));
|
|
165
|
+
const resolvedPath = projectRequire.resolve(packageName);
|
|
166
|
+
return findPackageRoot(packageName, resolvedPath);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function findPackageRoot(packageName, resolvedPath) {
|
|
173
|
+
let currentPath = path.dirname(resolvedPath);
|
|
174
|
+
while (true) {
|
|
175
|
+
const packageJsonPath = path.join(currentPath, 'package.json');
|
|
176
|
+
try {
|
|
177
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
178
|
+
if (packageJson.name === packageName) {
|
|
179
|
+
return currentPath;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Continue traversing upward until the package root is found.
|
|
184
|
+
}
|
|
185
|
+
const parentPath = path.dirname(currentPath);
|
|
186
|
+
if (parentPath === currentPath) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
currentPath = parentPath;
|
|
166
190
|
}
|
|
167
191
|
}
|
|
168
192
|
function directoryExistsSync(dirname) {
|