Android 开始使用
本指南将带你完成使用 Midscene 自动化 Android 设备所需的一切:通过 adb 连接真机、配置模型 API Key、体验零代码 Playground,并运行你的首个 JavaScript 脚本。
配置 AI 模型服务
将你的模型配置写入环境变量,可参考 模型策略 了解更多细节。
export MIDSCENE_MODEL_BASE_URL="https://替换为你的模型服务地址/v1"
export MIDSCENE_MODEL_API_KEY="替换为你的 API Key"
export MIDSCENE_MODEL_NAME="替换为你的模型名称"
export MIDSCENE_MODEL_FAMILY="替换为你的模型系列"
更多配置信息请参考 模型策略 和 模型配置。
准备工作
在编写脚本前,先确认 adb 能够连接设备且设备信任当前电脑。
安装 adb 并设置 ANDROID_HOME
出现类似输出表示安装成功:
Android Debug Bridge version 1.0.41
Version 34.0.4-10411341
Installed as /usr/local/bin//adb
Running on Darwin 24.3.0 (arm64)
有输出即代表配置成功:
/Users/your_username/Library/Android/sdk
启用 USB 调试并验证设备
在系统设置的开发者选项中开启 USB 调试(若有 USB 调试(安全设置) 也请一并开启),然后用数据线连接手机。

验证连接:
出现类似输出代表连接成功:
List of devices attached
s4ey59 device usb:34603008X product:cezanne model:M2006J device:cezan transport_id:3
试用 Playground(零代码)
Playground 是验证连接、观察 AI Agent 的最快方式,无需编写代码。它与 @midscene/android 共享相同的代码实现,因此在 Playground 上验证通过的流程,用脚本运行时也完全一致。
- 启动 Playground CLI:
npx --yes @midscene/android-playground
- 点击 Playground 窗口中的齿轮按钮,粘贴你的 API Key 配置。如果还没有 API Key,请回到 模型配置 获取。

开始体验
配置完成后,你可以立即开始体验 Midscene。它提供了多个关键操作 Tab:
- Act: 与网页进行交互,这就是自动规划(Auto Planning),对应于
aiAct 方法。比如
在搜索框中输入 Midscene,执行搜索,跳转到第一条结果
- Query: 从界面中提取 JSON 结构的数据,对应于
aiQuery 方法。
类似的方法还有 aiBoolean(), aiNumber(), aiString(),用于直接提取布尔值、数字和字符串。
提取页面中的用户 ID,返回 { id: string } 结构的 JSON 数据
- Assert: 理解页面,进行断言,如果不满足则抛出错误,对应于
aiAssert 方法。
页面上存在一个登录按钮,它的下方有一个用户协议的链接
- Tap: 在某个元素上点击,这就是即时操作(Instant Action),对应于
aiTap 方法。
关于自动规划(Auto Planning)和即时操作(Instant Action)的区别,请参考 API 文档。
集成 Midscene Agent
当 Playground 运行正常后,就可以切换到可复用的 JavaScript 脚本。
第 1 步:安装依赖
npm install @midscene/android dotenv --save-dev
yarn add @midscene/android dotenv --save-dev
pnpm add @midscene/android dotenv --save-dev
bun add @midscene/android dotenv --save-dev
deno add npm:@midscene/android npm:dotenv --save-dev
第 2 步:编写脚本
下面的示例会在设备上打开浏览器、搜索 eBay,并断言结果列表。
./demo.ts
import 'dotenv/config'; // 通过 dotenv/config 自动加载 .env 文件中的环境变量
import {
AndroidAgent,
AndroidDevice,
getConnectedDevices,
} from '@midscene/android';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
Promise.resolve(
(async () => {
const devices = await getConnectedDevices();
const device = new AndroidDevice(devices[0].udid);
const agent = new AndroidAgent(device, {
aiActionContext:
'If any location, permission, user agreement, etc. popup, click agree. If login page pops up, close it.',
});
await device.connect();
await agent.aiAct('open browser and navigate to ebay.com');
await sleep(5000);
await agent.aiAct('type "Headphones" in search box, hit Enter');
await agent.aiWaitFor('There is at least one headphone product');
const items = await agent.aiQuery(
'{itemTitle: string, price: Number}[], find item in list and corresponding price',
);
console.log('headphones in stock', items);
await agent.aiAssert('There is a category filter on the left');
})(),
);
第 3 步:运行示例
第 4 步:查看报告
脚本成功后会输出 Midscene - report file updated: /path/to/report/some_id.html。在浏览器中打开该 HTML 文件即可回放每一步交互、查询与断言。
进阶
当你需要自定义设备行为、把 Midscene 接入独立框架,或排查 adb 问题时,可参考本节内容。更多构造函数参数可前往 API 参考(Android)。
扩展 Android 上的 Midscene
使用 defineAction() 定义自定义手势,并通过 customActions 传入。Midscene 会把自定义动作追加到规划器中,让 AI 可以调用你领域特定的动作名。
import { getMidsceneLocationSchema, z } from '@midscene/core';
import { defineAction } from '@midscene/core/device';
import { AndroidAgent, AndroidDevice, getConnectedDevices } from '@midscene/android';
const ContinuousClick = defineAction({
name: 'continuousClick',
description: 'Click the same target repeatedly',
paramSchema: z.object({
locate: getMidsceneLocationSchema(),
count: z.number().int().positive().describe('How many times to click'),
}),
async call(param) {
const { locate, count } = param;
console.log('click target center', locate.center);
console.log('click count', count);
},
});
const devices = await getConnectedDevices();
const device = new AndroidDevice(devices[0].udid);
await device.connect();
const agent = new AndroidAgent(device, {
customActions: [ContinuousClick],
});
await agent.aiAct('click the red button five times');
关于自定义动作和动作 Schema 的更多解释,请参阅 与任意界面集成。
常见问题
为什么连接了设备,但仍然无法控制?
一个典型的错误信息是:
Error:
Exception occurred while executing 'tap':
java.lang.SecurityException: Injecting input events requires the caller (or the source of the instrumentation, if any) to have the INJECT_EVENTS permission.
请在系统设置的开发者选项中确认以下选项已开启:
- USB 调试
- USB 调试(安全设置)(如果存在)

输入文本后,输入框内容被清空或消失
Midscene 在输入文本后会自动隐藏键盘,默认行为是发送 ESC 按键事件。然而,部分输入框(尤其是 WebView 中的输入框)会监听 ESC 按键事件,导致以下副作用:
- 清空刚输入的文本
- 关闭包含输入框的弹窗或模态框
- 导航离开当前页面
你可以按以下优先级逐步尝试解决:
方案一:改用 BACK 键(Android 返回键)隐藏键盘
将 keyboardDismissStrategy 设为 'back-first',用 Android BACK 键替代 ESC 键来隐藏键盘:
const device = new AndroidDevice('device-id', {
keyboardDismissStrategy: 'back-first',
});
方案二:关闭自动隐藏键盘
如果你的输入框同时监听了 BACK 键,可以彻底关闭自动隐藏键盘,由 AI Agent 或后续操作自行管理键盘状态:
const device = new AndroidDevice('device-id', {
autoDismissKeyboard: false,
});
关闭后键盘不会自动隐藏,可能导致键盘覆盖大量屏幕区域。你可以通过以下方式应对:
- 使用
aiAct 指令手动隐藏键盘,例如 await agent.aiAct('点击键盘上的收起按钮')
- 安装并切换到 ADBKeyBoard——这是一款极小面积的虚拟键盘,即使不隐藏也几乎不影响屏幕操作
如何使用自定义的 adb 路径或远程 adb 服务器?
通过环境变量设置:
export MIDSCENE_ADB_PATH=/path/to/adb
export MIDSCENE_ADB_REMOTE_HOST=192.168.1.100
export MIDSCENE_ADB_REMOTE_PORT=5037
也可以通过 AndroidDevice 构造函数传入:
const device = new AndroidDevice('s4ey59', {
androidAdbPath: '/path/to/adb',
remoteAdbHost: '192.168.1.100',
remoteAdbPort: 5037,
});
更多