Created
December 24, 2025 12:30
-
-
Save smontlouis/0ac5998239a4a6a7b8909c1f3ee36ee2 to your computer and use it in GitHub Desktop.
expo 54 android webview fix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/async-require/setupHMR.ts b/src/async-require/setupHMR.ts | |
| index 1278b6eb12c4702d2c2487d7780266c454e5116e..d8ef51578019b46e9ce84b7ce0ccd145005dc065 100644 | |
| --- a/src/async-require/setupHMR.ts | |
| +++ b/src/async-require/setupHMR.ts | |
| @@ -3,7 +3,7 @@ import HMRClient from './hmr'; | |
| if ( | |
| typeof window !== 'undefined' && | |
| // @ts-expect-error: Added via react-native-webview | |
| - typeof window.$$EXPO_INITIAL_PROPS !== 'undefined' | |
| + typeof window.ReactNativeWebView !== 'undefined' | |
| ) { | |
| // Sets up developer tools for web platforms when running in a webview. This ensures that logs are visible in the terminal. | |
| // We assume full control over the console and send JavaScript logs to Metro. | |
| diff --git a/src/dom/dom-entry.tsx b/src/dom/dom-entry.tsx | |
| index f908ff5afb9706976038f2f9c4cf449dfa6cffd0..9b98cf9c38cddbf827a3e9b67081243835e1eae3 100644 | |
| --- a/src/dom/dom-entry.tsx | |
| +++ b/src/dom/dom-entry.tsx | |
| @@ -68,11 +68,6 @@ export function registerDOMComponent(AppModule: any) { | |
| function DOMComponentRoot(props: Record<string, unknown>) { | |
| // Props listeners | |
| const [marshalledProps, setProps] = React.useState(() => { | |
| - if (typeof window.$$EXPO_INITIAL_PROPS === 'undefined') { | |
| - throw new Error( | |
| - 'Initial props are not defined. This is a bug in the DOM Component runtime.' | |
| - ); | |
| - } | |
| return window.$$EXPO_INITIAL_PROPS; | |
| }); | |
| @@ -88,7 +83,7 @@ export function registerDOMComponent(AppModule: any) { | |
| }, [setProps]); | |
| const proxyActions = React.useMemo(() => { | |
| - if (!marshalledProps.names) return {}; | |
| + if (!marshalledProps?.names) return {}; | |
| // Create a named map { [name: string]: ProxyFunction } | |
| // TODO(@kitten): Unclear how this is typed or shaped | |
| return Object.fromEntries( | |
| @@ -96,7 +91,11 @@ export function registerDOMComponent(AppModule: any) { | |
| return [key, ACTIONS[key]]; | |
| }) | |
| ); | |
| - }, [marshalledProps.names]); | |
| + }, [marshalledProps?.names]); | |
| + | |
| + if (!marshalledProps) { | |
| + return null; | |
| + } | |
| return <AppModule {...props} {...(marshalledProps.props || {})} {...proxyActions} />; | |
| } | |
| diff --git a/src/dom/dom-hooks.ts b/src/dom/dom-hooks.ts | |
| index 1e29db942615b8d5b00afb94733e5c599b731d3f..4ca022d1360f1c33ba3393820b6f436c2c56291a 100644 | |
| --- a/src/dom/dom-hooks.ts | |
| +++ b/src/dom/dom-hooks.ts | |
| @@ -18,9 +18,7 @@ export function useDOMImperativeHandle<T extends DOMImperativeFactory>( | |
| ) { | |
| const isTargetWeb = | |
| // @ts-expect-error: Added via react-native-webview | |
| - typeof window.ReactNativeWebView === 'undefined' && | |
| - // @ts-expect-error: Added via expo/dom | |
| - typeof window.$$EXPO_INITIAL_PROPS === 'undefined'; | |
| + typeof window.ReactNativeWebView === 'undefined'; | |
| const stubHandlerFactory = useCallback(() => ({}) as T, deps ?? []); | |
| diff --git a/src/dom/dom.web.ts b/src/dom/dom.web.ts | |
| index f582c496e859a05cc6c767e939f73ef42224fbd2..d269d1ae1768bf7d5667c70131e692e9335afaf7 100644 | |
| --- a/src/dom/dom.web.ts | |
| +++ b/src/dom/dom.web.ts | |
| @@ -2,5 +2,6 @@ export * from './dom-hooks'; | |
| // TODO: Maybe this could be a bundler global instead. | |
| export const IS_DOM = | |
| + typeof window !== 'undefined' && | |
| // @ts-expect-error: Added via react-native-webview | |
| - typeof $$EXPO_INITIAL_PROPS !== 'undefined'; | |
| + typeof window.ReactNativeWebView !== 'undefined'; | |
| diff --git a/src/dom/marshal.tsx b/src/dom/marshal.tsx | |
| index 26e42d6da28d5060ce6564377c7851d6850196b7..d19126e2c3ad9b9d35828fbc4a155339500d297a 100644 | |
| --- a/src/dom/marshal.tsx | |
| +++ b/src/dom/marshal.tsx | |
| @@ -3,8 +3,6 @@ import { DOM_EVENT, NATIVE_ACTION, NATIVE_ACTION_RESULT } from './injection'; | |
| const IS_DOM = | |
| typeof window !== 'undefined' && | |
| - // @ts-expect-error: Added via expo/dom | |
| - typeof window.$$EXPO_INITIAL_PROPS !== 'undefined' && | |
| // @ts-expect-error: Added via react-native-webview | |
| typeof window.ReactNativeWebView !== 'undefined'; | |
| diff --git a/src/dom/webview-wrapper.tsx b/src/dom/webview-wrapper.tsx | |
| index 93041ac3cb77ebce5d3712a00269224cac494e57..d1a0c560c5376e1d815bfff985fe5f45b34705de 100644 | |
| --- a/src/dom/webview-wrapper.tsx | |
| +++ b/src/dom/webview-wrapper.tsx | |
| @@ -132,15 +132,24 @@ const RawWebView = React.forwardRef<object, Props>((props, ref) => { | |
| ...dom, | |
| containerStyle: [containerStyle, debugZeroHeightStyle, dom?.containerStyle], | |
| onLayout: __DEV__ ? debugOnLayout : dom?.onLayout, | |
| + onLoad: () => { | |
| + emit({ type: '$$props', data: smartActions }); | |
| + }, | |
| injectedJavaScriptBeforeContentLoaded: [ | |
| // On first mount, inject `$$EXPO_INITIAL_PROPS` with the initial props. | |
| `window.$$EXPO_INITIAL_PROPS = ${JSON.stringify(smartActions)};true;`, | |
| - dom?.matchContents ? getInjectBodySizeObserverScript() : null, | |
| dom?.injectedJavaScriptBeforeContentLoaded, | |
| 'true;', | |
| ] | |
| .filter(Boolean) | |
| .join('\n'), | |
| + injectedJavaScript: [ | |
| + dom?.matchContents ? getInjectBodySizeObserverScript() : null, | |
| + dom?.injectedJavaScript, | |
| + 'true;', | |
| + ] | |
| + .filter(Boolean) | |
| + .join('\n'), | |
| // @ts-expect-error: TODO(@kitten): untyped ref for now | |
| ref: webviewRef, | |
| source, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment