@appzung/react-native-code-push 10.0.1 → 11.0.0-rc2
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/android/app/build.gradle +9 -0
- package/android/app/src/main/java/com/appzung/codepush/react/CodePush.java +29 -2
- package/android/app/src/main/java/com/appzung/codepush/react/CodePushNativeModule.java +173 -70
- package/android/app/src/main/java/com/appzung/codepush/react/ReactHostHolder.java +11 -0
- package/ios/CodePush/CodePush.m +57 -13
- package/lib/commonjs/internals/version.js +1 -1
- package/lib/commonjs/internals/version.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/version.d.ts +1 -1
- package/lib/typescript/commonjs/src/internals/version.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/version.ts +1 -1
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
|
}
|
|
@@ -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");
|
|
@@ -363,6 +378,18 @@ public class CodePush implements ReactPackage {
|
|
|
363
378
|
return mReactInstanceHolder.getReactInstanceManager();
|
|
364
379
|
}
|
|
365
380
|
|
|
381
|
+
public static void setReactHost(ReactHostHolder reactHostHolder) {
|
|
382
|
+
mReactHostHolder = reactHostHolder;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
static ReactHost getReactHost() {
|
|
386
|
+
if (mReactHostHolder == null) {
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return mReactHostHolder.getReactHost();
|
|
391
|
+
}
|
|
392
|
+
|
|
366
393
|
@Override
|
|
367
394
|
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
|
|
368
395
|
CodePushNativeModule codePushModule = new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);
|
|
@@ -7,23 +7,29 @@ import android.os.Handler;
|
|
|
7
7
|
import android.os.Looper;
|
|
8
8
|
import android.view.View;
|
|
9
9
|
|
|
10
|
+
import androidx.annotation.OptIn;
|
|
11
|
+
|
|
10
12
|
import com.facebook.react.ReactApplication;
|
|
13
|
+
import com.facebook.react.ReactHost;
|
|
11
14
|
import com.facebook.react.ReactInstanceManager;
|
|
12
15
|
import com.facebook.react.ReactRootView;
|
|
13
16
|
import com.facebook.react.bridge.Arguments;
|
|
17
|
+
import com.facebook.react.bridge.BaseJavaModule;
|
|
14
18
|
import com.facebook.react.bridge.JSBundleLoader;
|
|
15
19
|
import com.facebook.react.bridge.LifecycleEventListener;
|
|
16
20
|
import com.facebook.react.bridge.Promise;
|
|
17
21
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
18
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
19
22
|
import com.facebook.react.bridge.ReactMethod;
|
|
20
23
|
import com.facebook.react.bridge.ReadableMap;
|
|
21
24
|
import com.facebook.react.bridge.WritableMap;
|
|
25
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
|
|
22
26
|
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
|
23
27
|
import com.facebook.react.modules.core.ChoreographerCompat;
|
|
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,7 +45,8 @@ 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 LifecycleEventListener mLifecycleEventListener = null;
|
|
@@ -50,9 +57,9 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
50
57
|
private CodePushTelemetryManager mTelemetryManager;
|
|
51
58
|
private CodePushUpdateManager mUpdateManager;
|
|
52
59
|
|
|
53
|
-
private
|
|
54
|
-
private
|
|
55
|
-
private
|
|
60
|
+
private boolean _allowed = true;
|
|
61
|
+
private boolean _restartInProgress = false;
|
|
62
|
+
private ArrayList<Boolean> _restartQueue = new ArrayList<>();
|
|
56
63
|
|
|
57
64
|
public CodePushNativeModule(ReactApplicationContext reactContext, CodePush codePush, CodePushUpdateManager codePushUpdateManager, CodePushTelemetryManager codePushTelemetryManager, SettingsManager settingsManager) {
|
|
58
65
|
super(reactContext);
|
|
@@ -95,7 +102,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
private void loadBundleLegacy() {
|
|
98
|
-
final Activity currentActivity = getCurrentActivity();
|
|
105
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
99
106
|
if (currentActivity == null) {
|
|
100
107
|
// The currentActivity can be null if it is backgrounded / destroyed, so we simply
|
|
101
108
|
// no-op to prevent any null pointer exceptions.
|
|
@@ -126,65 +133,132 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
126
133
|
bundleLoaderField.setAccessible(true);
|
|
127
134
|
bundleLoaderField.set(instanceManager, latestJSBundleLoader);
|
|
128
135
|
} catch (Exception e) {
|
|
129
|
-
CodePushUtils.log("Unable to set JSBundle - CodePush may not support this version of React Native");
|
|
136
|
+
CodePushUtils.log("Unable to set JSBundle of ReactInstanceManager - CodePush may not support this version of React Native");
|
|
130
137
|
throw new IllegalAccessException("Could not setJSBundle");
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
// Use reflection to find and set the appropriate fields on ReactHostDelegate. See #556 for a proposal for a less brittle way
|
|
142
|
+
// to approach this.
|
|
143
|
+
private void setJSBundle(ReactHostDelegate reactHostDelegate, String latestJSBundleFile) throws IllegalAccessException {
|
|
136
144
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
JSBundleLoader latestJSBundleLoader;
|
|
146
|
+
if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
|
|
147
|
+
latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
|
|
148
|
+
} else {
|
|
149
|
+
latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
|
|
141
150
|
}
|
|
142
|
-
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
143
151
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
Field bundleLoaderField = reactHostDelegate.getClass().getDeclaredField("jsBundleLoader");
|
|
153
|
+
bundleLoaderField.setAccessible(true);
|
|
154
|
+
bundleLoaderField.set(reactHostDelegate, latestJSBundleLoader);
|
|
155
|
+
} catch (Exception e) {
|
|
156
|
+
CodePushUtils.log("Unable to set JSBundle of ReactHostDelegate - CodePush may not support this version of React Native");
|
|
157
|
+
throw new IllegalAccessException("Could not setJSBundle");
|
|
148
158
|
}
|
|
159
|
+
}
|
|
149
160
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
private void loadBundle() {
|
|
162
|
+
clearLifecycleEventListener();
|
|
163
|
+
|
|
164
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
165
|
+
try {
|
|
166
|
+
DevSupportManager devSupportManager = null;
|
|
167
|
+
ReactHost reactHost = resolveReactHost();
|
|
168
|
+
if (reactHost != null) {
|
|
169
|
+
devSupportManager = reactHost.getDevSupportManager();
|
|
170
|
+
}
|
|
171
|
+
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
172
|
+
|
|
173
|
+
mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
|
|
174
|
+
} catch (Exception e) {
|
|
175
|
+
// If we got error in out reflection we should clear debug cache anyway.
|
|
176
|
+
mCodePush.clearDebugCacheIfNeeded(false);
|
|
156
177
|
}
|
|
157
178
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
165
|
-
@Override
|
|
166
|
-
public void run() {
|
|
167
|
-
try {
|
|
168
|
-
// We don't need to resetReactRootViews anymore
|
|
169
|
-
// due the issue https://github.com/facebook/react-native/issues/14533
|
|
170
|
-
// has been fixed in RN 0.46.0
|
|
171
|
-
//resetReactRootViews(instanceManager);
|
|
172
|
-
|
|
173
|
-
instanceManager.recreateReactContextInBackground();
|
|
174
|
-
mCodePush.initializeUpdateAfterRestart();
|
|
175
|
-
} catch (Exception e) {
|
|
176
|
-
// The recreation method threw an unknown exception
|
|
177
|
-
// so just simply fallback to restarting the Activity (if it exists)
|
|
178
|
-
loadBundleLegacy();
|
|
179
|
-
}
|
|
179
|
+
try {
|
|
180
|
+
// #1) Get the ReactHost instance, which is what includes the
|
|
181
|
+
// logic to reload the current React context.
|
|
182
|
+
final ReactHost reactHost = resolveReactHost();
|
|
183
|
+
if (reactHost == null) {
|
|
184
|
+
return;
|
|
180
185
|
}
|
|
181
|
-
});
|
|
182
186
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
|
|
188
|
+
|
|
189
|
+
// #2) Update the locally stored JS bundle file path
|
|
190
|
+
setJSBundle(getReactHostDelegate((ReactHostImpl) reactHost), latestJSBundleFile);
|
|
191
|
+
|
|
192
|
+
// #3) Get the context creation method
|
|
193
|
+
try {
|
|
194
|
+
reactHost.reload("CodePush triggers reload");
|
|
195
|
+
mCodePush.initializeUpdateAfterRestart();
|
|
196
|
+
} catch (Exception e) {
|
|
197
|
+
// The recreation method threw an unknown exception
|
|
198
|
+
// so just simply fallback to restarting the Activity (if it exists)
|
|
199
|
+
loadBundleLegacy();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
} catch (Exception e) {
|
|
203
|
+
// Our reflection logic failed somewhere
|
|
204
|
+
// so fall back to restarting the Activity (if it exists)
|
|
205
|
+
CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
|
|
206
|
+
loadBundleLegacy();
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
try {
|
|
210
|
+
DevSupportManager devSupportManager = null;
|
|
211
|
+
ReactInstanceManager reactInstanceManager = resolveInstanceManager();
|
|
212
|
+
if (reactInstanceManager != null) {
|
|
213
|
+
devSupportManager = reactInstanceManager.getDevSupportManager();
|
|
214
|
+
}
|
|
215
|
+
boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
|
|
216
|
+
|
|
217
|
+
mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
|
|
218
|
+
} catch (Exception e) {
|
|
219
|
+
// If we got error in out reflection we should clear debug cache anyway.
|
|
220
|
+
mCodePush.clearDebugCacheIfNeeded(false);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
// #1) Get the ReactInstanceManager instance, which is what includes the
|
|
225
|
+
// logic to reload the current React context.
|
|
226
|
+
final ReactInstanceManager instanceManager = resolveInstanceManager();
|
|
227
|
+
if (instanceManager == null) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
|
|
232
|
+
|
|
233
|
+
// #2) Update the locally stored JS bundle file path
|
|
234
|
+
setJSBundle(instanceManager, latestJSBundleFile);
|
|
235
|
+
|
|
236
|
+
// #3) Get the context creation method and fire it on the UI thread (which RN enforces)
|
|
237
|
+
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
238
|
+
@Override
|
|
239
|
+
public void run() {
|
|
240
|
+
try {
|
|
241
|
+
// We don't need to resetReactRootViews anymore
|
|
242
|
+
// due the issue https://github.com/facebook/react-native/issues/14533
|
|
243
|
+
// has been fixed in RN 0.46.0
|
|
244
|
+
//resetReactRootViews(instanceManager);
|
|
245
|
+
|
|
246
|
+
instanceManager.recreateReactContextInBackground();
|
|
247
|
+
mCodePush.initializeUpdateAfterRestart();
|
|
248
|
+
} catch (Exception e) {
|
|
249
|
+
// The recreation method threw an unknown exception
|
|
250
|
+
// so just simply fallback to restarting the Activity (if it exists)
|
|
251
|
+
loadBundleLegacy();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
} catch (Exception e) {
|
|
257
|
+
// Our reflection logic failed somewhere
|
|
258
|
+
// so fall back to restarting the Activity (if it exists)
|
|
259
|
+
CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
|
|
260
|
+
loadBundleLegacy();
|
|
261
|
+
}
|
|
188
262
|
}
|
|
189
263
|
}
|
|
190
264
|
|
|
@@ -214,7 +288,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
214
288
|
private void resetReactRootViews(ReactInstanceManager instanceManager) throws NoSuchFieldException, IllegalAccessException {
|
|
215
289
|
Field mAttachedRootViewsField = instanceManager.getClass().getDeclaredField("mAttachedRootViews");
|
|
216
290
|
mAttachedRootViewsField.setAccessible(true);
|
|
217
|
-
List<ReactRootView> mAttachedRootViews = (List<ReactRootView>)mAttachedRootViewsField.get(instanceManager);
|
|
291
|
+
List<ReactRootView> mAttachedRootViews = (List<ReactRootView>) mAttachedRootViewsField.get(instanceManager);
|
|
218
292
|
for (ReactRootView reactRootView : mAttachedRootViews) {
|
|
219
293
|
reactRootView.removeAllViews();
|
|
220
294
|
reactRootView.setId(View.NO_ID);
|
|
@@ -237,7 +311,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
237
311
|
return instanceManager;
|
|
238
312
|
}
|
|
239
313
|
|
|
240
|
-
final Activity currentActivity = getCurrentActivity();
|
|
314
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
241
315
|
if (currentActivity == null) {
|
|
242
316
|
return null;
|
|
243
317
|
}
|
|
@@ -248,6 +322,21 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
248
322
|
return instanceManager;
|
|
249
323
|
}
|
|
250
324
|
|
|
325
|
+
private ReactHost resolveReactHost() throws NoSuchFieldException, IllegalAccessException {
|
|
326
|
+
ReactHost reactHost = CodePush.getReactHost();
|
|
327
|
+
if (reactHost != null) {
|
|
328
|
+
return reactHost;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
|
|
332
|
+
if (currentActivity == null) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
|
|
337
|
+
return reactApplication.getReactHost();
|
|
338
|
+
}
|
|
339
|
+
|
|
251
340
|
private void restartAppInternal(boolean onlyIfUpdateIsPending) {
|
|
252
341
|
if (this._restartInProgress) {
|
|
253
342
|
CodePushUtils.log("Restart request queued until the current restart is completed");
|
|
@@ -310,7 +399,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
310
399
|
try {
|
|
311
400
|
restartAppInternal(onlyIfUpdateIsPending);
|
|
312
401
|
promise.resolve(null);
|
|
313
|
-
} catch(CodePushUnknownException e) {
|
|
402
|
+
} catch (CodePushUnknownException e) {
|
|
314
403
|
CodePushUtils.log(e);
|
|
315
404
|
promise.reject(e);
|
|
316
405
|
}
|
|
@@ -391,7 +480,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
391
480
|
@ReactMethod
|
|
392
481
|
public void getConfiguration(Promise promise) {
|
|
393
482
|
try {
|
|
394
|
-
WritableMap configMap =
|
|
483
|
+
WritableMap configMap = Arguments.createMap();
|
|
395
484
|
configMap.putString("appVersion", mCodePush.getAppVersion());
|
|
396
485
|
configMap.putString("clientUniqueId", mClientUniqueId);
|
|
397
486
|
configMap.putString("releaseChannelPublicId", mCodePush.getReleaseChannelPublicId());
|
|
@@ -403,7 +492,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
403
492
|
}
|
|
404
493
|
|
|
405
494
|
promise.resolve(configMap);
|
|
406
|
-
} catch(CodePushUnknownException e) {
|
|
495
|
+
} catch (CodePushUnknownException e) {
|
|
407
496
|
CodePushUtils.log(e);
|
|
408
497
|
promise.reject(e);
|
|
409
498
|
}
|
|
@@ -465,7 +554,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
465
554
|
CodePushUtils.log(e.getMessage());
|
|
466
555
|
clearUpdates();
|
|
467
556
|
promise.resolve(null);
|
|
468
|
-
} catch(CodePushUnknownException e) {
|
|
557
|
+
} catch (CodePushUnknownException e) {
|
|
469
558
|
CodePushUtils.log(e);
|
|
470
559
|
promise.reject(e);
|
|
471
560
|
}
|
|
@@ -523,7 +612,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
523
612
|
}
|
|
524
613
|
|
|
525
614
|
promise.resolve("");
|
|
526
|
-
} catch(CodePushUnknownException e) {
|
|
615
|
+
} catch (CodePushUnknownException e) {
|
|
527
616
|
CodePushUtils.log(e);
|
|
528
617
|
promise.reject(e);
|
|
529
618
|
}
|
|
@@ -550,11 +639,11 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
550
639
|
}
|
|
551
640
|
|
|
552
641
|
if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue() ||
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
642
|
+
// We also add the resume listener if the installMode is IMMEDIATE, because
|
|
643
|
+
// if the current activity is backgrounded, we want to reload the bundle when
|
|
644
|
+
// it comes back into the foreground.
|
|
645
|
+
installMode == CodePushInstallMode.IMMEDIATE.getValue() ||
|
|
646
|
+
installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
|
|
558
647
|
|
|
559
648
|
// Store the minimum duration on the native module as an instance
|
|
560
649
|
// variable instead of relying on a closure below, so that any
|
|
@@ -610,7 +699,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
610
699
|
}
|
|
611
700
|
|
|
612
701
|
promise.resolve("");
|
|
613
|
-
} catch(CodePushUnknownException e) {
|
|
702
|
+
} catch (CodePushUnknownException e) {
|
|
614
703
|
CodePushUtils.log(e);
|
|
615
704
|
promise.reject(e);
|
|
616
705
|
}
|
|
@@ -666,7 +755,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
666
755
|
&& packageHash.length() > 0
|
|
667
756
|
&& packageHash.equals(mUpdateManager.getCurrentPackageHash());
|
|
668
757
|
promise.resolve(isFirstRun);
|
|
669
|
-
} catch(CodePushUnknownException e) {
|
|
758
|
+
} catch (CodePushUnknownException e) {
|
|
670
759
|
CodePushUtils.log(e);
|
|
671
760
|
promise.reject(e);
|
|
672
761
|
}
|
|
@@ -677,7 +766,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
677
766
|
try {
|
|
678
767
|
mSettingsManager.removePendingUpdate();
|
|
679
768
|
promise.resolve("");
|
|
680
|
-
} catch(CodePushUnknownException e) {
|
|
769
|
+
} catch (CodePushUnknownException e) {
|
|
681
770
|
CodePushUtils.log(e);
|
|
682
771
|
promise.reject(e);
|
|
683
772
|
}
|
|
@@ -687,7 +776,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
687
776
|
public void recordStatusReported(ReadableMap statusReport) {
|
|
688
777
|
try {
|
|
689
778
|
mTelemetryManager.recordStatusReported(statusReport);
|
|
690
|
-
} catch(CodePushUnknownException e) {
|
|
779
|
+
} catch (CodePushUnknownException e) {
|
|
691
780
|
CodePushUtils.log(e);
|
|
692
781
|
}
|
|
693
782
|
}
|
|
@@ -696,7 +785,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
696
785
|
public void saveStatusReportForRetry(ReadableMap statusReport) {
|
|
697
786
|
try {
|
|
698
787
|
mTelemetryManager.saveStatusReportForRetry(statusReport);
|
|
699
|
-
} catch(CodePushUnknownException e) {
|
|
788
|
+
} catch (CodePushUnknownException e) {
|
|
700
789
|
CodePushUtils.log(e);
|
|
701
790
|
}
|
|
702
791
|
}
|
|
@@ -713,7 +802,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
713
802
|
throw new CodePushUnknownException("Unable to replace current bundle", e);
|
|
714
803
|
}
|
|
715
804
|
}
|
|
716
|
-
} catch(CodePushUnknownException | CodePushMalformedDataException e) {
|
|
805
|
+
} catch (CodePushUnknownException | CodePushMalformedDataException e) {
|
|
717
806
|
CodePushUtils.log(e);
|
|
718
807
|
}
|
|
719
808
|
}
|
|
@@ -740,4 +829,18 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
|
|
|
740
829
|
public void removeListeners(Integer count) {
|
|
741
830
|
// Remove upstream listeners, stop unnecessary background tasks
|
|
742
831
|
}
|
|
832
|
+
|
|
833
|
+
public ReactHostDelegate getReactHostDelegate(ReactHostImpl reactHostImpl) {
|
|
834
|
+
try {
|
|
835
|
+
Class<?> clazz = reactHostImpl.getClass();
|
|
836
|
+
Field field = clazz.getDeclaredField("mReactHostDelegate");
|
|
837
|
+
field.setAccessible(true);
|
|
838
|
+
|
|
839
|
+
// Get the value of the field for the provided instance
|
|
840
|
+
return (ReactHostDelegate) field.get(reactHostImpl);
|
|
841
|
+
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
842
|
+
e.printStackTrace();
|
|
843
|
+
return null;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
743
846
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package com.appzung.codepush.react;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactHost;
|
|
4
|
+
import com.facebook.react.runtime.ReactHostDelegate;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Provides access to a {@link ReactHostDelegate}
|
|
8
|
+
*/
|
|
9
|
+
public interface ReactHostHolder {
|
|
10
|
+
ReactHost getReactHost();
|
|
11
|
+
}
|
package/ios/CodePush/CodePush.m
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#if __has_include(<React/RCTAssert.h>)
|
|
1
2
|
#import <React/RCTAssert.h>
|
|
2
3
|
#import <React/RCTBridgeModule.h>
|
|
3
4
|
#import <React/RCTConvert.h>
|
|
@@ -5,10 +6,18 @@
|
|
|
5
6
|
#import <React/RCTRootView.h>
|
|
6
7
|
#import <React/RCTUtils.h>
|
|
7
8
|
#import <React/RCTReloadCommand.h>
|
|
9
|
+
#else // back compatibility for RN version < 0.40
|
|
10
|
+
#import "RCTAssert.h"
|
|
11
|
+
#import "RCTBridgeModule.h"
|
|
12
|
+
#import "RCTConvert.h"
|
|
13
|
+
#import "RCTEventDispatcher.h"
|
|
14
|
+
#import "RCTRootView.h"
|
|
15
|
+
#import "RCTUtils.h"
|
|
16
|
+
#endif
|
|
8
17
|
|
|
9
18
|
#import "CodePush.h"
|
|
10
19
|
|
|
11
|
-
@interface CodePush () <RCTBridgeModule>
|
|
20
|
+
@interface CodePush () <RCTBridgeModule, RCTFrameUpdateObserver>
|
|
12
21
|
@end
|
|
13
22
|
|
|
14
23
|
@implementation CodePush {
|
|
@@ -21,8 +30,8 @@
|
|
|
21
30
|
|
|
22
31
|
// Used to coordinate the dispatching of download progress events to JS.
|
|
23
32
|
long long _latestExpectedContentLength;
|
|
24
|
-
long long
|
|
25
|
-
|
|
33
|
+
long long _latestReceivedConentLength;
|
|
34
|
+
BOOL _didUpdateProgress;
|
|
26
35
|
|
|
27
36
|
BOOL _allowed;
|
|
28
37
|
BOOL _restartInProgress;
|
|
@@ -246,6 +255,19 @@ static NSString *const LatestRollbackCountKey = @"count";
|
|
|
246
255
|
#pragma mark - Private API methods
|
|
247
256
|
|
|
248
257
|
@synthesize methodQueue = _methodQueue;
|
|
258
|
+
@synthesize pauseCallback = _pauseCallback;
|
|
259
|
+
@synthesize paused = _paused;
|
|
260
|
+
|
|
261
|
+
- (void)setPaused:(BOOL)paused
|
|
262
|
+
{
|
|
263
|
+
if (_paused != paused) {
|
|
264
|
+
_paused = paused;
|
|
265
|
+
if (_pauseCallback) {
|
|
266
|
+
_pauseCallback();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
249
271
|
/*
|
|
250
272
|
* This method is used to clear updates that are installed
|
|
251
273
|
* under a different app version and hence don't apply anymore,
|
|
@@ -310,7 +332,7 @@ static NSString *const LatestRollbackCountKey = @"count";
|
|
|
310
332
|
@"totalBytes" : [NSNumber
|
|
311
333
|
numberWithLongLong:_latestExpectedContentLength],
|
|
312
334
|
@"receivedBytes" : [NSNumber
|
|
313
|
-
numberWithLongLong:
|
|
335
|
+
numberWithLongLong:_latestReceivedConentLength]
|
|
314
336
|
}];
|
|
315
337
|
}
|
|
316
338
|
|
|
@@ -374,6 +396,7 @@ static NSString *const LatestRollbackCountKey = @"count";
|
|
|
374
396
|
#ifdef DEBUG
|
|
375
397
|
[self clearDebugUpdates];
|
|
376
398
|
#endif
|
|
399
|
+
self.paused = YES;
|
|
377
400
|
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
|
378
401
|
NSDictionary *pendingUpdate = [preferences objectForKey:PendingUpdateKey];
|
|
379
402
|
if (pendingUpdate) {
|
|
@@ -695,6 +718,13 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage
|
|
|
695
718
|
forKey:BinaryBundleDateKey];
|
|
696
719
|
}
|
|
697
720
|
|
|
721
|
+
if (notifyProgress) {
|
|
722
|
+
// Set up and unpause the frame observer so that it can emit
|
|
723
|
+
// progress events every frame if the progress is updated.
|
|
724
|
+
_didUpdateProgress = NO;
|
|
725
|
+
self.paused = NO;
|
|
726
|
+
}
|
|
727
|
+
|
|
698
728
|
NSString * publicKey = [[CodePushConfig current] publicKey];
|
|
699
729
|
|
|
700
730
|
[CodePushPackage
|
|
@@ -704,18 +734,17 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage
|
|
|
704
734
|
operationQueue:_methodQueue
|
|
705
735
|
// The download is progressing forward
|
|
706
736
|
progressCallback:^(long long expectedContentLength, long long receivedContentLength) {
|
|
707
|
-
// Update the download progress
|
|
708
|
-
|
|
709
|
-
|
|
737
|
+
// Update the download progress so that the frame observer can notify the JS side
|
|
738
|
+
_latestExpectedContentLength = expectedContentLength;
|
|
739
|
+
_latestReceivedConentLength = receivedContentLength;
|
|
740
|
+
_didUpdateProgress = YES;
|
|
710
741
|
|
|
742
|
+
// If the download is completed, stop observing frame
|
|
743
|
+
// updates and synchronously send the last event.
|
|
711
744
|
if (expectedContentLength == receivedContentLength) {
|
|
745
|
+
_didUpdateProgress = NO;
|
|
746
|
+
self.paused = YES;
|
|
712
747
|
[self dispatchDownloadProgressEvent];
|
|
713
|
-
} else if (notifyProgress) {
|
|
714
|
-
NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
|
|
715
|
-
if (timestamp - self->_lastProgressEmitTimestamp > 30.0 / 1000.0) {
|
|
716
|
-
self->_lastProgressEmitTimestamp = timestamp;
|
|
717
|
-
[self dispatchDownloadProgressEvent];
|
|
718
|
-
}
|
|
719
748
|
}
|
|
720
749
|
}
|
|
721
750
|
// The download completed
|
|
@@ -734,6 +763,9 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage
|
|
|
734
763
|
[self saveFailedUpdate:mutableUpdatePackage];
|
|
735
764
|
}
|
|
736
765
|
|
|
766
|
+
// Stop observing frame updates if the download fails.
|
|
767
|
+
_didUpdateProgress = NO;
|
|
768
|
+
self.paused = YES;
|
|
737
769
|
reject([NSString stringWithFormat: @"%lu", (long)err.code], err.localizedDescription, err);
|
|
738
770
|
}];
|
|
739
771
|
}
|
|
@@ -1075,4 +1107,16 @@ RCT_EXPORT_METHOD(saveStatusReportForRetry:(NSDictionary *)statusReport)
|
|
|
1075
1107
|
[CodePushTelemetryManager saveStatusReportForRetry:statusReport];
|
|
1076
1108
|
}
|
|
1077
1109
|
|
|
1110
|
+
#pragma mark - RCTFrameUpdateObserver Methods
|
|
1111
|
+
|
|
1112
|
+
- (void)didUpdateFrame:(RCTFrameUpdate *)update
|
|
1113
|
+
{
|
|
1114
|
+
if (!_didUpdateProgress) {
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
[self dispatchDownloadProgressEvent];
|
|
1119
|
+
_didUpdateProgress = NO;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1078
1122
|
@end
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["version","exports"],"sourceRoot":"../../../src","sources":["internals/version.ts"],"mappings":";;;;;;AAAA;AACO,MAAMA,OAAO,GAAAC,OAAA,CAAAD,OAAA,GAAG,
|
|
1
|
+
{"version":3,"names":["version","exports"],"sourceRoot":"../../../src","sources":["internals/version.ts"],"mappings":";;;;;;AAAA;AACO,MAAMA,OAAO,GAAAC,OAAA,CAAAD,OAAA,GAAG,YAAY","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["version"],"sourceRoot":"../../../src","sources":["internals/version.ts"],"mappings":";;AAAA;AACA,OAAO,MAAMA,OAAO,GAAG,
|
|
1
|
+
{"version":3,"names":["version"],"sourceRoot":"../../../src","sources":["internals/version.ts"],"mappings":";;AAAA;AACA,OAAO,MAAMA,OAAO,GAAG,YAAY","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "
|
|
1
|
+
export declare const version = "11.0.0-rc2";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../../../src/internals/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../../../src/internals/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,eAAe,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "
|
|
1
|
+
export declare const version = "11.0.0-rc2";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../../../src/internals/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../../../src/internals/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appzung/react-native-code-push",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0-rc2",
|
|
4
4
|
"description": "React Native plugin for the CodePush service",
|
|
5
5
|
"author": "Louis Lagrange <lagrange.louis@gmail.com> (https://github.com/Minishlink)",
|
|
6
6
|
"license": "MIT",
|
package/react-native.config.js
CHANGED
package/src/internals/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '
|
|
2
|
+
export const version = '11.0.0-rc2';
|