Để AI agent tự bấm và kiểm tra app Flutter trên iOS lẫn Android: agent-device của Callstack
Muốn coding agent kiểm thử app Flutter thì agent phải tự mở app, bấm nút và đọc màn hình trên điện thoại thật hoặc giả lập. Trong 5 ứng viên tác giả thử qua, chỉ agent-device đáp ứng cả ba điều kiện: chạy được cả iOS lẫn Android, lưu được flow đã kiểm chứng để chạy lại, và có giấy phép mở. Bài này trình bày cách tác giả chọn, cách cài đặt, vòng lặp kiểm thử và 3 cạm bẫy riêng của Flutter.
Trong 5 ứng viên tác giả thử qua, chỉ một công cụ đáp ứng cả ba điều kiện: chạy được cả iOS lẫn Android, lưu được flow đã kiểm chứng để chạy lại, và có giấy phép mở. Công cụ đó là agent-device, công cụ mã nguồn mở của Callstack, cho phép AI agent điều khiển app iOS và Android rồi kiểm tra những gì hiện trên màn hình. Bài này dựa trên phiên bản 0.21.31, phát hành ngày 2026-10-24, và chỉ viết phần 1: chọn công cụ, cài đặt và vòng lặp cơ bản.
Năm ứng viên, một người thắng
App Flutter biên dịch ra cả Android lẫn iOS từ một codebase (một bộ mã nguồn chung). Công cụ kiểm thử vì thế phải bao quát được iOS, nếu không đội phải duy trì hai quy trình khác nhau.
| Ứng viên | Bao quát iOS và Android | Chạy lại flow đã kiểm chứng | Vấn đề khiến tác giả loại |
|---|---|---|---|
| Google Artemis | Không, chỉ Android | Có | iOS vẫn chỉ nằm trong lộ trình |
| mobile-mcp | Có | Không | Không có session, không có phát lại, không lưu bằng chứng |
| Maestro | Có | Có, flow cố định bằng YAML | Hợp với chạy hồi quy (regression) các flow cố định hơn là để agent tự khám phá màn hình |
| Arbigent | Có | Có | Tác giả của nó tự chấm 1/5 về tốc độ và 3/5 về độ tin cậy, định dạng YAML vẫn đang thay đổi |
| Dịch vụ thương mại | Có | Có | Chỉ có tài liệu của nhà cung cấp công khai, không kiểm chứng được chi phí và chất lượng |
agent-device thắng ở chỗ nó gộp được những mảnh rời rạc kia. Một công cụ duy nhất bao quát giả lập iOS, giả lập Android và máy thật. Nó có cả giao diện dòng lệnh lẫn máy chủ MCP (chuẩn để AI gọi công cụ ngoài). Flow đã kiểm chứng lưu thành script .ad để phát lại sau, và có thể xuất ra YAML của Maestro. Giấy phép của nó là MIT, tức dùng tự do trong dự án thương mại. Tài liệu của nó ghi rõ hỗ trợ Flutter.
Bảng trên là đánh giá của tác giả bài nguồn, không phải phép đo độc lập của blog này. Điểm đáng giữ lại không phải thứ hạng tuyệt đối, mà là bộ tiêu chí: bao quát nền tảng, chạy lại được, và có bằng chứng để bàn giao cho CI (hệ thống tích hợp liên tục).
Cài đặt trong vài phút
Cài giao diện dòng lệnh toàn cục, rồi kiểm tra môi trường:
npm i -g agent-device@latest
agent-device doctor
Lệnh doctor kiểm tra máy đã kết nối, chuỗi công cụ và máy chủ phát triển. Trong thiết lập của tác giả, nó chỉ cảnh báo về các nền tảng không dùng tới, như HarmonyOS và Vega.
Đăng ký công cụ với Claude Code dưới dạng máy chủ MCP. Cờ -s user khiến công cụ có mặt trong mọi dự án:
claude mcp add -s user agent-device -- agent-device mcp
Kho chứa của agent-device kèm ba kỹ năng cho agent: agent-device, ios-simulator và android-emulator. Hướng dẫn chính thức là npx skills add callstack/agent-device, nhưng chế độ tự động của Claude Code đã chặn lệnh đó trong lần thử của tác giả. Cách làm thay thế là nhân bản kho chứa rồi chép ba thư mục trong skills/ vào ~/.claude/skills/.
Muốn gỡ sạch, chạy ngược lại: gỡ đăng ký MCP, gỡ gói toàn cục, rồi xóa tay ba thư mục kỹ năng:
claude mcp remove agent-device -s user
npm uninstall -g agent-device
Có đường gỡ sạch nghĩa là bạn thử công cụ này mà không sợ kẹt lại cấu hình thừa trong máy.
Vòng lặp: mở app, bấm, kiểm tra, đóng
Vòng lặp cơ bản gồm 5 bước: chuẩn bị máy, mở app, thao tác, kiểm tra, đóng. Cờ --platform chọn nền tảng, --device chọn máy:
agent-device boot --platform android --device "<tên giả lập>" --headless
agent-device install <đường-dẫn-tuyệt-đối>/app-debug.apk --platform android --device "<tên giả lập>"
agent-device open <bundle-id> --platform android --device "<tên giả lập>" --foreground
agent-device press @e5 --settle
agent-device fill @e11 "văn bản" --settle
agent-device wait text "<văn bản mong đợi>"
agent-device screenshot <đường-dẫn-tuyệt-đối>/home.png
agent-device close
Lệnh open đọc màn hình rồi trả về một tham chiếu (reference) cho mỗi phần tử, ví dụ @e5 cho một nút bấm. Cờ --settle khiến press và fill chờ tới khi màn hình yên rồi chỉ trả về phần thay đổi. Nhờ đó agent chọn mục tiêu tiếp theo mà không phải đọc lại toàn bộ màn hình — cùng ý tưởng tiết kiệm output như bài về 9 cờ để runner chỉ in phần lỗi.
Ba lỗi thường gặp trong vòng lặp này:
- Tham chiếu cũ khi màn hình đổi. Sau mỗi thao tác, lấy tham chiếu mới từ phần thay đổi mà thao tác đó trả về, đừng dùng lại tham chiếu của màn hình trước.
- Ảnh chụp màn hình không phải là kiểm chứng. Dùng
wait texthoặcwait <selector>(bộ chọn phần tử) để khẳng định điều mong đợi thật sự xuất hiện. Ảnh chụp chỉ giữ vai trò bằng chứng. - Lệnh
installcần đường dẫn tuyệt đối. Đường dẫn tương đối được hiểu theo thư mục làm việc của tiến trình nền agent-device, và sẽ lỗi "App binary not found".
Với app Flutter, build bản iOS cho giả lập và bản Android để gỡ lỗi trước khi đưa vào vòng lặp:
flutter build ios --simulator --debug
flutter build apk --debug
Ba cạm bẫy riêng của Flutter
agent-device đọc màn hình qua cây trợ năng (accessibility tree), tức cấu trúc mô tả giao diện cho công cụ hỗ trợ. Trong Flutter, mặc định chỉ widget (thành phần giao diện) có văn bản mới xuất hiện trong cây đó. Nút bấm chỉ có biểu tượng và khối chứa không có văn bản thì agent không thấy.
Cách sửa là gắn Semantics(identifier:) hoặc semanticLabel cho các widget đó, để bộ chọn tìm được chúng. Lưu ý: Key của Flutter không xuất hiện trong cây trợ năng, nên đừng dùng Key làm bộ chọn.
Cạm bẫy thứ hai là ngôn ngữ của máy. Nhãn trong cây trợ năng đi theo ngôn ngữ máy đang đặt, nên cùng một app đọc ra văn bản khác nhau trên các máy khác nhau. Bộ chọn dựa trên văn bản vì thế đổi theo ngôn ngữ máy. identifier không đổi theo ngôn ngữ, nên là lựa chọn ổn định hơn.
Cạm bẫy thứ ba nằm trên iOS: banner quảng cáo thử nghiệm của AdMob hiện thành các nút platform_view, webview và link. Script phát lại nên tránh các nút đó, nếu không lần chạy lại sẽ bấm nhầm vào quảng cáo.
Khi nào chọn, khi nào không
Chọn agent-device khi bạn cần cả ba điều này cùng lúc. Thứ nhất, kiểm thử trên cả iOS lẫn Android. Thứ hai, agent tự khám phá màn hình thay vì chỉ chạy flow cố định. Thứ ba, flow đã kiểm chứng chạy lại được trong CI. Thiếu một trong ba, các ứng viên khác có thể đủ: Maestro đủ cho flow cố định, mobile-mcp đủ khi chỉ cần bấm và chụp màn hình.
Đừng chọn khi đội chưa sẵn sàng sửa widget để agent nhìn thấy. Nếu nút bấm không có Semantics(identifier:), agent mù trước chính giao diện của bạn, và mọi vòng lặp đều kẹt ở bước đầu tiên. Sửa cây trợ năng trước, rồi mới bàn tới công cụ.
Nguồn tham khảo
- krenin88, "Test Automation with agent-device (Part 1)", DEV Community, 2026-10-24. https://dev.to/krenin88/test-automation-with-agent-device-part-1-7nj
- Callstack, kho chứa agent-device. https://github.com/callstack/agent-device
- Callstack, tài liệu agent setup của agent-device. https://oss.callstack.com/agent-device/docs/agent-setup
