@bravemobile/react-native-code-push 9.0.1 → 10.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +8 -26
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +92 -22
- package/ios/CodePush/CodePush.m +2 -1
- package/package.json +1 -1
- package/react-native.config.js +1 -1
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java +0 -37
package/README.md
CHANGED
|
@@ -10,9 +10,18 @@ It allows self-hosting of CodePush deployments while retaining essential operati
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
### 🚀 New Architecture support
|
|
14
|
+
|
|
15
|
+
Tested on the React Native template apps
|
|
16
|
+
|
|
17
|
+
| RN Version | Old Architecture | New Architecture | New Architecture Bridgeless |
|
|
18
|
+
|--------|--------|--------|--------|
|
|
19
|
+
| 0.73.11 | ✅ | ✅ | Unsupported |
|
|
20
|
+
| 0.74.7 | ✅ | ✅ | ✅ |
|
|
21
|
+
| 0.75.5 | ✅ | ✅ | ✅ |
|
|
22
|
+
| 0.76.7 | ✅ | ✅ | ✅ |
|
|
23
|
+
| 0.77.1 | ✅ | ✅ | ✅ |
|
|
24
|
+
| 0.78.0 | ✅ | ✅ | ✅ |
|
|
16
25
|
|
|
17
26
|
|
|
18
27
|
## 🚗 Migration Guide
|
|
@@ -50,15 +50,18 @@ public class CodePush implements ReactPackage {
|
|
|
50
50
|
private static ReactInstanceHolder mReactInstanceHolder;
|
|
51
51
|
private static CodePush mCurrentInstance;
|
|
52
52
|
|
|
53
|
-
public CodePush(Context context) {
|
|
54
|
-
this(context, false);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
53
|
public static String getServiceUrl() {
|
|
58
54
|
return mServerUrl;
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
public CodePush(Context context, boolean isDebugMode) {
|
|
57
|
+
public static synchronized CodePush getInstance(Context context, boolean isDebugMode) {
|
|
58
|
+
if (mCurrentInstance == null) {
|
|
59
|
+
mCurrentInstance = new CodePush(context, isDebugMode);
|
|
60
|
+
}
|
|
61
|
+
return mCurrentInstance;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private CodePush(Context context, boolean isDebugMode) {
|
|
62
65
|
mContext = context.getApplicationContext();
|
|
63
66
|
|
|
64
67
|
mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath());
|
|
@@ -88,27 +91,6 @@ public class CodePush implements ReactPackage {
|
|
|
88
91
|
initializeUpdateAfterRestart();
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
public CodePush(Context context, boolean isDebugMode, String serverUrl) {
|
|
92
|
-
this(context, isDebugMode);
|
|
93
|
-
mServerUrl = serverUrl;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
public CodePush(Context context, boolean isDebugMode, int publicKeyResourceDescriptor) {
|
|
97
|
-
this(context, isDebugMode);
|
|
98
|
-
|
|
99
|
-
mPublicKey = getPublicKeyByResourceDescriptor(publicKeyResourceDescriptor);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
public CodePush(Context context, boolean isDebugMode, String serverUrl, Integer publicKeyResourceDescriptor) {
|
|
103
|
-
this(context, isDebugMode);
|
|
104
|
-
|
|
105
|
-
if (publicKeyResourceDescriptor != null) {
|
|
106
|
-
mPublicKey = getPublicKeyByResourceDescriptor(publicKeyResourceDescriptor);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
mServerUrl = serverUrl;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
94
|
private String getPublicKeyByResourceDescriptor(int publicKeyResourceDescriptor){
|
|
113
95
|
String publicKey;
|
|
114
96
|
try {
|
|
@@ -5,11 +5,15 @@ import android.content.SharedPreferences;
|
|
|
5
5
|
import android.os.AsyncTask;
|
|
6
6
|
import android.os.Handler;
|
|
7
7
|
import android.os.Looper;
|
|
8
|
-
import android.provider.Settings;
|
|
9
8
|
import android.view.View;
|
|
10
9
|
|
|
10
|
+
import androidx.annotation.OptIn;
|
|
11
|
+
|
|
11
12
|
import com.facebook.react.ReactApplication;
|
|
13
|
+
import com.facebook.react.ReactDelegate;
|
|
14
|
+
import com.facebook.react.ReactHost;
|
|
12
15
|
import com.facebook.react.ReactInstanceManager;
|
|
16
|
+
import com.facebook.react.ReactActivity;
|
|
13
17
|
import com.facebook.react.ReactRootView;
|
|
14
18
|
import com.facebook.react.bridge.Arguments;
|
|
15
19
|
import com.facebook.react.bridge.JSBundleLoader;
|
|
@@ -20,9 +24,11 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
|
20
24
|
import com.facebook.react.bridge.ReactMethod;
|
|
21
25
|
import com.facebook.react.bridge.ReadableMap;
|
|
22
26
|
import com.facebook.react.bridge.WritableMap;
|
|
27
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
|
|
23
28
|
import com.facebook.react.modules.core.ChoreographerCompat;
|
|
24
29
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
25
30
|
import com.facebook.react.modules.core.ReactChoreographer;
|
|
31
|
+
import com.facebook.react.runtime.ReactHostDelegate;
|
|
26
32
|
|
|
27
33
|
import org.json.JSONArray;
|
|
28
34
|
import org.json.JSONException;
|
|
@@ -30,10 +36,10 @@ import org.json.JSONObject;
|
|
|
30
36
|
|
|
31
37
|
import java.io.IOException;
|
|
32
38
|
import java.lang.reflect.Field;
|
|
39
|
+
import java.lang.reflect.Method;
|
|
33
40
|
import java.util.ArrayList;
|
|
34
41
|
import java.util.Date;
|
|
35
42
|
import java.util.HashMap;
|
|
36
|
-
import java.util.List;
|
|
37
43
|
import java.util.Map;
|
|
38
44
|
import java.util.UUID;
|
|
39
45
|
|
|
@@ -120,15 +126,38 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
120
126
|
latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
|
|
121
127
|
}
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
ReactHost reactHost = resolveReactHost();
|
|
130
|
+
if (reactHost == null) {
|
|
131
|
+
// Bridge, Old Architecture and RN < 0.74 (we support Bridgeless >= 0.74)
|
|
132
|
+
setJSBundleLoaderBridge(instanceManager, latestJSBundleLoader);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Bridgeless (RN >= 0.74)
|
|
137
|
+
setJSBundleLoaderBridgeless(reactHost, latestJSBundleLoader);
|
|
126
138
|
} catch (Exception e) {
|
|
127
139
|
CodePushUtils.log("Unable to set JSBundle - CodePush may not support this version of React Native");
|
|
128
140
|
throw new IllegalAccessException("Could not setJSBundle");
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
143
|
|
|
144
|
+
private void setJSBundleLoaderBridge(ReactInstanceManager instanceManager, JSBundleLoader latestJSBundleLoader) throws NoSuchFieldException, IllegalAccessException {
|
|
145
|
+
Field bundleLoaderField = instanceManager.getClass().getDeclaredField("mBundleLoader");
|
|
146
|
+
bundleLoaderField.setAccessible(true);
|
|
147
|
+
bundleLoaderField.set(instanceManager, latestJSBundleLoader);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@OptIn(markerClass = UnstableReactNativeAPI.class)
|
|
151
|
+
private void setJSBundleLoaderBridgeless(ReactHost reactHost, JSBundleLoader latestJSBundleLoader) throws NoSuchFieldException, IllegalAccessException {
|
|
152
|
+
Field mReactHostDelegateField = reactHost.getClass().getDeclaredField("mReactHostDelegate");
|
|
153
|
+
mReactHostDelegateField.setAccessible(true);
|
|
154
|
+
ReactHostDelegate reactHostDelegate = (ReactHostDelegate) mReactHostDelegateField.get(reactHost);
|
|
155
|
+
assert reactHostDelegate != null;
|
|
156
|
+
Field jsBundleLoaderField = reactHostDelegate.getClass().getDeclaredField("jsBundleLoader");
|
|
157
|
+
jsBundleLoaderField.setAccessible(true);
|
|
158
|
+
jsBundleLoaderField.set(reactHostDelegate, latestJSBundleLoader);
|
|
159
|
+
}
|
|
160
|
+
|
|
132
161
|
private void loadBundle() {
|
|
133
162
|
clearLifecycleEventListener();
|
|
134
163
|
try {
|
|
@@ -156,12 +185,22 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
156
185
|
@Override
|
|
157
186
|
public void run() {
|
|
158
187
|
try {
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
188
|
+
// reload method introduced in RN 0.74 (https://github.com/reactwg/react-native-new-architecture/discussions/174)
|
|
189
|
+
// so, we need to check if reload method exists and call it
|
|
190
|
+
try {
|
|
191
|
+
ReactDelegate reactDelegate = resolveReactDelegate();
|
|
192
|
+
if (reactDelegate == null) {
|
|
193
|
+
throw new NoSuchMethodException("ReactDelegate doesn't have reload method in RN < 0.74");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
resetReactRootViews(reactDelegate);
|
|
163
197
|
|
|
164
|
-
|
|
198
|
+
Method reloadMethod = reactDelegate.getClass().getMethod("reload");
|
|
199
|
+
reloadMethod.invoke(reactDelegate);
|
|
200
|
+
} catch (NoSuchMethodException e) {
|
|
201
|
+
// RN < 0.74 calls ReactInstanceManager.recreateReactContextInBackground() directly
|
|
202
|
+
instanceManager.recreateReactContextInBackground();
|
|
203
|
+
}
|
|
165
204
|
mCodePush.initializeUpdateAfterRestart();
|
|
166
205
|
} catch (Exception e) {
|
|
167
206
|
// The recreation method threw an unknown exception
|
|
@@ -179,18 +218,19 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
179
218
|
}
|
|
180
219
|
}
|
|
181
220
|
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
reactRootView
|
|
191
|
-
|
|
221
|
+
// Fix freezing that occurs when reloading the app (RN >= 0.77.1 Old Architecture)
|
|
222
|
+
// - "Trying to add a root view with an explicit id (11) already set.
|
|
223
|
+
// React Native uses the id field to track react tags and will overwrite this field.
|
|
224
|
+
// If that is fine, explicitly overwrite the id field to View.NO_ID before calling addRootView."
|
|
225
|
+
private void resetReactRootViews(ReactDelegate reactDelegate) {
|
|
226
|
+
ReactActivity currentActivity = (ReactActivity) getCurrentActivity();
|
|
227
|
+
if (currentActivity != null) {
|
|
228
|
+
ReactRootView reactRootView = reactDelegate.getReactRootView();
|
|
229
|
+
if (reactRootView != null) {
|
|
230
|
+
reactRootView.removeAllViews();
|
|
231
|
+
reactRootView.setId(View.NO_ID);
|
|
232
|
+
}
|
|
192
233
|
}
|
|
193
|
-
mAttachedRootViewsField.set(instanceManager, mAttachedRootViews);
|
|
194
234
|
}
|
|
195
235
|
|
|
196
236
|
private void clearLifecycleEventListener() {
|
|
@@ -201,6 +241,36 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
201
241
|
}
|
|
202
242
|
}
|
|
203
243
|
|
|
244
|
+
private ReactDelegate resolveReactDelegate() {
|
|
245
|
+
ReactActivity currentActivity = (ReactActivity) getCurrentActivity();
|
|
246
|
+
if (currentActivity == null) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
Method getReactDelegateMethod = currentActivity.getClass().getMethod("getReactDelegate");
|
|
252
|
+
return (ReactDelegate) getReactDelegateMethod.invoke(currentActivity);
|
|
253
|
+
} catch (Exception e) {
|
|
254
|
+
// RN < 0.74 doesn't have getReactDelegate method
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private ReactHost resolveReactHost() {
|
|
260
|
+
ReactDelegate reactDelegate = resolveReactDelegate();
|
|
261
|
+
if (reactDelegate == null) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
Field reactHostField = reactDelegate.getClass().getDeclaredField("mReactHost");
|
|
267
|
+
reactHostField.setAccessible(true);
|
|
268
|
+
return (ReactHost) reactHostField.get(reactDelegate);
|
|
269
|
+
} catch (Exception e) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
204
274
|
// Use reflection to find the ReactInstanceManager. See #556 for a proposal for a less brittle way to approach this.
|
|
205
275
|
private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException {
|
|
206
276
|
ReactInstanceManager instanceManager = CodePush.getReactInstanceManager();
|
|
@@ -492,7 +562,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
492
562
|
return null;
|
|
493
563
|
}
|
|
494
564
|
}
|
|
495
|
-
|
|
565
|
+
|
|
496
566
|
promise.resolve("");
|
|
497
567
|
} catch(CodePushUnknownException e) {
|
|
498
568
|
CodePushUtils.log(e);
|
package/ios/CodePush/CodePush.m
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#import <React/RCTEventDispatcher.h>
|
|
6
6
|
#import <React/RCTRootView.h>
|
|
7
7
|
#import <React/RCTUtils.h>
|
|
8
|
+
#import <React/RCTReloadCommand.h>
|
|
8
9
|
#else // back compatibility for RN version < 0.40
|
|
9
10
|
#import "RCTAssert.h"
|
|
10
11
|
#import "RCTBridgeModule.h"
|
|
@@ -540,7 +541,7 @@ static NSString *const LatestRollbackCountKey = @"count";
|
|
|
540
541
|
[super.bridge setValue:[CodePush bundleURL] forKey:@"bundleURL"];
|
|
541
542
|
}
|
|
542
543
|
|
|
543
|
-
|
|
544
|
+
RCTTriggerReloadCommandListeners(@"CodePush reload");
|
|
544
545
|
});
|
|
545
546
|
}
|
|
546
547
|
|
package/package.json
CHANGED
package/react-native.config.js
CHANGED
|
@@ -4,7 +4,7 @@ module.exports = {
|
|
|
4
4
|
android: {
|
|
5
5
|
packageImportPath: "import com.microsoft.codepush.react.CodePush;",
|
|
6
6
|
packageInstance:
|
|
7
|
-
"
|
|
7
|
+
"CodePush.getInstance(getApplicationContext(), BuildConfig.DEBUG)",
|
|
8
8
|
sourceDir: './android/app'
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
package com.microsoft.codepush.react;
|
|
2
|
-
|
|
3
|
-
import android.content.Context;
|
|
4
|
-
|
|
5
|
-
public class CodePushBuilder {
|
|
6
|
-
private String mDeploymentKey;
|
|
7
|
-
private Context mContext;
|
|
8
|
-
|
|
9
|
-
private boolean mIsDebugMode;
|
|
10
|
-
private String mServerUrl;
|
|
11
|
-
private Integer mPublicKeyResourceDescriptor;
|
|
12
|
-
|
|
13
|
-
public CodePushBuilder(Context context) {
|
|
14
|
-
this.mDeploymentKey = "deprecated_deployment_key";
|
|
15
|
-
this.mContext = context;
|
|
16
|
-
this.mServerUrl = CodePush.getServiceUrl();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public CodePushBuilder setIsDebugMode(boolean isDebugMode) {
|
|
20
|
-
this.mIsDebugMode = isDebugMode;
|
|
21
|
-
return this;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public CodePushBuilder setServerUrl(String serverUrl) {
|
|
25
|
-
this.mServerUrl = serverUrl;
|
|
26
|
-
return this;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public CodePushBuilder setPublicKeyResourceDescriptor(int publicKeyResourceDescriptor) {
|
|
30
|
-
this.mPublicKeyResourceDescriptor = publicKeyResourceDescriptor;
|
|
31
|
-
return this;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public CodePush build() {
|
|
35
|
-
return new CodePush(this.mContext, this.mIsDebugMode, this.mServerUrl, this.mPublicKeyResourceDescriptor);
|
|
36
|
-
}
|
|
37
|
-
}
|