@appzung/react-native-code-push 10.2.4 → 11.0.0-rc10
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 +3 -5
- package/README.md +22 -20
- package/android/app/build.gradle +9 -0
- package/android/app/proguard-rules.pro +5 -0
- package/android/app/src/main/java/com/appzung/codepush/react/CodePush.java +30 -2
- package/android/app/src/main/java/com/appzung/codepush/react/CodePushNativeModule.java +179 -70
- package/android/app/src/main/java/com/appzung/codepush/react/ExpoUtils.java +22 -0
- package/android/app/src/main/java/com/appzung/codepush/react/ReactHostHolder.java +11 -0
- package/ios/CodePush/CodePush.h +8 -0
- package/ios/CodePush/{CodePush.m → CodePush.mm} +104 -139
- package/ios/CodePush.xcodeproj/project.pbxproj +6 -6
- package/lib/commonjs/internals/CodePushEventEmitter.js +10 -0
- package/lib/commonjs/internals/CodePushEventEmitter.js.map +1 -0
- package/lib/commonjs/internals/RemotePackageImplementation.js +2 -3
- package/lib/commonjs/internals/RemotePackageImplementation.js.map +1 -1
- package/lib/commonjs/internals/version.js +1 -1
- package/lib/commonjs/internals/version.js.map +1 -1
- package/lib/module/internals/CodePushEventEmitter.js +6 -0
- package/lib/module/internals/CodePushEventEmitter.js.map +1 -0
- package/lib/module/internals/RemotePackageImplementation.js +2 -3
- package/lib/module/internals/RemotePackageImplementation.js.map +1 -1
- package/lib/module/internals/version.js +1 -1
- package/lib/module/internals/version.js.map +1 -1
- package/lib/typescript/commonjs/src/internals/CodePushEventEmitter.d.ts +3 -0
- package/lib/typescript/commonjs/src/internals/CodePushEventEmitter.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/internals/RemotePackageImplementation.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/internals/version.d.ts +1 -1
- package/lib/typescript/commonjs/src/internals/version.d.ts.map +1 -1
- package/lib/typescript/module/src/internals/CodePushEventEmitter.d.ts +3 -0
- package/lib/typescript/module/src/internals/CodePushEventEmitter.d.ts.map +1 -0
- package/lib/typescript/module/src/internals/RemotePackageImplementation.d.ts.map +1 -1
- package/lib/typescript/module/src/internals/version.d.ts +1 -1
- package/lib/typescript/module/src/internals/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/react-native.config.js +1 -1
- package/src/internals/CodePushEventEmitter.ts +4 -0
- package/src/internals/RemotePackageImplementation.ts +2 -3
- package/src/internals/version.ts +1 -1
package/CodePush.podspec
CHANGED
|
@@ -14,14 +14,12 @@ 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
|
s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# linked properly at a parent workspace level.
|
|
24
|
-
s.dependency 'React-Core'
|
|
21
|
+
install_modules_dependencies(s)
|
|
22
|
+
|
|
25
23
|
s.dependency 'SSZipArchive', '~> 2.5.5'
|
|
26
24
|
s.dependency 'JWT', '~> 3.0.0-beta.12'
|
|
27
25
|
s.dependency 'Base64', '~> 1.1'
|
package/README.md
CHANGED
|
@@ -55,13 +55,13 @@ Otherwise:
|
|
|
55
55
|
npm install --save @appzung/react-native-code-push
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
_NOTE: For Expo apps a plugin will be made available soon. In the meantime, you may eject._
|
|
59
|
-
|
|
60
58
|
Then continue with installing the native module:
|
|
61
59
|
|
|
62
|
-
- [iOS
|
|
63
|
-
- [Android
|
|
64
|
-
- [Windows
|
|
60
|
+
- [iOS setup](docs/setup-ios.md)
|
|
61
|
+
- [Android setup](docs/setup-android.md)
|
|
62
|
+
- [Windows setup](docs/setup-windows.md)
|
|
63
|
+
|
|
64
|
+
Or if your app is managed by the Expo framework, install and configure [@appzung/expo-config-code-push](https://github.com/AppZung/expo-config-code-push).
|
|
65
65
|
|
|
66
66
|
## Migrating to AppZung CodePush
|
|
67
67
|
|
|
@@ -109,8 +109,9 @@ We try our best to maintain backwards compatibility of our plugin with previous
|
|
|
109
109
|
| v0.60-v0.61 | 4.1+ (TLS 1.2+) | 7 | ✅ | ❌ | v6.3.1 |
|
|
110
110
|
| v0.62-v0.64 | 4.1+ (TLS 1.2+) | 7 | ✅ | ❌ | v6.4.2 |
|
|
111
111
|
| v0.65-v0.70 | 4.1+ (TLS 1.2+) | 9 | ✅ | ❌ | v7.1.1 |
|
|
112
|
-
| v0.71
|
|
113
|
-
| v0.71
|
|
112
|
+
| v0.71-v0.79 | 4.1+ (TLS 1.2+) | 9 | ✅ | ❌ | v8.3.2 |
|
|
113
|
+
| v0.71-v0.79 | 4.1+ (TLS 1.2+) | 15.5 | ✅ | ❌ | v9.0.2 |
|
|
114
|
+
| v0.71+ | 4.1+ (TLS 1.2+) | 15.5 | ✅ | ❌ | v10+ |
|
|
114
115
|
| v0.74+ | 4.1+ (TLS 1.2+) | 15.5 | ✅ | ✅ | v11+ |
|
|
115
116
|
|
|
116
117
|
We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is.
|
|
@@ -145,11 +146,11 @@ withCodePush({ checkFrequency: CheckFrequency.ON_APP_RESUME })(MyApp);
|
|
|
145
146
|
Alternatively, if you want fine-grained control over when the check happens (like a button press or timer interval), eg. in a staging environment, you can call [`CodePush.sync()`](docs/api-js/functions/sync.md) at any time with your desired `SyncOptions`, and turn off CodePush's automatic checking by specifying a manual `checkFrequency`:
|
|
146
147
|
|
|
147
148
|
```javascript
|
|
148
|
-
import withCodePush, { CheckFrequency, InstallMode } from '@appzung/react-native-code-push';
|
|
149
|
+
import withCodePush, { CheckFrequency, InstallMode, sync } from '@appzung/react-native-code-push';
|
|
149
150
|
|
|
150
151
|
class MyApp extends Component {
|
|
151
152
|
onButtonPress() {
|
|
152
|
-
|
|
153
|
+
sync({
|
|
153
154
|
updateDialog: true,
|
|
154
155
|
installMode: InstallMode.IMMEDIATE,
|
|
155
156
|
});
|
|
@@ -173,7 +174,7 @@ If you would like to display an update confirmation dialog (an "active install")
|
|
|
173
174
|
|
|
174
175
|
## Releasing updates
|
|
175
176
|
|
|
176
|
-
Once your app is configured and distributed to your users, and you have made some JS or asset changes, it's time to release them. The recommended way to release them is
|
|
177
|
+
Once your app is configured and distributed to your users, and you have made some JS or asset changes, it's time to release them. The recommended way to release them is running the `appzung releases deploy-react-native` command (or `appzung releases deploy-expo` if using Expo) in the AppZung CLI, which will bundle your JavaScript files, asset files, and release the update to the CodePush server.
|
|
177
178
|
|
|
178
179
|
### Locally
|
|
179
180
|
|
|
@@ -258,7 +259,7 @@ This is not necessarily the case for `updateDialog`, since it won't force the us
|
|
|
258
259
|
|
|
259
260
|
## Debugging / Troubleshooting
|
|
260
261
|
|
|
261
|
-
The `sync`
|
|
262
|
+
The `withCodePush`/`sync` methods include a lot of diagnostic logging out-of-the-box, so if you're encountering an issue when using it, the best thing to try first is examining the output logs of your app. This will tell you whether the app is configured correctly (like can the plugin find your release channel public ID?), if the app is able to reach the server, if an available update is being discovered, if the update is being successfully downloaded/installed, etc. We want to continue improving the logging to be as intuitive/comprehensive as possible, so please [let us know](mailto:support@appzung.com) if you find it to be confusing or missing anything.
|
|
262
263
|
|
|
263
264
|
Start up the Chrome DevTools Console, the Xcode Console (iOS) and/or ADB logcat (Android), and look for messages which are prefixed with `[CodePush]`.
|
|
264
265
|
|
|
@@ -274,12 +275,13 @@ Note that by default, React Native logs are disabled on iOS in release builds, s
|
|
|
274
275
|
|
|
275
276
|
Now you'll be able to see CodePush logs in either debug or release mode, on both iOS or Android. If examining the logs don't provide an indication of the issue, please refer to the following common issues for additional resolution ideas:
|
|
276
277
|
|
|
277
|
-
| Issue / Symptom
|
|
278
|
-
|
|
|
279
|
-
| Compilation Error
|
|
280
|
-
| Network timeout / hang when calling `sync` or `checkForUpdate` in the iOS Simulator
|
|
281
|
-
| Server responds with a `404` when calling `sync` or `checkForUpdate`
|
|
282
|
-
| Update not being discovered
|
|
283
|
-
| Update not being displayed after restart
|
|
284
|
-
| I've released an update for iOS but my Android app also shows an update and it breaks it
|
|
285
|
-
| I've released new update but changes are not reflected
|
|
278
|
+
| Issue / Symptom | Possible Solution |
|
|
279
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
280
|
+
| Compilation Error | Clean your build folders and double-check that your version of React Native is [compatible](#compatibility-table) with the CodePush version you are using. |
|
|
281
|
+
| Network timeout / hang when calling `sync` or `checkForUpdate` in the iOS Simulator | Try resetting the simulator by selecting the `Simulator -> Reset Content and Settings..` menu item, and then re-running your app. |
|
|
282
|
+
| Server responds with a `404` when calling `sync` or `checkForUpdate` | Double-check that the release channel public ID you added to your `Info.plist` (iOS), `strings.xml` or `app/build.gradle` (Android) or that you're passing to `sync`/`checkForUpdate`, is in fact correct. You can run `appzung release-channels list` to view the correct public ID for your app release channel. |
|
|
283
|
+
| Update not being discovered | Double-check that the version of your running app (like `1.0.0`) matches the version you specified when releasing the update to CodePush. Additionally, make sure that you are releasing to the same release channel that your app is configured to sync with. |
|
|
284
|
+
| Update not being displayed after restart | If you're not using the withCodePush HOC or calling `sync` on app start (like within `componentDidMount` of your root component), then you need to explicitly call `notifyAppReady` on app start, otherwise, the plugin will think your update failed and roll it back. |
|
|
285
|
+
| I've released an update for iOS but my Android app also shows an update and it breaks it | Be sure you have different release channels for each platform in order to receive updates correctly |
|
|
286
|
+
| I've released new update but changes are not reflected | Be sure that you are running app in modes other than Debug. In Debug mode, React Native app always downloads JS bundle generated by packager, so JS bundle downloaded by CodePush does not apply. |
|
|
287
|
+
| Android compilation fails after migrating to AppZung with error "Task :app:checkReleaseAarMetadata FAILED A problem was found with the configuration of task ':app:checkReleaseAarMetadata' (type 'CheckAarMetadataTask')". | In `android/settings.gradle` remove the lines about CodePush. Be sure to read the other [migration steps](./docs/migrating-to-v10.md) carefully to review if you missed any others. |
|
package/android/app/build.gradle
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
def isNewArchitectureEnabled() {
|
|
2
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
apply plugin: "com.android.library"
|
|
2
6
|
|
|
7
|
+
if (isNewArchitectureEnabled()) {
|
|
8
|
+
apply plugin: "com.facebook.react"
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
def getExtOrDefault(name) {
|
|
4
12
|
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["CodePush_" + name]
|
|
5
13
|
}
|
|
@@ -33,6 +41,7 @@ android {
|
|
|
33
41
|
defaultConfig {
|
|
34
42
|
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
35
43
|
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
44
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
36
45
|
|
|
37
46
|
consumerProguardFiles 'proguard-rules.pro'
|
|
38
47
|
}
|
|
@@ -20,6 +20,11 @@
|
|
|
20
20
|
-keepclassmembers class com.facebook.react.ReactInstanceManager {
|
|
21
21
|
private final ** mBundleLoader;
|
|
22
22
|
}
|
|
23
|
+
-keepclassmembers class com.facebook.react.runtime.ReactHostImpl {
|
|
24
|
+
private final ** mReactHostDelegate;
|
|
25
|
+
}
|
|
26
|
+
-keep interface com.facebook.react.runtime.ReactHostDelegate { *; }
|
|
27
|
+
-keep class * implements com.facebook.react.runtime.ReactHostDelegate { *; }
|
|
23
28
|
|
|
24
29
|
# Can't find referenced class org.bouncycastle.**
|
|
25
30
|
-dontwarn com.nimbusds.jose.**
|
|
@@ -4,6 +4,7 @@ import android.content.Context;
|
|
|
4
4
|
import android.content.pm.PackageInfo;
|
|
5
5
|
import android.content.pm.PackageManager;
|
|
6
6
|
|
|
7
|
+
import com.facebook.react.ReactHost;
|
|
7
8
|
import com.facebook.react.ReactInstanceManager;
|
|
8
9
|
import com.facebook.react.ReactPackage;
|
|
9
10
|
import com.facebook.react.bridge.NativeModule;
|
|
@@ -18,6 +19,19 @@ import java.util.ArrayList;
|
|
|
18
19
|
import java.util.List;
|
|
19
20
|
|
|
20
21
|
public class CodePush implements ReactPackage {
|
|
22
|
+
private static final Object LOCK = new Object();
|
|
23
|
+
private static volatile CodePush mCurrentInstance;
|
|
24
|
+
|
|
25
|
+
public static CodePush getInstance(Context context) {
|
|
26
|
+
if (mCurrentInstance == null) {
|
|
27
|
+
synchronized (LOCK) {
|
|
28
|
+
if (mCurrentInstance == null) {
|
|
29
|
+
mCurrentInstance = new CodePush(context);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return mCurrentInstance;
|
|
34
|
+
}
|
|
21
35
|
|
|
22
36
|
private static boolean sIsRunningBinaryVersion = false;
|
|
23
37
|
private static boolean sNeedToReportRollback = false;
|
|
@@ -43,13 +57,14 @@ public class CodePush implements ReactPackage {
|
|
|
43
57
|
private static String mPublicKey;
|
|
44
58
|
|
|
45
59
|
private static ReactInstanceHolder mReactInstanceHolder;
|
|
46
|
-
|
|
60
|
+
|
|
61
|
+
private static ReactHostHolder mReactHostHolder;
|
|
47
62
|
|
|
48
63
|
public static String getServiceUrl() {
|
|
49
64
|
return mServerUrl;
|
|
50
65
|
}
|
|
51
66
|
|
|
52
|
-
|
|
67
|
+
private CodePush(Context context) {
|
|
53
68
|
mContext = context.getApplicationContext();
|
|
54
69
|
|
|
55
70
|
String releaseChannelPublicIdFromStrings = getCustomPropertyFromStringsIfExist("ReleaseChannelPublicId");
|
|
@@ -188,6 +203,7 @@ public class CodePush implements ReactPackage {
|
|
|
188
203
|
|
|
189
204
|
public static String getJSBundleFile(String assetsBundleFileName) {
|
|
190
205
|
if (mCurrentInstance == null) {
|
|
206
|
+
CodePushUtils.log("A CodePush instance has not been created yet. Have you added it to your app's list of ReactPackages?");
|
|
191
207
|
throw new CodePushNotInitializedException("A CodePush instance has not been created yet. Have you added it to your app's list of ReactPackages?");
|
|
192
208
|
}
|
|
193
209
|
|
|
@@ -366,6 +382,18 @@ public class CodePush implements ReactPackage {
|
|
|
366
382
|
return mReactInstanceHolder.getReactInstanceManager();
|
|
367
383
|
}
|
|
368
384
|
|
|
385
|
+
public static void setReactHost(ReactHostHolder reactHostHolder) {
|
|
386
|
+
mReactHostHolder = reactHostHolder;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
static ReactHost getReactHost() {
|
|
390
|
+
if (mReactHostHolder == null) {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return mReactHostHolder.getReactHost();
|
|
395
|
+
}
|
|
396
|
+
|
|
369
397
|
@Override
|
|
370
398
|
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
|
|
371
399
|
CodePushNativeModule codePushModule = new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);
|
|
@@ -8,22 +8,28 @@ import android.os.Looper;
|
|
|
8
8
|
import android.view.Choreographer;
|
|
9
9
|
import android.view.View;
|
|
10
10
|
|
|
11
|
+
import androidx.annotation.OptIn;
|
|
12
|
+
|
|
11
13
|
import com.facebook.react.ReactApplication;
|
|
14
|
+
import com.facebook.react.ReactHost;
|
|
12
15
|
import com.facebook.react.ReactInstanceManager;
|
|
13
16
|
import com.facebook.react.ReactRootView;
|
|
14
17
|
import com.facebook.react.bridge.Arguments;
|
|
18
|
+
import com.facebook.react.bridge.BaseJavaModule;
|
|
15
19
|
import com.facebook.react.bridge.JSBundleLoader;
|
|
16
20
|
import com.facebook.react.bridge.LifecycleEventListener;
|
|
17
21
|
import com.facebook.react.bridge.Promise;
|
|
18
22
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
19
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
20
23
|
import com.facebook.react.bridge.ReactMethod;
|
|
21
24
|
import com.facebook.react.bridge.ReadableMap;
|
|
22
25
|
import com.facebook.react.bridge.WritableMap;
|
|
26
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
|
|
23
27
|
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
|
24
28
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
25
29
|
import com.facebook.react.modules.core.ReactChoreographer;
|
|
26
30
|
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
|
31
|
+
import com.facebook.react.runtime.ReactHostDelegate;
|
|
32
|
+
import com.facebook.react.runtime.ReactHostImpl;
|
|
27
33
|
|
|
28
34
|
import org.json.JSONArray;
|
|
29
35
|
import org.json.JSONException;
|
|
@@ -39,11 +45,13 @@ import java.util.List;
|
|
|
39
45
|
import java.util.Map;
|
|
40
46
|
import java.util.UUID;
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
@OptIn(markerClass = UnstableReactNativeAPI.class)
|
|
49
|
+
public class CodePushNativeModule extends BaseJavaModule {
|
|
43
50
|
private String mBinaryContentsHash = null;
|
|
44
51
|
private String mClientUniqueId = null;
|
|
45
52
|
private boolean mTelemetryEnabled = true;
|
|
46
53
|
private boolean mDataTransmissionEnabled = true;
|
|
54
|
+
private boolean mIsExpoApp = false;
|
|
47
55
|
private LifecycleEventListener mLifecycleEventListener = null;
|
|
48
56
|
private int mMinimumBackgroundDuration = 0;
|
|
49
57
|
|
|
@@ -52,9 +60,9 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
52
60
|
private CodePushTelemetryManager mTelemetryManager;
|
|
53
61
|
private CodePushUpdateManager mUpdateManager;
|
|
54
62
|
|
|
55
|
-
private
|
|
56
|
-
private
|
|
57
|
-
private
|
|
63
|
+
private boolean _allowed = true;
|
|
64
|
+
private boolean _restartInProgress = false;
|
|
65
|
+
private ArrayList<Boolean> _restartQueue = new ArrayList<>();
|
|
58
66
|
|
|
59
67
|
public CodePushNativeModule(ReactApplicationContext reactContext, CodePush codePush, CodePushUpdateManager codePushUpdateManager, CodePushTelemetryManager codePushTelemetryManager, SettingsManager settingsManager) {
|
|
60
68
|
super(reactContext);
|
|
@@ -64,6 +72,8 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
64
72
|
mTelemetryManager = codePushTelemetryManager;
|
|
65
73
|
mUpdateManager = codePushUpdateManager;
|
|
66
74
|
|
|
75
|
+
mIsExpoApp = ExpoUtils.detectExpoEnvironment(reactContext);
|
|
76
|
+
|
|
67
77
|
// Initialize module state while we have a reference to the current context.
|
|
68
78
|
mBinaryContentsHash = CodePushUpdateUtils.getHashForBinaryContents(reactContext, mCodePush.isDebugMode());
|
|
69
79
|
|
|
@@ -119,7 +129,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
private void loadBundleLegacy() {
|
|
122
|
-
final Activity currentActivity = getCurrentActivity();
|
|
132
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
123
133
|
if (currentActivity == null) {
|
|
124
134
|
// The currentActivity can be null if it is backgrounded / destroyed, so we simply
|
|
125
135
|
// no-op to prevent any null pointer exceptions.
|
|
@@ -150,65 +160,135 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
150
160
|
bundleLoaderField.setAccessible(true);
|
|
151
161
|
bundleLoaderField.set(instanceManager, latestJSBundleLoader);
|
|
152
162
|
} catch (Exception e) {
|
|
153
|
-
CodePushUtils.log("Unable to set JSBundle - CodePush may not support this version of React Native");
|
|
163
|
+
CodePushUtils.log("Unable to set JSBundle of ReactInstanceManager - CodePush may not support this version of React Native");
|
|
154
164
|
throw new IllegalAccessException("Could not setJSBundle");
|
|
155
165
|
}
|
|
156
166
|
}
|
|
157
167
|
|
|
158
|
-
|
|
159
|
-
|
|
168
|
+
// Use reflection to find and set the appropriate fields on ReactHostDelegate. See #556 for a proposal for a less brittle way
|
|
169
|
+
// to approach this.
|
|
170
|
+
private void setJSBundle(ReactHostDelegate reactHostDelegate, String latestJSBundleFile) throws IllegalAccessException {
|
|
160
171
|
try {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
172
|
+
JSBundleLoader latestJSBundleLoader;
|
|
173
|
+
if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
|
|
174
|
+
latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
|
|
175
|
+
} else {
|
|
176
|
+
latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
|
|
165
177
|
}
|
|
166
|
-
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
167
178
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
179
|
+
Field bundleLoaderField = reactHostDelegate.getClass().getDeclaredField("jsBundleLoader");
|
|
180
|
+
bundleLoaderField.setAccessible(true);
|
|
181
|
+
bundleLoaderField.set(reactHostDelegate, latestJSBundleLoader);
|
|
182
|
+
} catch (Exception e) {
|
|
183
|
+
CodePushUtils.log("Unable to set JSBundle of ReactHostDelegate - CodePush may not support this version of React Native");
|
|
184
|
+
throw new IllegalAccessException("Could not setJSBundle");
|
|
172
185
|
}
|
|
186
|
+
}
|
|
173
187
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
188
|
+
private void loadBundle() {
|
|
189
|
+
clearLifecycleEventListener();
|
|
190
|
+
|
|
191
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
192
|
+
try {
|
|
193
|
+
DevSupportManager devSupportManager = null;
|
|
194
|
+
ReactHost reactHost = resolveReactHost();
|
|
195
|
+
if (reactHost != null) {
|
|
196
|
+
devSupportManager = reactHost.getDevSupportManager();
|
|
197
|
+
}
|
|
198
|
+
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
199
|
+
|
|
200
|
+
mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
|
|
201
|
+
} catch (Exception e) {
|
|
202
|
+
// If we got error in out reflection we should clear debug cache anyway.
|
|
203
|
+
mCodePush.clearDebugCacheIfNeeded(false);
|
|
180
204
|
}
|
|
181
205
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
189
|
-
@Override
|
|
190
|
-
public void run() {
|
|
191
|
-
try {
|
|
192
|
-
// We don't need to resetReactRootViews anymore
|
|
193
|
-
// due the issue https://github.com/facebook/react-native/issues/14533
|
|
194
|
-
// has been fixed in RN 0.46.0
|
|
195
|
-
//resetReactRootViews(instanceManager);
|
|
196
|
-
|
|
197
|
-
instanceManager.recreateReactContextInBackground();
|
|
198
|
-
mCodePush.initializeUpdateAfterRestart();
|
|
199
|
-
} catch (Exception e) {
|
|
200
|
-
// The recreation method threw an unknown exception
|
|
201
|
-
// so just simply fallback to restarting the Activity (if it exists)
|
|
202
|
-
loadBundleLegacy();
|
|
203
|
-
}
|
|
206
|
+
try {
|
|
207
|
+
// #1) Get the ReactHost instance, which is what includes the
|
|
208
|
+
// logic to reload the current React context.
|
|
209
|
+
final ReactHost reactHost = resolveReactHost();
|
|
210
|
+
if (reactHost == null) {
|
|
211
|
+
return;
|
|
204
212
|
}
|
|
205
|
-
});
|
|
206
213
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
214
|
+
String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
|
|
215
|
+
|
|
216
|
+
// if expo and new arch this is unnecessary, see https://github.com/expo/expo/blob/8113ce44edaef0311e2daff3ab1a63b9731d2d6c/packages/expo-updates/android/src/main/java/expo/modules/updates/procedures/RelaunchProcedure.kt#L148
|
|
217
|
+
if (!mIsExpoApp) {
|
|
218
|
+
// #2) Update the locally stored JS bundle file path
|
|
219
|
+
setJSBundle(getReactHostDelegate((ReactHostImpl) reactHost), latestJSBundleFile);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// #3) Get the context creation method
|
|
223
|
+
try {
|
|
224
|
+
reactHost.reload("CodePush triggers reload");
|
|
225
|
+
mCodePush.initializeUpdateAfterRestart();
|
|
226
|
+
} catch (Exception e) {
|
|
227
|
+
// The recreation method threw an unknown exception
|
|
228
|
+
// so just simply fallback to restarting the Activity (if it exists)
|
|
229
|
+
loadBundleLegacy();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
} catch (Exception e) {
|
|
233
|
+
// Our reflection logic failed somewhere
|
|
234
|
+
// so fall back to restarting the Activity (if it exists)
|
|
235
|
+
CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
|
|
236
|
+
loadBundleLegacy();
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
try {
|
|
240
|
+
DevSupportManager devSupportManager = null;
|
|
241
|
+
ReactInstanceManager reactInstanceManager = resolveInstanceManager();
|
|
242
|
+
if (reactInstanceManager != null) {
|
|
243
|
+
devSupportManager = reactInstanceManager.getDevSupportManager();
|
|
244
|
+
}
|
|
245
|
+
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
246
|
+
|
|
247
|
+
mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
|
|
248
|
+
} catch (Exception e) {
|
|
249
|
+
// If we got error in out reflection we should clear debug cache anyway.
|
|
250
|
+
mCodePush.clearDebugCacheIfNeeded(false);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
// #1) Get the ReactInstanceManager instance, which is what includes the
|
|
255
|
+
// logic to reload the current React context.
|
|
256
|
+
final ReactInstanceManager instanceManager = resolveInstanceManager();
|
|
257
|
+
if (instanceManager == null) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
|
|
262
|
+
|
|
263
|
+
// #2) Update the locally stored JS bundle file path
|
|
264
|
+
setJSBundle(instanceManager, latestJSBundleFile);
|
|
265
|
+
|
|
266
|
+
// #3) Get the context creation method and fire it on the UI thread (which RN enforces)
|
|
267
|
+
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
268
|
+
@Override
|
|
269
|
+
public void run() {
|
|
270
|
+
try {
|
|
271
|
+
// We don't need to resetReactRootViews anymore
|
|
272
|
+
// due the issue https://github.com/facebook/react-native/issues/14533
|
|
273
|
+
// has been fixed in RN 0.46.0
|
|
274
|
+
//resetReactRootViews(instanceManager);
|
|
275
|
+
|
|
276
|
+
instanceManager.recreateReactContextInBackground();
|
|
277
|
+
mCodePush.initializeUpdateAfterRestart();
|
|
278
|
+
} catch (Exception e) {
|
|
279
|
+
// The recreation method threw an unknown exception
|
|
280
|
+
// so just simply fallback to restarting the Activity (if it exists)
|
|
281
|
+
loadBundleLegacy();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
} catch (Exception e) {
|
|
287
|
+
// Our reflection logic failed somewhere
|
|
288
|
+
// so fall back to restarting the Activity (if it exists)
|
|
289
|
+
CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
|
|
290
|
+
loadBundleLegacy();
|
|
291
|
+
}
|
|
212
292
|
}
|
|
213
293
|
}
|
|
214
294
|
|
|
@@ -238,7 +318,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
238
318
|
private void resetReactRootViews(ReactInstanceManager instanceManager) throws NoSuchFieldException, IllegalAccessException {
|
|
239
319
|
Field mAttachedRootViewsField = instanceManager.getClass().getDeclaredField("mAttachedRootViews");
|
|
240
320
|
mAttachedRootViewsField.setAccessible(true);
|
|
241
|
-
List<ReactRootView> mAttachedRootViews = (List<ReactRootView>)mAttachedRootViewsField.get(instanceManager);
|
|
321
|
+
List<ReactRootView> mAttachedRootViews = (List<ReactRootView>) mAttachedRootViewsField.get(instanceManager);
|
|
242
322
|
for (ReactRootView reactRootView : mAttachedRootViews) {
|
|
243
323
|
reactRootView.removeAllViews();
|
|
244
324
|
reactRootView.setId(View.NO_ID);
|
|
@@ -261,7 +341,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
261
341
|
return instanceManager;
|
|
262
342
|
}
|
|
263
343
|
|
|
264
|
-
final Activity currentActivity = getCurrentActivity();
|
|
344
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
265
345
|
if (currentActivity == null) {
|
|
266
346
|
return null;
|
|
267
347
|
}
|
|
@@ -272,6 +352,21 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
272
352
|
return instanceManager;
|
|
273
353
|
}
|
|
274
354
|
|
|
355
|
+
private ReactHost resolveReactHost() throws NoSuchFieldException, IllegalAccessException {
|
|
356
|
+
ReactHost reactHost = CodePush.getReactHost();
|
|
357
|
+
if (reactHost != null) {
|
|
358
|
+
return reactHost;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
362
|
+
if (currentActivity == null) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
|
|
367
|
+
return reactApplication.getReactHost();
|
|
368
|
+
}
|
|
369
|
+
|
|
275
370
|
private void restartAppInternal(boolean onlyIfUpdateIsPending) {
|
|
276
371
|
if (this._restartInProgress) {
|
|
277
372
|
CodePushUtils.log("Restart request queued until the current restart is completed");
|
|
@@ -334,7 +429,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
334
429
|
try {
|
|
335
430
|
restartAppInternal(onlyIfUpdateIsPending);
|
|
336
431
|
promise.resolve(null);
|
|
337
|
-
} catch(CodePushUnknownException e) {
|
|
432
|
+
} catch (CodePushUnknownException e) {
|
|
338
433
|
CodePushUtils.log(e);
|
|
339
434
|
promise.reject(e);
|
|
340
435
|
}
|
|
@@ -415,7 +510,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
415
510
|
@ReactMethod
|
|
416
511
|
public void getConfiguration(Promise promise) {
|
|
417
512
|
try {
|
|
418
|
-
WritableMap configMap =
|
|
513
|
+
WritableMap configMap = Arguments.createMap();
|
|
419
514
|
configMap.putString("appVersion", mCodePush.getAppVersion());
|
|
420
515
|
configMap.putString("clientUniqueId", mClientUniqueId);
|
|
421
516
|
configMap.putString("releaseChannelPublicId", mCodePush.getReleaseChannelPublicId());
|
|
@@ -429,7 +524,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
429
524
|
}
|
|
430
525
|
|
|
431
526
|
promise.resolve(configMap);
|
|
432
|
-
} catch(CodePushUnknownException e) {
|
|
527
|
+
} catch (CodePushUnknownException e) {
|
|
433
528
|
CodePushUtils.log(e);
|
|
434
529
|
promise.reject(e);
|
|
435
530
|
}
|
|
@@ -491,7 +586,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
491
586
|
CodePushUtils.log(e.getMessage());
|
|
492
587
|
clearUpdates();
|
|
493
588
|
promise.resolve(null);
|
|
494
|
-
} catch(CodePushUnknownException e) {
|
|
589
|
+
} catch (CodePushUnknownException e) {
|
|
495
590
|
CodePushUtils.log(e);
|
|
496
591
|
promise.reject(e);
|
|
497
592
|
}
|
|
@@ -549,7 +644,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
549
644
|
}
|
|
550
645
|
|
|
551
646
|
promise.resolve("");
|
|
552
|
-
} catch(CodePushUnknownException e) {
|
|
647
|
+
} catch (CodePushUnknownException e) {
|
|
553
648
|
CodePushUtils.log(e);
|
|
554
649
|
promise.reject(e);
|
|
555
650
|
}
|
|
@@ -576,11 +671,11 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
576
671
|
}
|
|
577
672
|
|
|
578
673
|
if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue() ||
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
674
|
+
// We also add the resume listener if the installMode is IMMEDIATE, because
|
|
675
|
+
// if the current activity is backgrounded, we want to reload the bundle when
|
|
676
|
+
// it comes back into the foreground.
|
|
677
|
+
installMode == CodePushInstallMode.IMMEDIATE.getValue() ||
|
|
678
|
+
installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
|
|
584
679
|
|
|
585
680
|
// Store the minimum duration on the native module as an instance
|
|
586
681
|
// variable instead of relying on a closure below, so that any
|
|
@@ -636,7 +731,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
636
731
|
}
|
|
637
732
|
|
|
638
733
|
promise.resolve("");
|
|
639
|
-
} catch(CodePushUnknownException e) {
|
|
734
|
+
} catch (CodePushUnknownException e) {
|
|
640
735
|
CodePushUtils.log(e);
|
|
641
736
|
promise.reject(e);
|
|
642
737
|
}
|
|
@@ -692,7 +787,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
692
787
|
&& packageHash.length() > 0
|
|
693
788
|
&& packageHash.equals(mUpdateManager.getCurrentPackageHash());
|
|
694
789
|
promise.resolve(isFirstRun);
|
|
695
|
-
} catch(CodePushUnknownException e) {
|
|
790
|
+
} catch (CodePushUnknownException e) {
|
|
696
791
|
CodePushUtils.log(e);
|
|
697
792
|
promise.reject(e);
|
|
698
793
|
}
|
|
@@ -703,7 +798,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
703
798
|
try {
|
|
704
799
|
mSettingsManager.removePendingUpdate();
|
|
705
800
|
promise.resolve("");
|
|
706
|
-
} catch(CodePushUnknownException e) {
|
|
801
|
+
} catch (CodePushUnknownException e) {
|
|
707
802
|
CodePushUtils.log(e);
|
|
708
803
|
promise.reject(e);
|
|
709
804
|
}
|
|
@@ -713,7 +808,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
713
808
|
public void recordStatusReported(ReadableMap statusReport) {
|
|
714
809
|
try {
|
|
715
810
|
mTelemetryManager.recordStatusReported(statusReport);
|
|
716
|
-
} catch(CodePushUnknownException e) {
|
|
811
|
+
} catch (CodePushUnknownException e) {
|
|
717
812
|
CodePushUtils.log(e);
|
|
718
813
|
}
|
|
719
814
|
}
|
|
@@ -722,7 +817,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
722
817
|
public void saveStatusReportForRetry(ReadableMap statusReport) {
|
|
723
818
|
try {
|
|
724
819
|
mTelemetryManager.saveStatusReportForRetry(statusReport);
|
|
725
|
-
} catch(CodePushUnknownException e) {
|
|
820
|
+
} catch (CodePushUnknownException e) {
|
|
726
821
|
CodePushUtils.log(e);
|
|
727
822
|
}
|
|
728
823
|
}
|
|
@@ -739,7 +834,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
739
834
|
throw new CodePushUnknownException("Unable to replace current bundle", e);
|
|
740
835
|
}
|
|
741
836
|
}
|
|
742
|
-
} catch(CodePushUnknownException | CodePushMalformedDataException e) {
|
|
837
|
+
} catch (CodePushUnknownException | CodePushMalformedDataException e) {
|
|
743
838
|
CodePushUtils.log(e);
|
|
744
839
|
}
|
|
745
840
|
}
|
|
@@ -816,4 +911,18 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
816
911
|
public void removeListeners(Integer count) {
|
|
817
912
|
// Remove upstream listeners, stop unnecessary background tasks
|
|
818
913
|
}
|
|
914
|
+
|
|
915
|
+
public ReactHostDelegate getReactHostDelegate(ReactHostImpl reactHostImpl) {
|
|
916
|
+
try {
|
|
917
|
+
Class<?> clazz = reactHostImpl.getClass();
|
|
918
|
+
Field field = clazz.getDeclaredField("mReactHostDelegate");
|
|
919
|
+
field.setAccessible(true);
|
|
920
|
+
|
|
921
|
+
// Get the value of the field for the provided instance
|
|
922
|
+
return (ReactHostDelegate) field.get(reactHostImpl);
|
|
923
|
+
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
924
|
+
e.printStackTrace();
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
819
928
|
}
|