EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Linux / ทำ Android dev บน MIUI/HyperOS แล้ว adb ทำงานไม่ได้ — กับดักบน Windows
Linux

ทำ Android dev บน MIUI/HyperOS แล้ว adb ทำงานไม่ได้ — กับดักบน Windows

โดย Ton-Or ·23 ก.ค. 2026·อ่าน 8 นาที
ทำ Android dev บน MIUI/HyperOS แล้ว adb ทำงานไม่ได้ — กับดักบน Windows

adb ขึ้น INSTALL_FAILED, ไฟล์ screenshot เป็น 0 ไบต์, path /sdcard เพี้ยนไปโผล่ในโฟลเดอร์ Git — สามอาการนี้ไม่ได้แปลว่าเครื่องพัง แต่คือ Windows, Git Bash, PowerShell และ MIUI ต่างคนต่างแทรกมือใส่ adb กันคนละจุด

พอดีช่วงนี้ผมทำแอป Android ที่เขียนด้วย Jetpack Compose มี backend เป็น Laravel แล้วยิงลงเครื่องทดสอบเป็น Xiaomi ที่รัน MIUI/HyperOS โดยมี dev box เป็น Windows — พอเริ่มจริงก็เจอว่า adb "ทำงานไม่ได้" อยู่หลายจุด ทั้งที่ตัว adb เองปกติดี ปัญหาคือ Windows, Git Bash, PowerShell และ MIUI ต่างคนต่างเข้ามาแทรกกลางระหว่างคำสั่งกับเครื่องคนละท่า กว่าจะไล่ครบผมเสียเวลาไปเยอะ เลยรวมกับดักที่เจอจริงมาเล่าให้ฟัง พร้อมคำสั่งที่ใช้แล้วผ่าน

ชื่อ package (com.example.pos), serial เครื่อง และ path ในบทความเป็นตัวอย่าง ส่วนคำสั่งกับอาการคือของจริงทั้งหมด

กับดักที่ 1: Git Bash แปลง /sdcard/ ให้เพี้ยน

อาการแรกคือสั่ง adb push ลง /sdcard/Download/ แล้วไฟล์หายไปเฉยๆ ไม่ได้อยู่บนเครื่อง พอไปไล่ดูถึงเจอว่ามันไปโผล่บนดิสก์ที่ C:/Program Files/Git/sdcard/Download/ แทน สาเหตุคือ Git Bash (MSYS) แปลง path แบบ POSIX ให้อัตโนมัติ พอเจอ /sdcard/... มันเข้าใจว่าเป็น absolute path บน Windows เลยเติม prefix ของ Git ให้

ทำไม path เพี้ยนadb push ... /sdcard/พิมพ์ใน Git Bash→MSYS แปลง POSIX pathอัตโนมัติ→ไปโผล่ C:/Program Files/Git/sdcard/ผิดที่

ทางที่ผมใช้คือย้ายไปยิง adb push จาก PowerShell แทน — path ฝั่งอุปกรณ์ไม่โดนแปลงเลย:

$device = "abc123def456"
$apk = "app\build\outputs\apk\debug\app-debug.apk"
adb -s $device push $apk /sdcard/Download/app-beta.apk

ถ้าจำเป็นต้องอยู่ใน Git Bash จริงๆ ให้ปิดการแปลง path ด้วยตัวแปร MSYS_NO_PATHCONV เฉพาะคำสั่งนั้น:

MSYS_NO_PATHCONV=1 adb -s "$device" push "$apk" /sdcard/Download/app-beta.apk

ส่วนตัวผมเลือกทำงาน adb ทั้งหมดใน PowerShell ไปเลย จำกฎน้อยกว่า ไม่ต้องมานั่งจำว่าคำสั่งไหนมี path ฝั่งเครื่องบ้าง

กับดักที่ 2: PowerShell ทำไฟล์ screenshot เป็น 0 ไบต์

พอจะเก็บภาพหน้าจอเครื่องมาแนบรายงานเทสต์ ผมสั่งตามที่เคยชินบน Linux:

adb exec-out screencap -p > .tmp\screen.png

ได้ไฟล์ออกมาแต่เปิดไม่ขึ้น บางทีก็ 0 ไบต์ ต้นเหตุคือเครื่องหมาย > ใน PowerShell มันคือ Out-File ที่ยัด text encoding ให้ทุกอย่างที่ไหลผ่าน — พอเป็นสตรีมไบนารีอย่าง PNG ไบต์เลยถูกแปลงพัง ไม่ใช่ไฟล์ภาพเดิมอีกต่อไป

ที่พังบ่อย

ไพป์ผ่าน PowerShell ตรงๆ

ให้ไบต์ของ PNG ไหลผ่าน > ของ PowerShell — โดน text encoding เหยียบทุกไบต์ ได้ไฟล์ 0 ไบต์หรือเปิดไม่ขึ้น

