@swyng/react-native-code-push 1.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/AlertAdapter.js +24 -0
- package/CLAUDE.md +57 -0
- package/CONTRIBUTING.md +134 -0
- package/CodePush.js +671 -0
- package/CodePush.podspec +28 -0
- package/LICENSE.md +13 -0
- package/README.md +323 -0
- package/SECURITY.md +24 -0
- package/android/app/build.gradle +48 -0
- package/android/app/proguard-rules.pro +33 -0
- package/android/app/src/main/AndroidManifest.xml +5 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePush.java +426 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushConstants.java +35 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushDialog.java +102 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushInstallMode.java +16 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushInvalidPublicKeyException.java +12 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushInvalidUpdateException.java +7 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushMalformedDataException.java +12 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushNativeModule.java +781 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushNotInitializedException.java +12 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushTelemetryManager.java +175 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushUnknownException.java +12 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushUpdateManager.java +383 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushUpdateState.java +15 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushUpdateUtils.java +275 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/CodePushUtils.java +238 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/DownloadProgress.java +30 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/DownloadProgressCallback.java +5 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/FileUtils.java +203 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/ReactHostHolder.java +11 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/SettingsManager.java +173 -0
- package/android/app/src/main/java/com/swyngpush/codepush/react/TLSSocketFactory.java +72 -0
- package/android/build.gradle +23 -0
- package/android/codepush.gradle +162 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradle.properties +18 -0
- package/android/gradlew +164 -0
- package/android/gradlew.bat +90 -0
- package/android/settings.gradle +2 -0
- package/docs/LOAD_BUNDLE_DELAY_ANALYSIS.md +68 -0
- package/docs/api-android.md +52 -0
- package/docs/api-ios.md +31 -0
- package/docs/api-js.md +592 -0
- package/docs/multi-deployment-testing-android.md +55 -0
- package/docs/multi-deployment-testing-ios.md +59 -0
- package/docs/setup-android.md +121 -0
- package/docs/setup-ios.md +141 -0
- package/docs/setup-windows.md +121 -0
- package/expo.js +347 -0
- package/ios/CodePush/Base64/Base64/MF_Base64Additions.h +34 -0
- package/ios/CodePush/Base64/Base64/MF_Base64Additions.m +252 -0
- package/ios/CodePush/Base64/README.md +47 -0
- package/ios/CodePush/CodePush.h +235 -0
- package/ios/CodePush/CodePush.m +1131 -0
- package/ios/CodePush/CodePushConfig.m +115 -0
- package/ios/CodePush/CodePushDownloadHandler.m +130 -0
- package/ios/CodePush/CodePushErrorUtils.m +20 -0
- package/ios/CodePush/CodePushPackage.m +602 -0
- package/ios/CodePush/CodePushTelemetryManager.m +175 -0
- package/ios/CodePush/CodePushUpdateUtils.m +376 -0
- package/ios/CodePush/CodePushUtils.m +9 -0
- package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithm.h +69 -0
- package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.h +16 -0
- package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.m +51 -0
- package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.h +15 -0
- package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.m +55 -0
- package/ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.h +24 -0
- package/ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.m +41 -0
- package/ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.h +28 -0
- package/ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.m +205 -0
- package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.h +103 -0
- package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.m +322 -0
- package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.h +37 -0
- package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.m +145 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.h +35 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.m +551 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTRSAlgorithm.h +23 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.h +43 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.m +230 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.h +31 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.m +113 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.h +38 -0
- package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +500 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaim.h +18 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaim.m +214 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.h +23 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.m +29 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.h +19 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.m +68 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.h +18 -0
- package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.m +72 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.h +67 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.m +111 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.h +119 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.m +307 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.h +94 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.m +619 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.h +164 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.m +514 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding.h +24 -0
- package/ios/CodePush/JWT/Core/Coding/JWTCoding.m +11 -0
- package/ios/CodePush/JWT/Core/FrameworkSupplement/JWT.h +52 -0
- package/ios/CodePush/JWT/Core/FrameworkSupplement/Map.modulemap +5 -0
- package/ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.h +28 -0
- package/ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.m +70 -0
- package/ios/CodePush/JWT/Core/Supplement/JWTDeprecations.h +22 -0
- package/ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.h +34 -0
- package/ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.m +73 -0
- package/ios/CodePush/JWT/LICENSE +19 -0
- package/ios/CodePush/JWT/README.md +489 -0
- package/ios/CodePush/RCTConvert+CodePushInstallMode.m +20 -0
- package/ios/CodePush/RCTConvert+CodePushUpdateState.m +20 -0
- package/ios/CodePush/SSZipArchive/Info.plist +26 -0
- package/ios/CodePush/SSZipArchive/README.md +1 -0
- package/ios/CodePush/SSZipArchive/SSZipArchive.h +178 -0
- package/ios/CodePush/SSZipArchive/SSZipArchive.m +1496 -0
- package/ios/CodePush/SSZipArchive/SSZipCommon.h +71 -0
- package/ios/CodePush/SSZipArchive/Supporting Files/PrivacyInfo.xcprivacy +23 -0
- package/ios/CodePush/SSZipArchive/include/ZipArchive.h +25 -0
- package/ios/CodePush/SSZipArchive/minizip/LICENSE +17 -0
- package/ios/CodePush/SSZipArchive/minizip/mz.h +273 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_compat.c +1306 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_compat.h +346 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_crypt.c +187 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_crypt.h +65 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_crypt_apple.c +526 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_os.c +348 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_os.h +176 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_os_posix.c +350 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm.c +556 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm.h +132 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_buf.c +383 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_buf.h +42 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_mem.c +269 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_mem.h +48 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_os.h +40 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_os_posix.c +203 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_pkcrypt.c +334 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_pkcrypt.h +46 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_split.c +429 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_split.h +43 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_wzaes.c +360 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_wzaes.h +46 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_zlib.c +389 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_strm_zlib.h +43 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_zip.c +2782 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_zip.h +262 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_zip_rw.c +1942 -0
- package/ios/CodePush/SSZipArchive/minizip/mz_zip_rw.h +285 -0
- package/ios/CodePush.xcodeproj/project.pbxproj +1052 -0
- package/ios/CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/CodePush.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/PrivacyInfo.xcprivacy +31 -0
- package/logging.js +6 -0
- package/package-mixins.js +68 -0
- package/package.json +91 -0
- package/react-native.config.js +11 -0
- package/request-fetch-adapter.js +52 -0
- package/scripts/generateBundledResourcesHash.js +125 -0
- package/scripts/getFilesInFolder.js +19 -0
- package/scripts/postlink/android/postlink.js +87 -0
- package/scripts/postlink/ios/postlink.js +116 -0
- package/scripts/postlink/run.js +11 -0
- package/scripts/postunlink/android/postunlink.js +74 -0
- package/scripts/postunlink/ios/postunlink.js +87 -0
- package/scripts/postunlink/run.js +11 -0
- package/scripts/recordFilesBeforeBundleCommand.js +41 -0
- package/scripts/tools/linkToolsAndroid.js +57 -0
- package/scripts/tools/linkToolsIos.js +130 -0
- package/tsconfig.json +17 -0
- package/tslint.json +32 -0
- package/typings/react-native-code-push.d.ts +455 -0
- package/windows/CodePush/.!12419!CodePushNativeModule.h +154 -0
- package/windows/CodePush/.!12440!CodePushNativeModule.h +154 -0
- package/windows/CodePush/CodePush.def +3 -0
- package/windows/CodePush/CodePush.vcxproj +198 -0
- package/windows/CodePush/CodePush.vcxproj.filters +91 -0
- package/windows/CodePush/CodePushConfig.cpp +99 -0
- package/windows/CodePush/CodePushConfig.h +66 -0
- package/windows/CodePush/CodePushConfig.idl +12 -0
- package/windows/CodePush/CodePushDownloadHandler.cpp +73 -0
- package/windows/CodePush/CodePushDownloadHandler.h +32 -0
- package/windows/CodePush/CodePushNativeModule.cpp +934 -0
- package/windows/CodePush/CodePushNativeModule.h +247 -0
- package/windows/CodePush/CodePushPackage.cpp +456 -0
- package/windows/CodePush/CodePushPackage.h +49 -0
- package/windows/CodePush/CodePushTelemetryManager.cpp +213 -0
- package/windows/CodePush/CodePushTelemetryManager.h +29 -0
- package/windows/CodePush/CodePushUpdateUtils.cpp +86 -0
- package/windows/CodePush/CodePushUpdateUtils.h +38 -0
- package/windows/CodePush/CodePushUtils.cpp +29 -0
- package/windows/CodePush/CodePushUtils.h +18 -0
- package/windows/CodePush/FileUtils.cpp +131 -0
- package/windows/CodePush/FileUtils.h +28 -0
- package/windows/CodePush/PropertySheet.props +16 -0
- package/windows/CodePush/ReactPackageProvider.cpp +15 -0
- package/windows/CodePush/ReactPackageProvider.h +22 -0
- package/windows/CodePush/ReactPackageProvider.idl +9 -0
- package/windows/CodePush/miniz/LICENSE +22 -0
- package/windows/CodePush/miniz/miniz.c +7657 -0
- package/windows/CodePush/miniz/miniz.h +1338 -0
- package/windows/CodePush/miniz/readme.md +37 -0
- package/windows/CodePush/packages.config +4 -0
- package/windows/CodePush/pch.cpp +1 -0
- package/windows/CodePush/pch.h +4 -0
- package/windows-legacy/CodePush/CodePush.csproj +128 -0
- package/windows-legacy/CodePush/CodePushUtils.cs +47 -0
- package/windows-legacy/CodePush/FileUtils.cs +40 -0
- package/windows-legacy/CodePush/Properties/AssemblyInfo.cs +29 -0
- package/windows-legacy/CodePush/Properties/CodePush.rd.xml +33 -0
- package/windows-legacy/CodePush/UpdateManager.cs +305 -0
- package/windows-legacy/CodePush/UpdateUtils.cs +46 -0
- package/windows-legacy/CodePush.Net46/Adapters/Http/HttpProgress.cs +28 -0
- package/windows-legacy/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs +106 -0
- package/windows-legacy/CodePush.Net46/CodePush.Net46.csproj +103 -0
- package/windows-legacy/CodePush.Net46/CodePushUtils.cs +158 -0
- package/windows-legacy/CodePush.Net46/FileUtils.cs +55 -0
- package/windows-legacy/CodePush.Net46/Properties/AssemblyInfo.cs +36 -0
- package/windows-legacy/CodePush.Net46/UpdateManager.cs +330 -0
- package/windows-legacy/CodePush.Net46/UpdateUtils.cs +70 -0
- package/windows-legacy/CodePush.Net46/packages.config +5 -0
- package/windows-legacy/CodePush.Net46.Test/ApplicationDataContainerTest.cs +105 -0
- package/windows-legacy/CodePush.Net46.Test/CodePush.Net46.Test.csproj +137 -0
- package/windows-legacy/CodePush.Net46.Test/Properties/AssemblyInfo.cs +36 -0
- package/windows-legacy/CodePush.Net46.Test/TelemetryManagerTest.cs +117 -0
- package/windows-legacy/CodePush.Net46.Test/app.config +11 -0
- package/windows-legacy/CodePush.Net46.Test/packages.config +4 -0
- package/windows-legacy/CodePush.Shared/CodePush.Shared.projitems +22 -0
- package/windows-legacy/CodePush.Shared/CodePush.Shared.shproj +13 -0
- package/windows-legacy/CodePush.Shared/CodePushConstants.cs +35 -0
- package/windows-legacy/CodePush.Shared/CodePushNativeModule.cs +329 -0
- package/windows-legacy/CodePush.Shared/CodePushReactPackage.cs +235 -0
- package/windows-legacy/CodePush.Shared/CodePushUtils.cs +70 -0
- package/windows-legacy/CodePush.Shared/InstallMode.cs +9 -0
- package/windows-legacy/CodePush.Shared/MinimumBackgroundListener.cs +44 -0
- package/windows-legacy/CodePush.Shared/SettingsManager.cs +148 -0
- package/windows-legacy/CodePush.Shared/TelemetryManager.cs +250 -0
- package/windows-legacy/CodePush.Shared/UpdateState.cs +9 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
package com.swyngpush.codepush.react;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.content.SharedPreferences;
|
|
5
|
+
import android.os.AsyncTask;
|
|
6
|
+
import android.os.Handler;
|
|
7
|
+
import android.os.Looper;
|
|
8
|
+
import android.view.View;
|
|
9
|
+
|
|
10
|
+
import androidx.annotation.OptIn;
|
|
11
|
+
|
|
12
|
+
import com.facebook.react.ReactApplication;
|
|
13
|
+
import com.facebook.react.ReactHost;
|
|
14
|
+
import com.facebook.react.ReactInstanceManager;
|
|
15
|
+
import com.facebook.react.ReactRootView;
|
|
16
|
+
import com.facebook.react.bridge.Arguments;
|
|
17
|
+
import com.facebook.react.bridge.BaseJavaModule;
|
|
18
|
+
import com.facebook.react.bridge.JSBundleLoader;
|
|
19
|
+
import com.facebook.react.bridge.LifecycleEventListener;
|
|
20
|
+
import com.facebook.react.bridge.Promise;
|
|
21
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
22
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
23
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
24
|
+
import com.facebook.react.bridge.WritableMap;
|
|
25
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
|
|
26
|
+
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
|
27
|
+
import android.view.Choreographer;
|
|
28
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
29
|
+
import com.facebook.react.modules.core.ReactChoreographer;
|
|
30
|
+
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
|
31
|
+
import com.facebook.react.runtime.ReactHostDelegate;
|
|
32
|
+
import com.facebook.react.runtime.ReactHostImpl;
|
|
33
|
+
|
|
34
|
+
import org.json.JSONArray;
|
|
35
|
+
import org.json.JSONException;
|
|
36
|
+
import org.json.JSONObject;
|
|
37
|
+
|
|
38
|
+
import java.io.IOException;
|
|
39
|
+
import java.lang.reflect.Field;
|
|
40
|
+
import java.lang.reflect.Method;
|
|
41
|
+
import java.util.ArrayList;
|
|
42
|
+
import java.util.Date;
|
|
43
|
+
import java.util.HashMap;
|
|
44
|
+
import java.util.List;
|
|
45
|
+
import java.util.Map;
|
|
46
|
+
import java.util.UUID;
|
|
47
|
+
|
|
48
|
+
@OptIn(markerClass = UnstableReactNativeAPI.class)
|
|
49
|
+
public class CodePushNativeModule extends BaseJavaModule {
|
|
50
|
+
private String mBinaryContentsHash = null;
|
|
51
|
+
private String mClientUniqueId = null;
|
|
52
|
+
private LifecycleEventListener mLifecycleEventListener = null;
|
|
53
|
+
private int mMinimumBackgroundDuration = 0;
|
|
54
|
+
|
|
55
|
+
private CodePush mCodePush;
|
|
56
|
+
private SettingsManager mSettingsManager;
|
|
57
|
+
private CodePushTelemetryManager mTelemetryManager;
|
|
58
|
+
private CodePushUpdateManager mUpdateManager;
|
|
59
|
+
|
|
60
|
+
private boolean _allowed = true;
|
|
61
|
+
private boolean _restartInProgress = false;
|
|
62
|
+
private ArrayList<Boolean> _restartQueue = new ArrayList<>();
|
|
63
|
+
|
|
64
|
+
public CodePushNativeModule(ReactApplicationContext reactContext, CodePush codePush, CodePushUpdateManager codePushUpdateManager, CodePushTelemetryManager codePushTelemetryManager, SettingsManager settingsManager) {
|
|
65
|
+
super(reactContext);
|
|
66
|
+
|
|
67
|
+
mCodePush = codePush;
|
|
68
|
+
mSettingsManager = settingsManager;
|
|
69
|
+
mTelemetryManager = codePushTelemetryManager;
|
|
70
|
+
mUpdateManager = codePushUpdateManager;
|
|
71
|
+
|
|
72
|
+
// Initialize module state while we have a reference to the current context.
|
|
73
|
+
mBinaryContentsHash = CodePushUpdateUtils.getHashForBinaryContents(reactContext, mCodePush.isDebugMode());
|
|
74
|
+
|
|
75
|
+
SharedPreferences preferences = codePush.getContext().getSharedPreferences(CodePushConstants.CODE_PUSH_PREFERENCES, 0);
|
|
76
|
+
mClientUniqueId = preferences.getString(CodePushConstants.CLIENT_UNIQUE_ID_KEY, null);
|
|
77
|
+
if (mClientUniqueId == null) {
|
|
78
|
+
mClientUniqueId = UUID.randomUUID().toString();
|
|
79
|
+
preferences.edit().putString(CodePushConstants.CLIENT_UNIQUE_ID_KEY, mClientUniqueId).apply();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@Override
|
|
84
|
+
public Map<String, Object> getConstants() {
|
|
85
|
+
final Map<String, Object> constants = new HashMap<>();
|
|
86
|
+
|
|
87
|
+
constants.put("codePushInstallModeImmediate", CodePushInstallMode.IMMEDIATE.getValue());
|
|
88
|
+
constants.put("codePushInstallModeOnNextRestart", CodePushInstallMode.ON_NEXT_RESTART.getValue());
|
|
89
|
+
constants.put("codePushInstallModeOnNextResume", CodePushInstallMode.ON_NEXT_RESUME.getValue());
|
|
90
|
+
constants.put("codePushInstallModeOnNextSuspend", CodePushInstallMode.ON_NEXT_SUSPEND.getValue());
|
|
91
|
+
|
|
92
|
+
constants.put("codePushUpdateStateRunning", CodePushUpdateState.RUNNING.getValue());
|
|
93
|
+
constants.put("codePushUpdateStatePending", CodePushUpdateState.PENDING.getValue());
|
|
94
|
+
constants.put("codePushUpdateStateLatest", CodePushUpdateState.LATEST.getValue());
|
|
95
|
+
|
|
96
|
+
return constants;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@Override
|
|
100
|
+
public String getName() {
|
|
101
|
+
return "CodePush";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private void loadBundleLegacy() {
|
|
105
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
106
|
+
if (currentActivity == null) {
|
|
107
|
+
// The currentActivity can be null if it is backgrounded / destroyed, so we simply
|
|
108
|
+
// no-op to prevent any null pointer exceptions.
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
mCodePush.invalidateCurrentInstance();
|
|
112
|
+
|
|
113
|
+
currentActivity.runOnUiThread(new Runnable() {
|
|
114
|
+
@Override
|
|
115
|
+
public void run() {
|
|
116
|
+
currentActivity.recreate();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private Field findBundleLoaderField(Class<?> delegateClass) {
|
|
122
|
+
Class<?> currentClass = delegateClass;
|
|
123
|
+
while (currentClass != null) {
|
|
124
|
+
try {
|
|
125
|
+
return currentClass.getDeclaredField("jsBundleLoader");
|
|
126
|
+
} catch (NoSuchFieldException ignored) {
|
|
127
|
+
// Continue searching the class hierarchy and alternate field names.
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
return currentClass.getDeclaredField("_jsBundleLoader");
|
|
132
|
+
} catch (NoSuchFieldException ignored) {
|
|
133
|
+
currentClass = currentClass.getSuperclass();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Use reflection to find and set the appropriate fields on ReactHostDelegate. See #556 for a proposal for a less brittle way
|
|
141
|
+
// to approach this.
|
|
142
|
+
private void setJSBundle(ReactHostDelegate reactHostDelegate, String latestJSBundleFile) throws IllegalAccessException {
|
|
143
|
+
try {
|
|
144
|
+
JSBundleLoader latestJSBundleLoader;
|
|
145
|
+
if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
|
|
146
|
+
latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
|
|
147
|
+
} else {
|
|
148
|
+
latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
Field bundleLoaderField = findBundleLoaderField(reactHostDelegate.getClass());
|
|
152
|
+
if (bundleLoaderField == null) {
|
|
153
|
+
throw new NoSuchFieldException("jsBundleLoader");
|
|
154
|
+
}
|
|
155
|
+
bundleLoaderField.setAccessible(true);
|
|
156
|
+
bundleLoaderField.set(reactHostDelegate, latestJSBundleLoader);
|
|
157
|
+
|
|
158
|
+
} catch (NoSuchFieldException nsfe) {
|
|
159
|
+
CodePushUtils.log("Field 'jsBundleLoader' NOT FOUND on " + (reactHostDelegate != null ? reactHostDelegate.getClass().getName() : "null") + ". This is an EXPECTED and IGNORED failure with ExpoReactHostDelegate. Will rely on reactHost.reload(). Original log: Unable to set JSBundle of ReactHostDelegate - CodePush may not support this version of React Native");
|
|
160
|
+
// DO NOT THROW for NoSuchFieldException.
|
|
161
|
+
}catch (Exception e) {
|
|
162
|
+
CodePushUtils.log("Unable to set JSBundle of ReactHostDelegate - CodePush may not support this version of React Native");
|
|
163
|
+
throw new IllegalAccessException("Could not setJSBundle");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private void loadBundle() {
|
|
168
|
+
clearLifecycleEventListener();
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
DevSupportManager devSupportManager = null;
|
|
172
|
+
ReactHost reactHost = resolveReactHost();
|
|
173
|
+
if (reactHost != null) {
|
|
174
|
+
devSupportManager = reactHost.getDevSupportManager();
|
|
175
|
+
}
|
|
176
|
+
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
177
|
+
|
|
178
|
+
mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
|
|
179
|
+
} catch(Exception e) {
|
|
180
|
+
// If we got error in out reflection we should clear debug cache anyway.
|
|
181
|
+
mCodePush.clearDebugCacheIfNeeded(false);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
// #1) Get the ReactHost instance, which is what includes the
|
|
187
|
+
// logic to reload the current React context.
|
|
188
|
+
final ReactHost reactHost = resolveReactHost();
|
|
189
|
+
if (reactHost == null) {
|
|
190
|
+
loadBundleLegacy(); // Fallback if reactHost can't be resolved
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
|
|
195
|
+
CodePushUtils.log("[MyDebug] Latest JS bundle for New Arch: " + latestJSBundleFile);
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
if (reactHost instanceof ReactHostImpl) {
|
|
200
|
+
ReactHostDelegate delegate = getReactHostDelegate((ReactHostImpl) reactHost);
|
|
201
|
+
if (delegate != null) {
|
|
202
|
+
// #2) Update the locally stored JS bundle file path
|
|
203
|
+
setJSBundle(delegate, latestJSBundleFile);
|
|
204
|
+
} else {
|
|
205
|
+
CodePushUtils.log("Could not get ReactHostDelegate from ReactHostImpl.");
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
CodePushUtils.log("ReactHost is not a direct ReactHostImpl instance (" + reactHost.getClass().getName() + "), skipping direct setJSBundle reflection attempt. This is expected with Expo.");
|
|
209
|
+
}
|
|
210
|
+
} catch (ClassCastException cce) {
|
|
211
|
+
CodePushUtils.log(new Exception("ClassCastException trying to get/use ReactHostDelegate. Skipping reflection call to setJSBundle. This is expected for Expo.", cce));
|
|
212
|
+
}catch (Exception e) {
|
|
213
|
+
// Catch any unexpected errors from the attempt to call setJSBundle, e.g., if getReactHostDelegate itself fails
|
|
214
|
+
CodePushUtils.log("Exception during the reflective setJSBundle block: " + e.getMessage());
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// #3) Get the context creation method
|
|
218
|
+
try {
|
|
219
|
+
reactHost.reload("CodePush triggers reload");
|
|
220
|
+
mCodePush.initializeUpdateAfterRestart();
|
|
221
|
+
} catch (Exception e) {
|
|
222
|
+
// The recreation method threw an unknown exception
|
|
223
|
+
// so just simply fallback to restarting the Activity (if it exists)
|
|
224
|
+
loadBundleLegacy();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
} catch (Exception e) {
|
|
228
|
+
// reflection logic failed somewhere so fall back to restarting the Activity (if it exists)
|
|
229
|
+
CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
|
|
230
|
+
loadBundleLegacy();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private boolean isLiveReloadEnabled(DevSupportManager devSupportManager) {
|
|
235
|
+
if (devSupportManager != null) {
|
|
236
|
+
DeveloperSettings devSettings = devSupportManager.getDevSettings();
|
|
237
|
+
Method[] methods = devSettings.getClass().getMethods();
|
|
238
|
+
for (Method m : methods) {
|
|
239
|
+
if (m.getName().equals("isReloadOnJSChangeEnabled")) {
|
|
240
|
+
try {
|
|
241
|
+
return (boolean) m.invoke(devSettings);
|
|
242
|
+
} catch (Exception x) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private void clearLifecycleEventListener() {
|
|
253
|
+
// Remove LifecycleEventListener to prevent infinite restart loop
|
|
254
|
+
if (mLifecycleEventListener != null) {
|
|
255
|
+
getReactApplicationContext().removeLifecycleEventListener(mLifecycleEventListener);
|
|
256
|
+
mLifecycleEventListener = null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private ReactHost resolveReactHost() throws NoSuchFieldException, IllegalAccessException {
|
|
261
|
+
ReactHost reactHost = CodePush.getReactHost();
|
|
262
|
+
if (reactHost != null) {
|
|
263
|
+
return reactHost;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
267
|
+
if (currentActivity == null) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
|
|
272
|
+
return reactApplication.getReactHost();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private void restartAppInternal(boolean onlyIfUpdateIsPending) {
|
|
276
|
+
if (this._restartInProgress) {
|
|
277
|
+
CodePushUtils.log("Restart request queued until the current restart is completed");
|
|
278
|
+
this._restartQueue.add(onlyIfUpdateIsPending);
|
|
279
|
+
return;
|
|
280
|
+
} else if (!this._allowed) {
|
|
281
|
+
CodePushUtils.log("Restart request queued until restarts are re-allowed");
|
|
282
|
+
this._restartQueue.add(onlyIfUpdateIsPending);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
this._restartInProgress = true;
|
|
287
|
+
if (!onlyIfUpdateIsPending || mSettingsManager.isPendingUpdate(null)) {
|
|
288
|
+
loadBundle();
|
|
289
|
+
CodePushUtils.log("Restarting app");
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
this._restartInProgress = false;
|
|
294
|
+
if (this._restartQueue.size() > 0) {
|
|
295
|
+
boolean buf = this._restartQueue.get(0);
|
|
296
|
+
this._restartQueue.remove(0);
|
|
297
|
+
this.restartAppInternal(buf);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
@ReactMethod
|
|
302
|
+
public void allow(Promise promise) {
|
|
303
|
+
CodePushUtils.log("Re-allowing restarts");
|
|
304
|
+
this._allowed = true;
|
|
305
|
+
|
|
306
|
+
if (_restartQueue.size() > 0) {
|
|
307
|
+
CodePushUtils.log("Executing pending restart");
|
|
308
|
+
boolean buf = this._restartQueue.get(0);
|
|
309
|
+
this._restartQueue.remove(0);
|
|
310
|
+
this.restartAppInternal(buf);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
promise.resolve(null);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@ReactMethod
|
|
318
|
+
public void clearPendingRestart(Promise promise) {
|
|
319
|
+
this._restartQueue.clear();
|
|
320
|
+
promise.resolve(null);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
@ReactMethod
|
|
325
|
+
public void disallow(Promise promise) {
|
|
326
|
+
CodePushUtils.log("Disallowing restarts");
|
|
327
|
+
this._allowed = false;
|
|
328
|
+
promise.resolve(null);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
@ReactMethod
|
|
333
|
+
public void restartApp(boolean onlyIfUpdateIsPending, Promise promise) {
|
|
334
|
+
try {
|
|
335
|
+
restartAppInternal(onlyIfUpdateIsPending);
|
|
336
|
+
promise.resolve(null);
|
|
337
|
+
} catch(CodePushUnknownException e) {
|
|
338
|
+
CodePushUtils.log(e);
|
|
339
|
+
promise.reject(e);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@ReactMethod
|
|
344
|
+
public void downloadUpdate(final ReadableMap updatePackage, final boolean notifyProgress, final Promise promise) {
|
|
345
|
+
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
|
|
346
|
+
@Override
|
|
347
|
+
protected Void doInBackground(Void... params) {
|
|
348
|
+
try {
|
|
349
|
+
JSONObject mutableUpdatePackage = CodePushUtils.convertReadableToJsonObject(updatePackage);
|
|
350
|
+
CodePushUtils.setJSONValueForKey(mutableUpdatePackage, CodePushConstants.BINARY_MODIFIED_TIME_KEY, "" + mCodePush.getBinaryResourcesModifiedTime());
|
|
351
|
+
mUpdateManager.downloadPackage(mutableUpdatePackage, mCodePush.getAssetsBundleFileName(), new DownloadProgressCallback() {
|
|
352
|
+
private boolean hasScheduledNextFrame = false;
|
|
353
|
+
private DownloadProgress latestDownloadProgress = null;
|
|
354
|
+
|
|
355
|
+
@Override
|
|
356
|
+
public void call(DownloadProgress downloadProgress) {
|
|
357
|
+
if (!notifyProgress) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
latestDownloadProgress = downloadProgress;
|
|
362
|
+
// If the download is completed, synchronously send the last event.
|
|
363
|
+
if (latestDownloadProgress.isCompleted()) {
|
|
364
|
+
dispatchDownloadProgressEvent();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (hasScheduledNextFrame) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
hasScheduledNextFrame = true;
|
|
373
|
+
getReactApplicationContext().runOnUiQueueThread(new Runnable() {
|
|
374
|
+
@Override
|
|
375
|
+
public void run() {
|
|
376
|
+
ReactChoreographer.getInstance().postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, new Choreographer.FrameCallback() {
|
|
377
|
+
@Override
|
|
378
|
+
public void doFrame(long frameTimeNanos) {
|
|
379
|
+
if (!latestDownloadProgress.isCompleted()) {
|
|
380
|
+
dispatchDownloadProgressEvent();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
hasScheduledNextFrame = false;
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
public void dispatchDownloadProgressEvent() {
|
|
391
|
+
getReactApplicationContext()
|
|
392
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
393
|
+
.emit(CodePushConstants.DOWNLOAD_PROGRESS_EVENT_NAME, latestDownloadProgress.createWritableMap());
|
|
394
|
+
}
|
|
395
|
+
}, mCodePush.getPublicKey());
|
|
396
|
+
|
|
397
|
+
JSONObject newPackage = mUpdateManager.getPackage(CodePushUtils.tryGetString(updatePackage, CodePushConstants.PACKAGE_HASH_KEY));
|
|
398
|
+
promise.resolve(CodePushUtils.convertJsonObjectToWritable(newPackage));
|
|
399
|
+
} catch (CodePushInvalidUpdateException e) {
|
|
400
|
+
CodePushUtils.log(e);
|
|
401
|
+
mSettingsManager.saveFailedUpdate(CodePushUtils.convertReadableToJsonObject(updatePackage));
|
|
402
|
+
promise.reject(e);
|
|
403
|
+
} catch (IOException | CodePushUnknownException e) {
|
|
404
|
+
CodePushUtils.log(e);
|
|
405
|
+
promise.reject(e);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
@ReactMethod
|
|
416
|
+
public void getConfiguration(Promise promise) {
|
|
417
|
+
try {
|
|
418
|
+
WritableMap configMap = Arguments.createMap();
|
|
419
|
+
configMap.putString("appVersion", mCodePush.getAppVersion());
|
|
420
|
+
configMap.putString("clientUniqueId", mClientUniqueId);
|
|
421
|
+
configMap.putString("deploymentKey", mCodePush.getDeploymentKey());
|
|
422
|
+
configMap.putString("serverUrl", mCodePush.getServerUrl());
|
|
423
|
+
|
|
424
|
+
// The binary hash may be null in debug builds
|
|
425
|
+
if (mBinaryContentsHash != null) {
|
|
426
|
+
configMap.putString(CodePushConstants.PACKAGE_HASH_KEY, mBinaryContentsHash);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
promise.resolve(configMap);
|
|
430
|
+
} catch(CodePushUnknownException e) {
|
|
431
|
+
CodePushUtils.log(e);
|
|
432
|
+
promise.reject(e);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
@ReactMethod
|
|
437
|
+
public void getUpdateMetadata(final int updateState, final Promise promise) {
|
|
438
|
+
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
|
|
439
|
+
@Override
|
|
440
|
+
protected Void doInBackground(Void... params) {
|
|
441
|
+
try {
|
|
442
|
+
JSONObject currentPackage = mUpdateManager.getCurrentPackage();
|
|
443
|
+
|
|
444
|
+
if (currentPackage == null) {
|
|
445
|
+
promise.resolve(null);
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
Boolean currentUpdateIsPending = false;
|
|
450
|
+
|
|
451
|
+
if (currentPackage.has(CodePushConstants.PACKAGE_HASH_KEY)) {
|
|
452
|
+
String currentHash = currentPackage.optString(CodePushConstants.PACKAGE_HASH_KEY, null);
|
|
453
|
+
currentUpdateIsPending = mSettingsManager.isPendingUpdate(currentHash);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (updateState == CodePushUpdateState.PENDING.getValue() && !currentUpdateIsPending) {
|
|
457
|
+
// The caller wanted a pending update
|
|
458
|
+
// but there isn't currently one.
|
|
459
|
+
promise.resolve(null);
|
|
460
|
+
} else if (updateState == CodePushUpdateState.RUNNING.getValue() && currentUpdateIsPending) {
|
|
461
|
+
// The caller wants the running update, but the current
|
|
462
|
+
// one is pending, so we need to grab the previous.
|
|
463
|
+
JSONObject previousPackage = mUpdateManager.getPreviousPackage();
|
|
464
|
+
|
|
465
|
+
if (previousPackage == null) {
|
|
466
|
+
promise.resolve(null);
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
promise.resolve(CodePushUtils.convertJsonObjectToWritable(previousPackage));
|
|
471
|
+
} else {
|
|
472
|
+
// The current package satisfies the request:
|
|
473
|
+
// 1) Caller wanted a pending, and there is a pending update
|
|
474
|
+
// 2) Caller wanted the running update, and there isn't a pending
|
|
475
|
+
// 3) Caller wants the latest update, regardless if it's pending or not
|
|
476
|
+
if (mCodePush.isRunningBinaryVersion()) {
|
|
477
|
+
// This only matters in Debug builds. Since we do not clear "outdated" updates,
|
|
478
|
+
// we need to indicate to the JS side that somehow we have a current update on
|
|
479
|
+
// disk that is not actually running.
|
|
480
|
+
CodePushUtils.setJSONValueForKey(currentPackage, "_isDebugOnly", true);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Enable differentiating pending vs. non-pending updates
|
|
484
|
+
CodePushUtils.setJSONValueForKey(currentPackage, "isPending", currentUpdateIsPending);
|
|
485
|
+
promise.resolve(CodePushUtils.convertJsonObjectToWritable(currentPackage));
|
|
486
|
+
}
|
|
487
|
+
} catch (CodePushMalformedDataException e) {
|
|
488
|
+
// We need to recover the app in case 'codepush.json' is corrupted
|
|
489
|
+
CodePushUtils.log(e.getMessage());
|
|
490
|
+
clearUpdates();
|
|
491
|
+
promise.resolve(null);
|
|
492
|
+
} catch(CodePushUnknownException e) {
|
|
493
|
+
CodePushUtils.log(e);
|
|
494
|
+
promise.reject(e);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
@ReactMethod
|
|
505
|
+
public void getNewStatusReport(final Promise promise) {
|
|
506
|
+
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
|
|
507
|
+
@Override
|
|
508
|
+
protected Void doInBackground(Void... params) {
|
|
509
|
+
try {
|
|
510
|
+
if (mCodePush.needToReportRollback()) {
|
|
511
|
+
mCodePush.setNeedToReportRollback(false);
|
|
512
|
+
JSONArray failedUpdates = mSettingsManager.getFailedUpdates();
|
|
513
|
+
if (failedUpdates != null && failedUpdates.length() > 0) {
|
|
514
|
+
try {
|
|
515
|
+
JSONObject lastFailedPackageJSON = failedUpdates.getJSONObject(failedUpdates.length() - 1);
|
|
516
|
+
WritableMap lastFailedPackage = CodePushUtils.convertJsonObjectToWritable(lastFailedPackageJSON);
|
|
517
|
+
WritableMap failedStatusReport = mTelemetryManager.getRollbackReport(lastFailedPackage);
|
|
518
|
+
if (failedStatusReport != null) {
|
|
519
|
+
promise.resolve(failedStatusReport);
|
|
520
|
+
return null;
|
|
521
|
+
}
|
|
522
|
+
} catch (JSONException e) {
|
|
523
|
+
throw new CodePushUnknownException("Unable to read failed updates information stored in SharedPreferences.", e);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
} else if (mCodePush.didUpdate()) {
|
|
527
|
+
JSONObject currentPackage = mUpdateManager.getCurrentPackage();
|
|
528
|
+
if (currentPackage != null) {
|
|
529
|
+
WritableMap newPackageStatusReport = mTelemetryManager.getUpdateReport(CodePushUtils.convertJsonObjectToWritable(currentPackage));
|
|
530
|
+
if (newPackageStatusReport != null) {
|
|
531
|
+
promise.resolve(newPackageStatusReport);
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
} else if (mCodePush.isRunningBinaryVersion()) {
|
|
536
|
+
WritableMap newAppVersionStatusReport = mTelemetryManager.getBinaryUpdateReport(mCodePush.getAppVersion());
|
|
537
|
+
if (newAppVersionStatusReport != null) {
|
|
538
|
+
promise.resolve(newAppVersionStatusReport);
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
WritableMap retryStatusReport = mTelemetryManager.getRetryStatusReport();
|
|
543
|
+
if (retryStatusReport != null) {
|
|
544
|
+
promise.resolve(retryStatusReport);
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
promise.resolve("");
|
|
550
|
+
} catch(CodePushUnknownException e) {
|
|
551
|
+
CodePushUtils.log(e);
|
|
552
|
+
promise.reject(e);
|
|
553
|
+
}
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
@ReactMethod
|
|
562
|
+
public void installUpdate(final ReadableMap updatePackage, final int installMode, final int minimumBackgroundDuration, final Promise promise) {
|
|
563
|
+
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
|
|
564
|
+
@Override
|
|
565
|
+
protected Void doInBackground(Void... params) {
|
|
566
|
+
try {
|
|
567
|
+
mUpdateManager.installPackage(CodePushUtils.convertReadableToJsonObject(updatePackage), mSettingsManager.isPendingUpdate(null));
|
|
568
|
+
|
|
569
|
+
String pendingHash = CodePushUtils.tryGetString(updatePackage, CodePushConstants.PACKAGE_HASH_KEY);
|
|
570
|
+
if (pendingHash == null) {
|
|
571
|
+
throw new CodePushUnknownException("Update package to be installed has no hash.");
|
|
572
|
+
} else {
|
|
573
|
+
mSettingsManager.savePendingUpdate(pendingHash, /* isLoading */false);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue() ||
|
|
577
|
+
// We also add the resume listener if the installMode is IMMEDIATE, because
|
|
578
|
+
// if the current activity is backgrounded, we want to reload the bundle when
|
|
579
|
+
// it comes back into the foreground.
|
|
580
|
+
installMode == CodePushInstallMode.IMMEDIATE.getValue() ||
|
|
581
|
+
installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
|
|
582
|
+
|
|
583
|
+
// Store the minimum duration on the native module as an instance
|
|
584
|
+
// variable instead of relying on a closure below, so that any
|
|
585
|
+
// subsequent resume-based installs could override it.
|
|
586
|
+
CodePushNativeModule.this.mMinimumBackgroundDuration = minimumBackgroundDuration;
|
|
587
|
+
|
|
588
|
+
if (mLifecycleEventListener == null) {
|
|
589
|
+
// Ensure we do not add the listener twice.
|
|
590
|
+
mLifecycleEventListener = new LifecycleEventListener() {
|
|
591
|
+
private Date lastPausedDate = null;
|
|
592
|
+
private Handler appSuspendHandler = new Handler(Looper.getMainLooper());
|
|
593
|
+
private Runnable loadBundleRunnable = new Runnable() {
|
|
594
|
+
@Override
|
|
595
|
+
public void run() {
|
|
596
|
+
CodePushUtils.log("Loading bundle on suspend");
|
|
597
|
+
restartAppInternal(false);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
@Override
|
|
602
|
+
public void onHostResume() {
|
|
603
|
+
appSuspendHandler.removeCallbacks(loadBundleRunnable);
|
|
604
|
+
// As of RN 36, the resume handler fires immediately if the app is in
|
|
605
|
+
// the foreground, so explicitly wait for it to be backgrounded first
|
|
606
|
+
if (lastPausedDate != null) {
|
|
607
|
+
long durationInBackground = (new Date().getTime() - lastPausedDate.getTime()) / 1000;
|
|
608
|
+
if (installMode == CodePushInstallMode.IMMEDIATE.getValue()
|
|
609
|
+
|| durationInBackground >= CodePushNativeModule.this.mMinimumBackgroundDuration) {
|
|
610
|
+
CodePushUtils.log("Loading bundle on resume");
|
|
611
|
+
restartAppInternal(false);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
@Override
|
|
617
|
+
public void onHostPause() {
|
|
618
|
+
// Save the current time so that when the app is later
|
|
619
|
+
// resumed, we can detect how long it was in the background.
|
|
620
|
+
lastPausedDate = new Date();
|
|
621
|
+
|
|
622
|
+
if (installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue() && mSettingsManager.isPendingUpdate(null)) {
|
|
623
|
+
appSuspendHandler.postDelayed(loadBundleRunnable, minimumBackgroundDuration * 1000);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
@Override
|
|
628
|
+
public void onHostDestroy() {
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
getReactApplicationContext().addLifecycleEventListener(mLifecycleEventListener);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
promise.resolve("");
|
|
637
|
+
} catch(CodePushUnknownException e) {
|
|
638
|
+
CodePushUtils.log(e);
|
|
639
|
+
promise.reject(e);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
@ReactMethod
|
|
650
|
+
public void isFailedUpdate(String packageHash, Promise promise) {
|
|
651
|
+
try {
|
|
652
|
+
promise.resolve(mSettingsManager.isFailedHash(packageHash));
|
|
653
|
+
} catch (CodePushUnknownException e) {
|
|
654
|
+
CodePushUtils.log(e);
|
|
655
|
+
promise.reject(e);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
@ReactMethod
|
|
660
|
+
public void getLatestRollbackInfo(Promise promise) {
|
|
661
|
+
try {
|
|
662
|
+
JSONObject latestRollbackInfo = mSettingsManager.getLatestRollbackInfo();
|
|
663
|
+
if (latestRollbackInfo != null) {
|
|
664
|
+
promise.resolve(CodePushUtils.convertJsonObjectToWritable(latestRollbackInfo));
|
|
665
|
+
} else {
|
|
666
|
+
promise.resolve(null);
|
|
667
|
+
}
|
|
668
|
+
} catch (CodePushUnknownException e) {
|
|
669
|
+
CodePushUtils.log(e);
|
|
670
|
+
promise.reject(e);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
@ReactMethod
|
|
675
|
+
public void setLatestRollbackInfo(String packageHash, Promise promise) {
|
|
676
|
+
try {
|
|
677
|
+
mSettingsManager.setLatestRollbackInfo(packageHash);
|
|
678
|
+
promise.resolve(null);
|
|
679
|
+
} catch (CodePushUnknownException e) {
|
|
680
|
+
CodePushUtils.log(e);
|
|
681
|
+
promise.reject(e);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
@ReactMethod
|
|
686
|
+
public void isFirstRun(String packageHash, Promise promise) {
|
|
687
|
+
try {
|
|
688
|
+
boolean isFirstRun = mCodePush.didUpdate()
|
|
689
|
+
&& packageHash != null
|
|
690
|
+
&& packageHash.length() > 0
|
|
691
|
+
&& packageHash.equals(mUpdateManager.getCurrentPackageHash());
|
|
692
|
+
promise.resolve(isFirstRun);
|
|
693
|
+
} catch(CodePushUnknownException e) {
|
|
694
|
+
CodePushUtils.log(e);
|
|
695
|
+
promise.reject(e);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
@ReactMethod
|
|
700
|
+
public void notifyApplicationReady(Promise promise) {
|
|
701
|
+
try {
|
|
702
|
+
mSettingsManager.removePendingUpdate();
|
|
703
|
+
promise.resolve("");
|
|
704
|
+
} catch(CodePushUnknownException e) {
|
|
705
|
+
CodePushUtils.log(e);
|
|
706
|
+
promise.reject(e);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
@ReactMethod
|
|
711
|
+
public void recordStatusReported(ReadableMap statusReport) {
|
|
712
|
+
try {
|
|
713
|
+
mTelemetryManager.recordStatusReported(statusReport);
|
|
714
|
+
} catch(CodePushUnknownException e) {
|
|
715
|
+
CodePushUtils.log(e);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
@ReactMethod
|
|
720
|
+
public void saveStatusReportForRetry(ReadableMap statusReport) {
|
|
721
|
+
try {
|
|
722
|
+
mTelemetryManager.saveStatusReportForRetry(statusReport);
|
|
723
|
+
} catch(CodePushUnknownException e) {
|
|
724
|
+
CodePushUtils.log(e);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
@ReactMethod
|
|
729
|
+
// Replaces the current bundle with the one downloaded from removeBundleUrl.
|
|
730
|
+
// It is only to be used during tests. No-ops if the test configuration flag is not set.
|
|
731
|
+
public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
|
|
732
|
+
try {
|
|
733
|
+
if (mCodePush.isUsingTestConfiguration()) {
|
|
734
|
+
try {
|
|
735
|
+
mUpdateManager.downloadAndReplaceCurrentBundle(remoteBundleUrl, mCodePush.getAssetsBundleFileName());
|
|
736
|
+
} catch (IOException e) {
|
|
737
|
+
throw new CodePushUnknownException("Unable to replace current bundle", e);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
} catch(CodePushUnknownException | CodePushMalformedDataException e) {
|
|
741
|
+
CodePushUtils.log(e);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* This method clears CodePush's downloaded updates.
|
|
747
|
+
* It is needed to switch to a different deployment if the current deployment is more recent.
|
|
748
|
+
* Note: we don’t recommend to use this method in scenarios other than that (CodePush will call
|
|
749
|
+
* this method automatically when needed in other cases) as it could lead to unpredictable
|
|
750
|
+
* behavior.
|
|
751
|
+
*/
|
|
752
|
+
@ReactMethod
|
|
753
|
+
public void clearUpdates() {
|
|
754
|
+
CodePushUtils.log("Clearing updates.");
|
|
755
|
+
mCodePush.clearUpdates();
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
@ReactMethod
|
|
759
|
+
public void addListener(String eventName) {
|
|
760
|
+
// Set up any upstream listeners or background tasks as necessary
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
@ReactMethod
|
|
764
|
+
public void removeListeners(Integer count) {
|
|
765
|
+
// Remove upstream listeners, stop unnecessary background tasks
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
public ReactHostDelegate getReactHostDelegate(ReactHostImpl reactHostImpl) {
|
|
769
|
+
try {
|
|
770
|
+
Class<?> clazz = reactHostImpl.getClass();
|
|
771
|
+
Field field = clazz.getDeclaredField("reactHostDelegate");
|
|
772
|
+
field.setAccessible(true);
|
|
773
|
+
|
|
774
|
+
// Get the value of the field for the provided instance
|
|
775
|
+
return (ReactHostDelegate) field.get(reactHostImpl);
|
|
776
|
+
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
777
|
+
e.printStackTrace();
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|