Skip to content

Commit 61560ff

Browse files
msluszniakclaude
andauthored
fix(ios): raise deployment target to 17.0 and stabilize Babel hoisting (#1085)
## Summary - Bumps the iOS deployment target from 15.1 to 17.0 everywhere (podspec, tracked app xcodeprojs and Podfile, Expo apps via `expo-build-properties`) so the target matches the prebuilt executorch libraries (minos 17.0). Silences the "was built for newer iOS version" linker warnings that previously ran at the end of every iOS build. - Re-adds `expo-router` to the workspace root `devDependencies` so Yarn hoists it next to `babel-preset-expo`. Without this, `babel-preset-expo`'s `require.resolve('expo-router')` check fails, its expo-router Babel plugin is never registered, `process.env.EXPO_ROUTER_APP_ROOT` stays un-inlined, and Metro rejects `require.context` in `expo-router/_ctx.ios.js`. Reverts the incidental breakage from #1083. - Scopes `logFilters` in `.yarnrc.yml` to silence the YN0002 lines for the root workspace's expo-router peers (and the YN0086 summary). Warnings from any other workspace still surface. The mechanism mirrors the existing `@signalwire/docusaurus-theme-llms-txt` filter. - Updates React Native Audio Api to version 0.12.0 ### Why iOS 17 specifically The executorch prebuilt libraries (`libexecutorch_ios.a`, `libbackend_xnnpack_ios.a`, etc.) and `ExecutorchLib.xcframework` are built with `minos=17.0`. Linking them into an app with a lower deployment target produces a run of linker warnings on every build. README already documents iOS 17.0 as the minimum supported version, so this change also brings build configs in line with the docs. ### Remaining warnings after this PR - **phonemis** — shipped with `minos=26.0`, which is way above the app target. Out of scope here; the library is being rebuilt by a separate team member. - **pthreadpool** (minos 12/14) and **cpuinfo** (LC_VERSION_MIN 11) — *below* 17.0, so they don't trigger "built for newer" warnings. No action needed today; worth rebuilding next time those libraries touch the repo for consistency. ## Test plan - [ ] `yarn` at repo root completes without YN0002 / YN0086 warnings (PR #1083's original goal, preserved). - [ ] For each Expo app (`apps/{llm,computer-vision,speech,text-embeddings}`): `rm -rf ios && yarn ios` successfully prebuilds, installs pods, and builds. - [ ] In each app's build log, the previous block of "object file was built for newer iOS version (17.0) than being linked (15.1)" warnings from executorch libs is gone. - [ ] `apps/bare-rn`: `pod install && yarn ios` builds; no executorch version-mismatch linker warnings. - [ ] Metro bundles successfully for Expo apps using expo-router (`llm`, `computer-vision`, `text-embeddings`) — the `_ctx.ios.js` `require.context` error reported during development is resolved by the hoist fix. - [ ] `apps/llm` builds on Xcode 26.4 without the `size_t` / `Constants.h` compile error from `react-native-audio-api`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a46ec71 commit 61560ff

16 files changed

Lines changed: 85 additions & 30 deletions

File tree

.yarnrc.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,25 @@ nodeLinker: node-modules
1515
# a React 19-compatible peer range, bump it in docs/package.json and
1616
# remove this filter — we'd rather follow upstream than carry a local
1717
# suppression.
18+
#
19+
# The root workspace declares `expo-router` as a devDependency only to
20+
# force Yarn to hoist it into the root node_modules alongside
21+
# babel-preset-expo. babel-preset-expo calls require.resolve('expo-router')
22+
# from its own location to decide whether to register the expo-router Babel
23+
# plugin; if the two packages live in different node_modules folders (which
24+
# happens when expo-router ends up per-app and babel-preset-expo is hoisted),
25+
# process.env.EXPO_ROUTER_APP_ROOT never gets replaced and Metro fails to
26+
# bundle expo-router/_ctx.ios.js. Because the root workspace doesn't actually
27+
# execute expo-router code, it legitimately doesn't provide its peers — each
28+
# app that consumes expo-router declares them directly. The pattern below
29+
# silences the resulting YN0002 lines about the ROOT workspace only;
30+
# unmet peer warnings from any other workspace still surface.
1831
logFilters:
1932
- pattern: '*@signalwire/docusaurus-theme-llms-txt*'
2033
level: discard
34+
- pattern: "react-native-executorch-monorepo@workspace:. doesn't provide*requested by expo-router*"
35+
level: discard
36+
- code: YN0086
37+
level: discard
2138

2239
yarnPath: .yarn/releases/yarn-4.1.1.cjs

apps/bare-rn/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ require Pod::Executable.execute_command('node', ['-p',
55
{paths: [process.argv[1]]},
66
)', __dir__]).strip
77

8-
platform :ios, min_ios_version_supported
8+
platform :ios, '17.0'
99
prepare_react_native_project!
1010

1111
linkage = ENV['USE_FRAMEWORKS']

apps/bare-rn/ios/bare-rn.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@
262262
CURRENT_PROJECT_VERSION = 1;
263263
ENABLE_BITCODE = NO;
264264
INFOPLIST_FILE = "bare-rn/Info.plist";
265-
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
265+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
266266
LD_RUNPATH_SEARCH_PATHS = (
267267
"$(inherited)",
268268
"@executable_path/Frameworks",
@@ -291,7 +291,7 @@
291291
CLANG_ENABLE_MODULES = YES;
292292
CURRENT_PROJECT_VERSION = 1;
293293
INFOPLIST_FILE = "bare-rn/Info.plist";
294-
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
294+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
295295
LD_RUNPATH_SEARCH_PATHS = (
296296
"$(inherited)",
297297
"@executable_path/Frameworks",
@@ -360,7 +360,7 @@
360360
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
361361
GCC_WARN_UNUSED_FUNCTION = YES;
362362
GCC_WARN_UNUSED_VARIABLE = YES;
363-
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
363+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
364364
LD_RUNPATH_SEARCH_PATHS = (
365365
/usr/lib/swift,
366366
"$(inherited)",
@@ -429,7 +429,7 @@
429429
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
430430
GCC_WARN_UNUSED_FUNCTION = YES;
431431
GCC_WARN_UNUSED_VARIABLE = YES;
432-
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
432+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
433433
LD_RUNPATH_SEARCH_PATHS = (
434434
/usr/lib/swift,
435435
"$(inherited)",

apps/computer-vision/app.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
{
4040
"android": {
4141
"minSdkVersion": 26
42+
},
43+
"ios": {
44+
"deploymentTarget": "17.0"
4245
}
4346
}
4447
]

apps/llm/app.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@
3838
"androidForegroundService": true,
3939
"androidFSTypes": ["mediaPlayback"]
4040
}
41+
],
42+
[
43+
"expo-build-properties",
44+
{
45+
"ios": {
46+
"deploymentTarget": "17.0"
47+
}
48+
}
4149
]
4250
],
4351
"newArchEnabled": true,

apps/llm/app/voice_chat/index.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,7 @@ function VoiceChatScreen() {
6969
useState<STTModelSources>(WHISPER_TINY_EN);
7070
const [error, setError] = useState<string | null>(null);
7171

72-
const [recorder] = useState(
73-
() =>
74-
new AudioRecorder({
75-
sampleRate: 16000,
76-
bufferLengthInSamples: 1600,
77-
})
78-
);
72+
const [recorder] = useState(() => new AudioRecorder());
7973

8074
const { setGlobalGenerating } = useContext(GeneratingContext);
8175

@@ -92,7 +86,7 @@ function VoiceChatScreen() {
9286
AudioManager.setAudioSessionOptions({
9387
iosCategory: 'playAndRecord',
9488
iosMode: 'spokenAudio',
95-
iosOptions: ['allowBluetooth', 'defaultToSpeaker'],
89+
iosOptions: ['allowBluetoothHFP', 'defaultToSpeaker'],
9690
});
9791
AudioManager.requestRecordingPermissions();
9892
}, []);
@@ -106,9 +100,17 @@ function VoiceChatScreen() {
106100
setIsRecording(true);
107101
setLiveTranscription('');
108102

109-
recorder.onAudioReady(({ buffer }) => {
110-
speechToText.streamInsert(buffer.getChannelData(0));
111-
});
103+
const sampleRate = 16000;
104+
recorder.onAudioReady(
105+
{
106+
sampleRate,
107+
bufferLength: 0.1 * sampleRate,
108+
channelCount: 1,
109+
},
110+
({ buffer }) => {
111+
speechToText.streamInsert(buffer.getChannelData(0));
112+
}
113+
);
112114
recorder.start();
113115

114116
let finalResult = '';

apps/llm/metro.config.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
const { getDefaultConfig } = require('expo/metro-config');
2-
const {
3-
wrapWithAudioAPIMetroConfig,
4-
} = require('react-native-audio-api/metro-config');
52

63
const config = getDefaultConfig(__dirname);
74

@@ -19,4 +16,4 @@ config.resolver = {
1916

2017
config.resolver.assetExts.push('pte');
2118

22-
module.exports = wrapWithAudioAPIMetroConfig(config);
19+
module.exports = config;

apps/llm/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@react-navigation/native": "^7.1.28",
1717
"expo": "^54.0.27",
1818
"expo-brightness": "~14.0.8",
19+
"expo-build-properties": "~1.0.10",
1920
"expo-calendar": "~15.0.8",
2021
"expo-constants": "~18.0.11",
2122
"expo-document-picker": "~13.0.3",
@@ -26,7 +27,7 @@
2627
"metro-config": "^0.81.5",
2728
"react": "19.1.0",
2829
"react-native": "0.81.5",
29-
"react-native-audio-api": "^0.8.2",
30+
"react-native-audio-api": "0.12.0",
3031
"react-native-device-info": "^15.0.2",
3132
"react-native-executorch": "workspace:*",
3233
"react-native-executorch-expo-resource-fetcher": "workspace:*",

apps/speech/app.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@
5454
"androidForegroundService": true,
5555
"androidFSTypes": ["mediaPlayback", "microphone"]
5656
}
57+
],
58+
[
59+
"expo-build-properties",
60+
{
61+
"ios": {
62+
"deploymentTarget": "17.0"
63+
}
64+
}
5765
]
5866
]
5967
}

apps/speech/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@react-native/metro-config": "^0.84.0",
1515
"buffer": "^6.0.3",
1616
"expo": "^54.0.27",
17+
"expo-build-properties": "~1.0.10",
1718
"expo-font": "~14.0.10",
1819
"expo-status-bar": "~3.0.9",
1920
"metro-config": "^0.81.5",

0 commit comments

Comments
 (0)