ที่ใช้ได้จริง

ให้เครื่องเซฟเองแล้วค่อยดึง

screencap เขียนลง /sdcard บนเครื่องก่อน แล้ว adb pull กลับมา — ไบต์ไม่ผ่านมือ PowerShell เลย ภาพครบทุกครั้ง

วิธีที่ผมใช้แล้วได้ภาพครบทุกครั้งคือให้เครื่องเซฟลง /sdcard ก่อน แล้วค่อย adb pull กลับมา ไบต์ไม่ต้องผ่านมือ PowerShell เลย:

adb -s $device shell screencap -p /sdcard/screen.png
adb -s $device pull /sdcard/screen.png .tmp\screen.png
adb -s $device shell rm /sdcard/screen.png

ถ้าอยากไพป์ตรงจริงๆ ให้ใช้ redirect ของ cmd.exe แทน เพราะ cmd ไม่ยุ่งกับ encoding ของสตรีม:

adb exec-out screencap -p > screen.png

อีกจุดที่พลาดกันบ่อยคืออย่าเซฟลง C:\temp เพราะโฟลเดอร์นั้นอาจไม่มีอยู่จริง แล้ว PowerShell สร้างให้ไม่เหมือน Git Bash — เซฟลงโฟลเดอร์ในโปรเจกต์ (เช่น .tmp\) ที่มีอยู่แน่ๆ จะชัวร์กว่า

กับดักที่ 3: MIUI บล็อกการติดตั้งครั้งแรก

พอ build เสร็จจะติดตั้งลงเครื่องรอบแรก MIUI/HyperOS เด้งกลับมาแบบนี้:

adb: failed to install fresh.apk: Failure [INSTALL_FAILED_USER_RESTRICTED: Install canceled by user]

ทั้งที่ป๊อปอัปยืนยันบนเครื่องยังไม่ทันโผล่ด้วยซ้ำ สาเหตุคือ toggle "Install via USB" ใน Developer options ปิดอยู่ พอปิดไว้ MIUI จะบล็อกการติดตั้งครั้งแรกผ่าน adb ทุกกรณี ตัว toggle นี้ต้องล็อกอิน Mi Account และมีซิมในเครื่องถึงจะเปิดได้ ซึ่งเครื่องเทสต์บางเครื่องไม่มีซิมเสียบ ทางที่ผมใช้เลยเป็นการหลบด่านแทน — push APK ลง /sdcard แล้วแตะติดตั้งด้วยมือผ่านแอป Files บนเครื่อง เพราะการติดตั้งที่ผู้ใช้กดเองไม่ติดด่านนี้

  1. สั่ง assembleDebugAndroidTest ให้ได้ทั้ง APK แอปและ APK เทสต์ออกมา
  2. ติดตั้งครั้งแรกด้วยมือ — push APK ลง /sdcard แล้วแตะติดตั้งผ่านแอป Files บนเครื่อง (ข้ามด่าน MIUI)
  3. ครั้งต่อไปใช้ adb install -r ทับได้เงียบๆ ไม่โดนบล็อกอีก
  4. ยิงเทสต์ตรงด้วย am instrument ไม่ต้องพึ่ง gradle task

พอติดตั้งผ่านรอบแรกไปแล้ว การอัปเดตครั้งถัดไปใช้ธง -r (reinstall ทับ) ได้เงียบๆ MIUI ไม่ถามอีก:

.\gradlew.bat assembleDebugAndroidTest
# รอบแรก: push ให้ผู้ใช้ติดตั้งด้วยมือผ่าน Files
adb -s $device push app\build\outputs\apk\androidTest\debug\app-debug-androidTest.apk /sdcard/Download/
# รอบถัดไป: ทับได้เลยด้วย -r
adb -s $device install -r app\build\outputs\apk\androidTest\debug\app-debug-androidTest.apk

ที่สำคัญคืออย่าใช้ gradle task connectedAndroidTest บน MIUI — ให้ยิง am instrument ตรงแทน:

# รันทั้งชุด
adb -s $device shell am instrument -w -r -e debug false com.example.pos.test/androidx.test.runner.AndroidJUnitRunner
# รันเฉพาะคลาสเดียว
adb -s $device shell am instrument -w -r -e class com.example.pos.OwnerHomeTest com.example.pos.test/androidx.test.runner.AndroidJUnitRunner

-w คือรอจนจบ, -r คือ raw output ที่ parse ต่อได้

อย่าใช้ gradle connectedAndroidTest บน MIUI

task นี้จะถอนแอปหลักออกก่อนแล้วค่อยติดตั้งใหม่ พอการติดตั้งใหม่โดนด่าน MIUI ปัดตก เครื่องจะเหลือทั้งแอปหลักและแอปเทสต์ หายไปทั้งคู่ — ต้องมานั่งติดตั้งด้วยมือใหม่หมด ผมโดนมาแล้ว ให้ยิง am instrument ตรงแทนตั้งแต่แรก

