Skip to content

Commit dfba220

Browse files
authored
fix(Android): Support RN 0.82 (#95)
* fix(Android): app freezes when restarting in RN 0.82 deprecated ReactInstanceManager no longer needed on RN >= 0.74 * fix(Android): JS bundle file name incorrectly set to null (RN 0.82) * remove(Android): legacy code doesn't work * remove(Android): unused imports from CodePush.java * remove(Android): code no longer used * fix(CLI): tsc build failure * fix(CLI): jest error while resolving js modules ``` Cannot find module '../initIos.js' from 'commands/initCommand/test/initIos.test.ts' > 1 | import { modifyObjectiveCAppDelegate, modifySwiftAppDelegate } from "../initIos.js"; | ^ ``` ``` Cannot find module '../initAndroid.js' from 'commands/initCommand/test/initAndroid.test.ts' 1 | import fs from "fs"; 2 | import path from "path"; > 3 | import { initAndroid, modifyMainApplicationKt } from "../initAndroid.js"; | ^ ``` * remove(Android): code not used * docs: update supported React Native version to 0.82
1 parent 9696bc7 commit dfba220

File tree

11 files changed

+40
-119
lines changed

11 files changed

+40
-119
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
### 🚀 New Architecture support
1010

11-
Supports React Native 0.74 ~ 0.81.
11+
Supports React Native 0.74 ~ 0.82.
1212

1313
(Tested on the React Native CLI template apps)
1414

android/app/src/main/java/com/microsoft/codepush/react/CodePush.java

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,17 @@
55
import android.content.pm.PackageManager;
66
import android.content.res.Resources;
77

8-
import com.facebook.react.ReactInstanceManager;
98
import com.facebook.react.ReactPackage;
109
import com.facebook.react.bridge.JavaScriptModule;
1110
import com.facebook.react.bridge.NativeModule;
1211
import com.facebook.react.bridge.ReactApplicationContext;
13-
import com.facebook.react.devsupport.interfaces.DevSupportManager;
14-
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
1512
import com.facebook.react.uimanager.ViewManager;
1613

1714
import org.json.JSONException;
1815
import org.json.JSONObject;
1916

20-
import java.io.File;
2117
import java.util.ArrayList;
2218
import java.util.List;
23-
import java.lang.reflect.Method;
2419

2520
public class CodePush implements ReactPackage {
2621

@@ -31,7 +26,7 @@ public class CodePush implements ReactPackage {
3126

3227
private boolean mDidUpdate = false;
3328

34-
private String mAssetsBundleFileName;
29+
private String mAssetsBundleFileName = CodePushConstants.DEFAULT_JS_BUNDLE_NAME;
3530

3631
// Helper classes.
3732
private CodePushUpdateManager mUpdateManager;
@@ -47,7 +42,6 @@ public class CodePush implements ReactPackage {
4742

4843
private static String mPublicKey;
4944

50-
private static ReactInstanceHolder mReactInstanceHolder;
5145
private static CodePush mCurrentInstance;
5246

5347
public static String getServiceUrl() {
@@ -87,7 +81,6 @@ private CodePush(Context context, boolean isDebugMode) {
8781
String serverUrlFromStrings = getCustomPropertyFromStringsIfExist("ServerUrl");
8882
if (serverUrlFromStrings != null) mServerUrl = serverUrlFromStrings;
8983

90-
clearDebugCacheIfNeeded(null);
9184
initializeUpdateAfterRestart();
9285
}
9386

@@ -128,39 +121,6 @@ private String getCustomPropertyFromStringsIfExist(String propertyName) {
128121
return null;
129122
}
130123

131-
private boolean isLiveReloadEnabled(ReactInstanceManager instanceManager) {
132-
// Use instanceManager for checking if we use LiveReload mode. In this case we should not remove ReactNativeDevBundle.js file
133-
// because we get error with trying to get this after reloading. Issue: https://github.com/microsoft/react-native-code-push/issues/1272
134-
if (instanceManager != null) {
135-
DevSupportManager devSupportManager = instanceManager.getDevSupportManager();
136-
if (devSupportManager != null) {
137-
DeveloperSettings devSettings = devSupportManager.getDevSettings();
138-
Method[] methods = devSettings.getClass().getMethods();
139-
for (Method m : methods) {
140-
if (m.getName().equals("isReloadOnJSChangeEnabled")) {
141-
try {
142-
return (boolean) m.invoke(devSettings);
143-
} catch (Exception x) {
144-
return false;
145-
}
146-
}
147-
}
148-
}
149-
}
150-
151-
return false;
152-
}
153-
154-
public void clearDebugCacheIfNeeded(ReactInstanceManager instanceManager) {
155-
if (mIsDebugMode && mSettingsManager.isPendingUpdate(null) && !isLiveReloadEnabled(instanceManager)) {
156-
// This needs to be kept in sync with https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java#L78
157-
File cachedDevBundle = new File(mContext.getFilesDir(), "ReactNativeDevBundle.js");
158-
if (cachedDevBundle.exists()) {
159-
cachedDevBundle.delete();
160-
}
161-
}
162-
}
163-
164124
public boolean didUpdate() {
165125
return mDidUpdate;
166126
}
@@ -368,17 +328,6 @@ public void clearUpdates() {
368328
mSettingsManager.removeFailedUpdates();
369329
}
370330

371-
public static void setReactInstanceHolder(ReactInstanceHolder reactInstanceHolder) {
372-
mReactInstanceHolder = reactInstanceHolder;
373-
}
374-
375-
static ReactInstanceManager getReactInstanceManager() {
376-
if (mReactInstanceHolder == null) {
377-
return null;
378-
}
379-
return mReactInstanceHolder.getReactInstanceManager();
380-
}
381-
382331
@Override
383332
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
384333
CodePushNativeModule codePushModule = new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);

android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import androidx.annotation.OptIn;
1212

13-
import com.facebook.react.ReactApplication;
1413
import com.facebook.react.ReactDelegate;
1514
import com.facebook.react.ReactHost;
1615
import com.facebook.react.ReactInstanceManager;
@@ -116,7 +115,7 @@ public void run() {
116115

117116
// Use reflection to find and set the appropriate fields on ReactInstanceManager. See #556 for a proposal for a less brittle way
118117
// to approach this.
119-
private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBundleFile) throws IllegalAccessException {
118+
private void setJSBundle(String latestJSBundleFile) throws IllegalAccessException {
120119
try {
121120
JSBundleLoader latestJSBundleLoader;
122121
if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
@@ -128,7 +127,6 @@ private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBu
128127
ReactHost reactHost = resolveReactHost();
129128
if (reactHost == null) {
130129
// Bridge, Old Architecture
131-
setJSBundleLoaderBridge(instanceManager, latestJSBundleLoader);
132130
return;
133131
}
134132

@@ -140,12 +138,6 @@ private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBu
140138
}
141139
}
142140

143-
private void setJSBundleLoaderBridge(ReactInstanceManager instanceManager, JSBundleLoader latestJSBundleLoader) throws NoSuchFieldException, IllegalAccessException {
144-
Field bundleLoaderField = instanceManager.getClass().getDeclaredField("mBundleLoader");
145-
bundleLoaderField.setAccessible(true);
146-
bundleLoaderField.set(instanceManager, latestJSBundleLoader);
147-
}
148-
149141
@OptIn(markerClass = UnstableReactNativeAPI.class)
150142
private void setJSBundleLoaderBridgeless(ReactHost reactHost, JSBundleLoader latestJSBundleLoader) throws NoSuchFieldException, IllegalAccessException {
151143
Field mReactHostDelegateField = reactHost.getClass().getDeclaredField("mReactHostDelegate");
@@ -159,27 +151,14 @@ private void setJSBundleLoaderBridgeless(ReactHost reactHost, JSBundleLoader lat
159151

160152
private void loadBundle() {
161153
clearLifecycleEventListener();
162-
try {
163-
mCodePush.clearDebugCacheIfNeeded(resolveInstanceManager());
164-
} catch(Exception e) {
165-
// If we got error in out reflection we should clear debug cache anyway.
166-
mCodePush.clearDebugCacheIfNeeded(null);
167-
}
168154

169155
try {
170-
// #1) Get the ReactInstanceManager instance, which is what includes the
171-
// logic to reload the current React context.
172-
final ReactInstanceManager instanceManager = resolveInstanceManager();
173-
if (instanceManager == null) {
174-
return;
175-
}
176-
177156
String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
178157

179-
// #2) Update the locally stored JS bundle file path
180-
setJSBundle(instanceManager, latestJSBundleFile);
158+
// #1) Update the locally stored JS bundle file path
159+
setJSBundle(latestJSBundleFile);
181160

182-
// #3) Get the context creation method and fire it on the UI thread (which RN enforces)
161+
// #2) Get the context creation method and fire it on the UI thread (which RN enforces)
183162
new Handler(Looper.getMainLooper()).post(new Runnable() {
184163
@Override
185164
public void run() {
@@ -249,24 +228,6 @@ private ReactHost resolveReactHost() {
249228
}
250229
}
251230

252-
// Use reflection to find the ReactInstanceManager. See #556 for a proposal for a less brittle way to approach this.
253-
private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException {
254-
ReactInstanceManager instanceManager = CodePush.getReactInstanceManager();
255-
if (instanceManager != null) {
256-
return instanceManager;
257-
}
258-
259-
final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
260-
if (currentActivity == null) {
261-
return null;
262-
}
263-
264-
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
265-
instanceManager = reactApplication.getReactNativeHost().getReactInstanceManager();
266-
267-
return instanceManager;
268-
}
269-
270231
private void restartAppInternal(boolean onlyIfUpdateIsPending) {
271232
if (this._restartInProgress) {
272233
CodePushUtils.log("Restart request queued until the current restart is completed");

android/app/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java

Lines changed: 0 additions & 17 deletions
This file was deleted.

cli/commands/initCommand/test/initAndroid.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from "fs";
22
import path from "path";
3-
import { initAndroid, modifyMainApplicationKt } from "../initAndroid.ts";
3+
import { initAndroid, modifyMainApplicationKt } from "../initAndroid.js";
44
import { jest, expect, describe, it } from "@jest/globals";
55

66
const tempDir = path.join(__dirname, 'temp');

cli/commands/initCommand/test/initIos.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { modifyObjectiveCAppDelegate, modifySwiftAppDelegate } from "../initIos.ts";
1+
import { modifyObjectiveCAppDelegate, modifySwiftAppDelegate } from "../initIos.js";
22
import { expect, describe, it} from "@jest/globals";
33

44
// https://github.com/react-native-community/template/blob/0.80.2/template/ios/HelloWorld/AppDelegate.swift

cli/jest.config.cjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/** @type {import('jest').Config} */
2+
module.exports = {
3+
rootDir: __dirname,
4+
testEnvironment: 'node',
5+
// resolver: '<rootDir>/jest.resolver.cjs',
6+
transform: {
7+
'^.+\\.(t|j)s$': ['babel-jest', { configFile: '../babel.config.js' }],
8+
},
9+
moduleFileExtensions: ['ts', 'js'],
10+
watchman: false,
11+
};

cli/jest.resolver.cjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module.exports = (request, options) => {
2+
const defaultResolver = options.defaultResolver;
3+
4+
try {
5+
return defaultResolver(request, options);
6+
} catch (error) {
7+
if (request.endsWith('.js') && error && error.code === 'MODULE_NOT_FOUND') {
8+
const tsRequest = request.replace(/\.js$/, '.ts');
9+
try {
10+
return defaultResolver(tsRequest, options);
11+
} catch {
12+
throw error;
13+
}
14+
}
15+
throw error;
16+
}
17+
};

cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"scripts": {
88
"clean": "rm -rf dist",
99
"build": "tsc -p tsconfig.json",
10-
"typecheck": "tsc -p tsconfig.json --noEmit"
10+
"typecheck": "tsc -p tsconfig.json --noEmit",
11+
"test": "jest"
1112
},
1213
"dependencies": {
1314
"commander": "^12.1.0",

cli/tsconfig.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
"esModuleInterop": true,
1313
"skipLibCheck": true,
1414
"strict": true,
15-
"forceConsistentCasingInFileNames": true,
16-
"allowImportingTsExtensions": true
15+
"forceConsistentCasingInFileNames": true
1716
},
1817
"include": ["./**/*.ts"],
1918
"exclude": [

0 commit comments

Comments
 (0)