authorgravatar for 91240327+shivamhwp@users.noreply.github.comshivam <91240327+shivamhwp@users.noreply.github.com> 2026-10-12 20:00:52+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-12 20:00:52+05:30
log7b6d90757415f7897bac1a39e42cfb1331c97ee5
treeba9fd02496a963acfd9ebcf25d1a2621c649cdc7
parent5753207d53362608f281738eda3a9faf4e13b6be
signature Signed by PGP key B5690EEEBB952194

fix(mobile): iPhones on iOS 27.2 beta no longer open to a black screen (#18654)

Co-authored-by: T3 Code Test <t3code-test@example.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

2 files changed, 30 insertions(+), 5 deletions(-)

apps/mobile/modules/t3-native-controls/ios/T3LayoutMetricsView.swift+12
......@@ -35,9 +35,21 @@ final class T3LayoutMetricsView: ExpoView {
3535 override func didMoveToWindow() {
3636 super.didMoveToWindow()
3737 lastMetrics = nil
38 assumeNoHingeIfSilent()
3839 publishMetrics()
3940 }
4041
42 /// UIKit only sends hinge updates on devices that have a hinge. Without this,
43 /// an ordinary iPhone never publishes and the navigator never attaches.
44 private func assumeNoHingeIfSilent() {
45 guard window != nil, hasHinge == nil else { return }
46 DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
47 guard let self, self.window != nil, self.hasHinge == nil else { return }
48 self.hasHinge = false
49 self.publishMetrics()
50 }
51 }
52
4153 override func layoutSubviews() {
4254 super.layoutSubviews()
4355 publishMetrics()
apps/mobile/src/native/NativeWorkspaceColumns.ios.tsx+18-5
......@@ -1,4 +1,5 @@
11import { requireOptionalNativeModule } from "expo";
2import { useEffect, useState } from "react";
23import { Platform } from "react-native";
34import { useNativeLayoutMetrics } from "./native-layout-metrics";
45
......@@ -9,15 +10,27 @@ const nativeControls = requireOptionalNativeModule<{
910export const NATIVE_WORKSPACE_COLUMNS_SUPPORTED =
1011 Platform.OS === "ios" && Platform.isPad && nativeControls?.supportsWorkspaceColumns === true;
1112
13// Binaries without the native no-hinge fallback never report metrics on ordinary
14// iPhones running iOS 27.1 or later. Use the compact navigator rather than staying blank.
15const NATIVE_METRICS_TIMEOUT_MS = 1000;
16
1217export function useNativeWorkspaceColumnsReady() {
1318 const metrics = useNativeLayoutMetrics();
19 const [timedOut, setTimedOut] = useState(false);
1420 // Choose the phone's native host before attaching any screens. Older clients
1521 // without the observer can immediately use the compact navigator.
16 return (
17 (Platform.OS === "ios" && Platform.isPad) ||
18 !nativeControls?.ViewPrototypes?.T3NativeControls_LayoutMetrics ||
19 metrics !== null
20 );
22 const waiting =
23 !(Platform.OS === "ios" && Platform.isPad) &&
24 !!nativeControls?.ViewPrototypes?.T3NativeControls_LayoutMetrics &&
25 metrics === null;
26
27 useEffect(() => {
28 if (!waiting) return;
29 const timeout = setTimeout(() => setTimedOut(true), NATIVE_METRICS_TIMEOUT_MS);
30 return () => clearTimeout(timeout);
31 }, [waiting]);
32
33 return !waiting || timedOut;
2134}
2235
2336export function useNativeWorkspaceColumnsSupported() {