Fix WebSocket failure on Android release builds#16
Merged
saeedvaziry merged 1 commit intoMay 10, 2026
Conversation
Android 9+ blocks cleartext traffic by default, so release builds refused the local-network ws:// connection to the Mac while debug worked via the per-variant manifest override. Add expo-build-properties with android.usesCleartextTraffic=true so prebuild emits the flag on the main manifest.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release Android builds fail to open the
ws://connection to the Mac while debug builds (Expo Go andexpo run:android) connect fine. Root cause: Android 9+ blocks cleartext network traffic by default, and the release manifest had no override.Root cause
The client connects via cleartext WebSocket:
src/state/connection.ts:8—url: 'ws://0.0.0.0:0'src/state/connection.ts:112—client.setUrl(\ws://${active.host}:${active.port}`)`src/state/pair.ts:38—const url = \ws://${host}:${port}``Cleartext is permitted in debug because the per-variant manifests include the override:
android/app/src/debug/AndroidManifest.xml—android:usesCleartextTraffic="true"android/app/src/debugOptimized/AndroidManifest.xml— sameThe release/main manifest (
android/app/src/main/AndroidManifest.xml) had no such flag, so Android refused the socket and the user saw a generic WebSocket error.Fix
Add the
expo-build-propertiesconfig plugin so prebuild emitsandroid:usesCleartextTraffic="true"on the main manifest:/androidis gitignored, so the plugin inapp.jsonis the source of truth — runningnpx expo prebuild --platform android(or any flow that triggers prebuild) re-applies the flag on every regeneration.Files changed
app.json— registersexpo-build-propertiesplugin withandroid.usesCleartextTraffic: truepackage.json/package-lock.json— addsexpo-build-propertiesdep (installed vianpx expo install)Security note
This blanket-allows cleartext to any host. For a LAN-only companion app it's acceptable. If a stricter posture is preferred, swap in a
network_security_config.xmlthat allows cleartext only to private ranges (10/8, 172.16/12, 192.168/16, 169.254/16) — happy to follow up with that change.Test plan
npm run typecheckpassesnpm run lintpassesnpx expo prebuild --platform android --cleanregeneratesandroid/app/src/main/AndroidManifest.xmlwithandroid:usesCleartextTraffic="true"on the<application>tagws://on the local network