Skip to content

Work / Aakalan / Wiki / Concepts

expo-contacts-pinned

Conceptverified 2026-10-30

expo-contacts-pinned

expo-contacts stays pinned to an exact 57.0.4. SDK 57 links Expo's modules as prebuilt xcframeworks (EXPO_USE_PRECOMPILED_MODULES, on by default), so a bad artifact is a bug inherited without changing a line.

57.0.5, the version the SDK asks for, ships an ExpoContacts.xcframework that links @rpath/Testing.framework/Testing (Swift Testing), which no app bundle carries. Their podspec's exclude_files = 'Tests/' does not match the files inside that directory, so their build compiled the test target into the shipped binary. The npm tarball has no Tests/, so nothing in this repo reproduces it and reading the source tells you nothing.

The pin alone is not enough. b2d3cb0 set this pin with no reason and the version came back: expo-doctor flags a pin below the SDK's range, and the fix it prints, npx expo install --check, reinstalls the broken build. package.json stays clean while node_modules is not, so pnpm install says "Already up to date" and the next pnpm ios crashes at launch. expo.install.exclude in package.json carries expo-contacts, which stops doctor asking.

Unpin only when a release comes back clean from the otool check in ops/runbooks/ios-launch-crash.md, and take it off the exclude list in the same commit.

Turning precompiled modules off is not an escape hatch. ios.useFrameworks: "dynamic" is mandatory for react-native-firebase's SPM use, and the logic that keeps pods with React headers in their public API from being built as dynamic frameworks lives behind the same flag. Without it RNPurchases links as a framework and fails on _OBJC_CLASS_$_RCTEventEmitter, because the prebuilt React is not linkable that way. expo-modules-autolinking has no per-module opt-out: it is the whole switch or nothing, and nothing is the right choice.