|
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; |
11 | 13 | import com.facebook.react.ReactDelegate; |
| 14 | +import com.facebook.react.ReactHost; |
12 | 15 | import com.facebook.react.ReactInstanceManager; |
13 | 16 | import com.facebook.react.ReactActivity; |
14 | 17 | import com.facebook.react.ReactRootView; |
|
21 | 24 | import com.facebook.react.bridge.ReactMethod; |
22 | 25 | import com.facebook.react.bridge.ReadableMap; |
23 | 26 | import com.facebook.react.bridge.WritableMap; |
24 | | -import com.facebook.react.devsupport.interfaces.DevSupportManager; |
| 27 | +import com.facebook.react.common.annotations.UnstableReactNativeAPI; |
25 | 28 | import com.facebook.react.modules.core.ChoreographerCompat; |
26 | 29 | import com.facebook.react.modules.core.DeviceEventManagerModule; |
27 | 30 | import com.facebook.react.modules.core.ReactChoreographer; |
| 31 | +import com.facebook.react.runtime.ReactHostDelegate; |
28 | 32 |
|
29 | 33 | import org.json.JSONArray; |
30 | 34 | import org.json.JSONException; |
@@ -122,15 +126,38 @@ private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBu |
122 | 126 | latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile); |
123 | 127 | } |
124 | 128 |
|
125 | | - Field bundleLoaderField = instanceManager.getClass().getDeclaredField("mBundleLoader"); |
126 | | - bundleLoaderField.setAccessible(true); |
127 | | - bundleLoaderField.set(instanceManager, latestJSBundleLoader); |
| 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); |
128 | 138 | } catch (Exception e) { |
129 | 139 | CodePushUtils.log("Unable to set JSBundle - CodePush may not support this version of React Native"); |
130 | 140 | throw new IllegalAccessException("Could not setJSBundle"); |
131 | 141 | } |
132 | 142 | } |
133 | 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 | + |
134 | 161 | private void loadBundle() { |
135 | 162 | clearLifecycleEventListener(); |
136 | 163 | try { |
@@ -161,7 +188,7 @@ public void run() { |
161 | 188 | // reload method introduced in RN 0.74 (https://github.com/reactwg/react-native-new-architecture/discussions/174) |
162 | 189 | // so, we need to check if reload method exists and call it |
163 | 190 | try { |
164 | | - ReactDelegate reactDelegate = CodePushNativeModule.this.resolveReactDelegate(); |
| 191 | + ReactDelegate reactDelegate = resolveReactDelegate(); |
165 | 192 | if (reactDelegate == null) { |
166 | 193 | throw new NoSuchMethodException("ReactDelegate doesn't have reload method in RN < 0.74"); |
167 | 194 | } |
@@ -229,6 +256,21 @@ private ReactDelegate resolveReactDelegate() { |
229 | 256 | } |
230 | 257 | } |
231 | 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 | + |
232 | 274 | // Use reflection to find the ReactInstanceManager. See #556 for a proposal for a less brittle way to approach this. |
233 | 275 | private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException { |
234 | 276 | ReactInstanceManager instanceManager = CodePush.getReactInstanceManager(); |
|
0 commit comments