-
-
Notifications
You must be signed in to change notification settings - Fork 103
Open
Description
TCP Socket Connection Works on iOS but Fails on Android
Environment
- Platform: React Native (Expo)
- Library:
react-native-tcp-socket - iOS: ✅ Working
- Android: ❌ Not working
- Use Case: Scanning subnet for printers on port 9100
Description
I'm implementing a network scanner to discover ESC/POS printers by scanning all IPs in a subnet on port 9100. The implementation works perfectly on iOS but completely fails on Android, even with all necessary permissions configured.
Code Implementation
Function 1: Basic TCP Port Check
function tcpCheckPort(host: string, port: number, timeoutMs = 1500): Promise<boolean> {
return new Promise((resolve) => {
let finished = false;
let timer: ReturnType<typeof setTimeout>;
const done = (ok: boolean, reason: string) => {
if (finished) return;
finished = true;
if (timer) clearTimeout(timer);
try {
socket.destroy();
} catch (e) {
// ignore destroy errors
}
if (ok) {
console.log(`✅ ${host}:${port} - ${reason}`);
}
resolve(ok);
};
console.log(`[${Platform.OS}] Attempting connection to ${host}:${port}...`);
const socket = TcpSocket.createConnection(
{ host, port },
() => {
// Connection established successfully
done(true, 'connected');
}
);
socket.on('error', (err: any) => {
console.log(`[${Platform.OS}] Connection error to ${host}:${port}: ${err?.message || 'unknown'}`);
done(false, `error: ${err?.message || 'unknown'}`);
});
socket.on('close', (hadError: boolean) => {
if (!finished) {
done(true, 'closed after accept');
}
});
timer = setTimeout(() => {
done(false, 'timeout');
}, timeoutMs);
});
}Function 2: ESC/POS Command Test
async function testPrinterConnection(host: string, port: number = 9100, timeoutMs = 2000): Promise<boolean> {
return new Promise((resolve) => {
let finished = false;
let timer: ReturnType<typeof setTimeout>;
const done = (ok: boolean, reason: string) => {
if (finished) return;
finished = true;
if (timer) clearTimeout(timer);
try {
socket.destroy();
} catch (e) {
// ignore destroy errors
}
if (ok) {
console.log(`✅ ${host}:${port} - Printer detected: ${reason}`);
}
resolve(ok);
};
const socket = TcpSocket.createConnection(
{ host, port },
() => {
try {
// Send ESC/POS initialization command (0x1B 0x40)
const escInit = Buffer.from([0x1b, 0x40]); // ESC @
socket.write(escInit, 'binary', (err) => {
if (err) {
done(false, `write error: ${err?.message || 'unknown'}`);
} else {
done(true, 'ESC/POS command accepted');
}
});
setTimeout(() => {
try {
socket.end();
} catch (e) {
// ignore
}
}, 200);
} catch (err: any) {
done(false, `initialization error: ${err?.message || 'unknown'}`);
}
}
);
socket.on('error', (err: any) => {
done(false, `error: ${err?.message || 'unknown'}`);
});
socket.on('close', (hadError: boolean) => {
if (!finished) {
done(false, 'closed before write');
}
});
timer = setTimeout(() => {
done(false, 'timeout');
}, timeoutMs);
});
}Android Configuration
app.json
{
"expo": {
"android": {
"usesCleartextTraffic": true,
"permissions": [
"INTERNET",
"ACCESS_NETWORK_STATE",
"ACCESS_WIFI_STATE",
"CHANGE_WIFI_STATE"
]
}
}
}AndroidManifest.xml (after prebuild)
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application
android:usesCleartextTraffic="true"
...>Observed Behavior
iOS (Working ✅)
- Successfully scans all IPs in subnet
- Correctly identifies printers on port 9100
- Both
tcpCheckPortandtestPrinterConnectionwork - Connection callbacks fire properly
- ESC/POS commands are delivered successfully
Android (Not Working ❌)
- Connections appear to time out
- No successful connections detected
- No error messages in
adb logcat - Both functions fail silently
- Timeouts occur even with known working printer IPs
Questions
- Is there a known issue with TCP socket connections on Android?
- Are there additional Android-specific configurations needed beyond cleartext traffic?
- Could this be related to IPv4/IPv6 handling differences between iOS and Android?
- Should I be using different socket options or events for Android?
- Is there a better approach for network scanning on Android?
What I've Tried
- ✅ Added all necessary permissions
- ✅ Enabled
usesCleartextTraffic - ✅ Tested with
npx expo prebuild --cleanandnpx expo run:android - ✅ Verified the same printer works from iOS device on the same network
- ✅ Checked
adb logcatfor errors (none found) - ✅ Tested with different timeout values
Expected Behavior
TCP socket connections should work consistently across both iOS and Android platforms, allowing subnet scanning for printer discovery.
Additional Context
- Using Expo managed workflow with custom development build
- Target printer: ESC/POS compatible printer on port 9100
- Network: Local WiFi subnet (e.g., 192.168.1.0/24)
- Both devices (iOS/Android) are on the same network
Any guidance on Android-specific requirements or better approaches would be greatly appreciated!
Metadata
Metadata
Assignees
Labels
No labels