惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
B
Blog RSS Feed
量子位
aimingoo的专栏
aimingoo的专栏
V
Visual Studio Blog
Y
Y Combinator Blog
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
宝玉的分享
宝玉的分享
Engineering at Meta
Engineering at Meta
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
Stack Overflow Blog
Stack Overflow Blog
大猫的无限游戏
大猫的无限游戏
Microsoft Security Blog
Microsoft Security Blog
B
Blog
Last Week in AI
Last Week in AI
有赞技术团队
有赞技术团队
博客园 - 聂微东
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
J
Java Code Geeks

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Wi-Fi ADB Lies to You: The Silent Disconnect Problem No O...
hiyoyo · 2026-06-03 · via DEV Community

All results from shipping Mac×Android tools as a solo developer. Tested across multiple Android versions including Android 16.

I lost 4 hours to a silent Wi-Fi ADB disconnect. The device showed as connected. Commands returned nothing. No error, no crash — just silence. Here's the keepalive pattern that fixed it, and everything else I learned building HiyokoAutoSync on top of Wi-Fi ADB.


Speed comparison

Operation USB Wi-Fi (same network)
adb push 100MB file ~3–5s ~8–15s
adb shell command <50ms 80–200ms
Screenshot capture ~200ms ~400–700ms
Log streaming Stable Occasional drop

Wi-Fi ADB runs over TCP/IP on port 5555. You're limited by your local network throughput, not USB 2.0/3.0. On a congested network, latency spikes unpredictably.

For file sync use cases — pushing a few hundred MB — the gap is real but livable. For anything real-time (log streaming, screen mirroring), USB wins clearly.


The silent disconnect problem

USB is deterministic. The connection either works or it doesn't, and when it breaks, you know immediately.

Wi-Fi ADB drops silently. adb devices still shows the device as connected for several seconds after it's actually gone. If you're building a tool on top of ADB, you need explicit keepalive logic — or you'll spend hours debugging commands that appear to run but do nothing.

// Keepalive pattern for Wi-Fi ADB in Rust
async fn check_connection(device_id: &str) -> bool {
    let output = Command::new("adb")
        .args(["-s", device_id, "shell", "echo", "ok"])
        .output()
        .await;

    match output {
        Ok(out) => out.status.success(),
        Err(_) => false,
    }
}

Poll this every 5 seconds in a background task. When it returns false, mark the device as disconnected immediately — don't wait for the next command to fail.


The Android 16 wrinkle

Android 16 tightened wireless debugging permissions. On some devices, Wi-Fi ADB now requires re-pairing after reboot even if you previously paired via QR code. USB connections are unaffected.

If your users are on Android 16 and hitting "device not found" after a restart, this is likely why. HiyokoShot broke on Android 16 for exactly this reason — the pairing state wasn't persisting across reboots on certain OEMs.


When to use USB

  • File transfer (anything over 50MB)
  • Real-time log streaming
  • Screen mirroring / scrcpy
  • First-time setup and pairing
  • Debugging connection issues

When to use Wi-Fi

  • Quick shell commands while the phone is across the room
  • Automated background sync (if you handle reconnection logic)
  • Situations where plugging in isn't practical
  • Testing on a device mounted in a fixed location

Setting up Wi-Fi ADB (Android 11+)

# On the device: Developer Options → Wireless debugging → Pair device with pairing code
# Then on Mac:
adb pair 192.168.1.x:PORT
# Enter the pairing code shown on the device

adb connect 192.168.1.x:5555
adb devices
# Should show: 192.168.1.x:5555  device

Android 10 and below requires USB first:

adb tcpip 5555
# Unplug USB
adb connect 192.168.1.x:5555


The hybrid approach: USB → Wi-Fi auto-switch

The most robust setup is USB for initial connection, then automatic switch to Wi-Fi. Here's the actual implementation pattern:

// 1. Detect connection type from `adb devices` output
fn is_wifi_device(device_id: &str) -> bool {
    // Wi-Fi devices appear as IP:PORT, USB devices as serial numbers
    device_id.contains(':')
}

// 2. Switch a USB-connected device to TCP mode
async fn switch_to_wifi(serial: &str) -> Result<String, String> {
    // Enable TCP on the device
    Command::new("adb")
        .args(["-s", serial, "tcpip", "5555"])
        .output()
        .await
        .map_err(|e| e.to_string())?;

    // Get device IP via shell
    let output = Command::new("adb")
        .args(["-s", serial, "shell", "ip", "route"])
        .output()
        .await
        .map_err(|e| e.to_string())?;

    let ip = parse_device_ip(&String::from_utf8_lossy(&output.stdout))?;

    // Connect over Wi-Fi
    Command::new("adb")
        .args(["connect", &format!("{}:5555", ip)])
        .output()
        .await
        .map_err(|e| e.to_string())?;

    Ok(format!("{}:5555", ip))
}

// 3. Monitor with keepalive loop
async fn monitor_connection(device_id: String, tx: Sender<DeviceEvent>) {
    loop {
        tokio::time::sleep(Duration::from_secs(5)).await;
        if !check_connection(&device_id).await {
            tx.send(DeviceEvent::Disconnected(device_id.clone())).ok();
            break;
        }
    }
}

Connect once via USB, call switch_to_wifi(), then hand the new IP-based device ID to the monitor loop. The cable can be unplugged immediately after the switch completes.


The verdict

USB is the safer default. Wi-Fi unlocks real convenience but requires you to handle reconnection explicitly — something most ADB tutorials skip entirely.

If you're building on top of ADB, design for Wi-Fi disconnects from day one. Retrofitting that logic is painful.

What's your default — cable or wireless? Curious how others handle the reconnection problem.


I built HiyokoAutoSync around exactly this pattern — USB setup, automatic Wi-Fi switch, background keepalive. If you're doing Mac×Android sync without a cable, it might save you some time.
HiyokoAutoSync → https://hiyokomtp.lemonsqueezy.com/checkout/buy/20c922f1-ca45-4f77-aeb2-04e34aad2fb4
X → @hiyoyok