อีกจุดที่เจอตอนรันชุดเทสต์ยาวเกินห้านาที คือ MIUI พักหน้าจอแล้ว activity หลุด focus ทำให้เทสต์ที่แตะหรือ scroll ล้มเป็นชุด กันด้วยการปลุกจอค้างไว้ก่อนเริ่ม:

adb -s $device shell input keyevent KEYCODE_WAKEUP
adb -s $device shell svc power stayon true

กับดักที่ 4: here-string ของ PowerShell กลืน backslash เวลาปั้นโค้ด PHP

กับดักตัวสุดท้ายอยู่ฝั่ง backend เวลาจะปั้น seed / test fixture ของ Laravel แล้วส่งขึ้นเซิร์ฟเวอร์ ผมเคยลองยัดโค้ด PHP หลายบรรทัดผ่าน here-string ของ PowerShell แล้ว pipe ขึ้น ssh — ปรากฏว่า backslash ในโค้ดโดนกลืนหายตั้งแต่ต้นทาง พอขึ้นไปถึงเซิร์ฟเวอร์ PHP จึงเป็น parse error แบบงงๆ ที่หาต้นเหตุยากมาก เพราะไฟล์ในเครื่องกับที่ส่งขึ้นไปหน้าตาไม่เหมือนกัน

อย่าปั้นโค้ด PHP ผ่าน here-string ของ PowerShell

backslash และตัว escape ในโค้ดจะโดนกลืน พอส่งขึ้นเซิร์ฟเวอร์ PHP จะ parse error แบบไล่ต้นเหตุยาก เพราะโค้ดต้นทางกับปลายทางไม่ตรงกัน — เขียนลงไฟล์ในเครื่องก่อนแล้วค่อย scp ขึ้นไปรัน ปลอดภัยกว่ามาก

วิธีที่ผมใช้คือเขียนโค้ดลงเป็นไฟล์จริงในเครื่องก่อน (ผ่าน editor ไม่ผ่าน here-string) แล้วค่อย scp ขึ้นไปรัน เสร็จแล้วลบไฟล์ชั่วคราวทิ้งทุกครั้ง:

scp .\scripts\seed.php host:/home/deploy/seed.php
ssh host "php /home/deploy/seed.php && rm -f /home/deploy/seed.php"

จุดที่ต้องระวังในไฟล์นั้นคืออย่าใส่ path แบบ Windows (D:\... หรือ C:\...) ลงในสคริปต์ที่จะไปรันบน Linux เด็ดขาด เพราะ backslash จะกลายเป็นชื่อไฟล์ประหลาดใน /tmp แล้วบางเซิร์ฟเวอร์มี monitor คอยจับชื่อไฟล์แปลกๆ อยู่ ใช้ path แบบ Linux ให้หมด แล้วเก็บกวาดไฟล์ชั่วคราวทุกครั้งหลังรันเสร็จ

สรุปลำดับที่ยิงแล้วไม่พลาด

พอไล่ครบทั้งสี่จุดแล้ว pipeline ที่ผมใช้ประจำจะเป็นแบบนี้ — เลือกเครื่องมือให้ถูกตัวในแต่ละสเต็ป ไม่สลับไปมา:

ลำดับที่ยิงแล้วไม่พลาดbuild + push ใน PowerShellไม่ใช่ Git Bash→ติดตั้งด้วยมือรอบแรกข้ามด่าน MIUI→adb install -r รอบถัดไป→am instrument ยิงเทสต์ไม่ใช้ gradle task→screencap ลงเครื่อง + pull

หัวใจของทุกกับดักคือเรื่องเดียวกันหมด — คำสั่ง adb ไม่ได้วิ่งตรงถึงเครื่องอย่างที่คิด แต่มีชั้นของ Windows, Git Bash และ PowerShell แทรกอยู่ตรงกลาง แล้ว MIUI ก็มีด่านของมันอีกชั้น พอรู้ว่าใครแทรกตรงไหนก็เลี่ยงได้หมด ใครจะปรับ flow ตามเครื่องและ ROM ของตัวเองก็ได้ตามสะดวกครับ ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

ชั้นที่แทรกอยู่ระหว่างคำสั่งกับเครื่องคำสั่ง adbบน WindowsGit Bashแปลง /sdcard ให้เพี้ยนPowerShell> ทำไบต์ PNG พังadbเครื่อง MIUIบล็อกติดตั้งครั้งแรกติดตั้งมือรอบแรกadb เองไม่ได้พัง แต่ละชั้นที่แทรกอยู่กลางทางต่างหากที่ทำให้ผลเพี้ยน
Git Bash แปลง path PowerShell ทำไบต์ไบนารีพัง และ MIUI บล็อกการติดตั้งครั้งแรก

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย