开发模版与 SDK
TypeScript / Node.js SDK
基于原生 fetch 的单文件 TypeScript 客户端,零外部依赖
无论是构建 Electron 桌面应用、Next.js 后端还是 Node.js 自动化服务,将以下单文件直接拷入项目中即可开箱即用。
客户端源码 (LanghuaClient.ts)
export interface DeviceInfo {
deviceId: string;
brand: string;
model: string;
status: "ONLINE" | "OFFLINE";
batteryLevel?: number;
currentApp?: string;
}
export interface ScreenshotResult {
image_base64: string;
width: number;
height: number;
}
export interface SkillResponse<T = any> {
success: boolean;
message: string;
data?: T;
skillId?: string;
deviceId?: string;
}
export class LanghuaClient {
private baseUrl: string;
private appKey: string;
constructor(options: { baseUrl?: string; appKey: string }) {
this.baseUrl = (options.baseUrl || "http://localhost:58166").replace(/\/+$/, "");
this.appKey = options.appKey;
}
private async request<T = any>(path: string, options: RequestInit = {}): Promise<T> {
const res = await fetch(`${this.baseUrl}${path}`, {
...options,
headers: {
"Content-Type": "application/json",
"X-AppKey": this.appKey,
...(options.headers || {})
}
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${await res.text()}`);
}
return (await res.json()) as T;
}
/** 统一技能执行通道 */
async executeSkill<T = any>(deviceId: string, skillId: string, params: Record<string, any> = {}): Promise<SkillResponse<T>> {
return this.request<SkillResponse<T>>("/gateway/skill/execute", {
method: "POST",
body: JSON.stringify({
device_id: deviceId,
skill_id: skillId,
params
})
});
}
// ── 1. 设备与生命周期 ──
/** 获取名下已绑定的在线设备列表 */
async listDevices(): Promise<DeviceInfo[]> {
const res = await this.request<{ code: number; data: DeviceInfo[] }>("/gateway/device/list");
return res.data || [];
}
/** 唤醒屏幕并解锁 */
async unlock(deviceId: string, credential = ""): Promise<SkillResponse> {
return this.executeSkill(deviceId, "system.unlock", { credential });
}
// ── 2. 触控与输入 ──
/** 点击屏幕物理坐标 (x, y) */
async tap(deviceId: string, x: number, y: number, duration = 150): Promise<SkillResponse> {
return this.executeSkill(deviceId, "ui.tap", { x, y, duration });
}
/** 拟人平滑滑动 */
async swipe(deviceId: string, x1: number, y1: number, x2: number, y2: number, duration = 300, steps = 10): Promise<SkillResponse> {
return this.executeSkill(deviceId, "ui.swipe", { x1, y1, x2, y2, duration, steps });
}
/** 整页翻页 */
async scroll(deviceId: string, action: "PAGE_DOWN" | "PAGE_UP" | "LEFT" | "RIGHT" = "PAGE_DOWN"): Promise<SkillResponse> {
return this.executeSkill(deviceId, "ui.scroll", { action });
}
/** 拟真逐字输入 (可传 x, y 自动先点击获焦) */
async inputText(deviceId: string, text: string, options?: { x?: number; y?: number; clear?: boolean }): Promise<SkillResponse> {
const params: Record<string, any> = {
text,
clear: options?.clear ?? true,
delay: 150
};
if (options?.x !== undefined && options?.y !== undefined) {
params.x = options.x;
params.y = options.y;
}
return this.executeSkill(deviceId, "ui.input", params);
}
/** 物理按键 (4=Back, 3=Home, 187=Recents, 66=Enter) */
async pressKey(deviceId: string, keyCode = 4): Promise<SkillResponse> {
return this.executeSkill(deviceId, "control.key_event", { keyCode });
}
// ── 3. 应用管理 ──
/** 启动应用 (息屏自动唤醒解锁) */
async launchApp(deviceId: string, packageName: string): Promise<SkillResponse> {
return this.executeSkill(deviceId, "app.launch", { package_name: packageName });
}
/** 获取当前活跃前台包名与界面 */
async getCurrentApp(deviceId: string): Promise<{ package_name: string; activity_name: string }> {
const res = await this.executeSkill(deviceId, "app.get_current");
return res.data;
}
/** 静默授权敏感权限 */
async grantPermission(deviceId: string, packageName: string, permission: string): Promise<SkillResponse> {
return this.executeSkill(deviceId, "app.grant_permission", {
package_name: packageName,
permission
});
}
// ── 4. 视觉感知与媒体 ──
/** 高质量采集 (返回 Base64 与宽高,赋能 VLM) */
async screenshot(deviceId: string, options?: { quality?: number; scale?: number }): Promise<ScreenshotResult> {
const res = await this.executeSkill<ScreenshotResult>(deviceId, "control.screenshot_info", {
quality: options?.quality ?? 50,
scale: options?.scale ?? 0.5
});
return (res.data || res) as ScreenshotResult;
}
/** 批量向系统相册注入图片 */
async downloadToGallery(deviceId: string, imageUrls: string[]): Promise<SkillResponse> {
return this.executeSkill(deviceId, "media.download_image", { image_urls: imageUrls });
}
}
30 秒上手示例
import { LanghuaClient } from "./LanghuaClient";
const client = new LanghuaClient({
baseUrl: "http://localhost:58166",
appKey: "sk-lh-xxxxxxxxxxxxxxxx"
});
async function run() {
const devices = await client.listDevices();
const deviceId = devices[0].deviceId;
// 1. 唤醒并启动微信
await client.launchApp(deviceId, "com.tencent.mm");
// 2. 在指定坐标获焦并输入文本
await client.inputText(deviceId, "自动化测试消息", { x: 540, y: 320 });
// 3. 点击发送按钮
await client.tap(deviceId, 980, 2300);
}
run().catch(console.error);