文章目录

Open-AutoGLM iOS苹果手机 完整部署指南(全网最全,踩坑全解+原理剖析)

1. 概述

1.1 项目背景

若对您有帮助的话,请点赞收藏加关注哦,您的关注是我持续创作的动力!有问题请私信或联系邮箱:funian.gm@gmail.com

Open-AutoGLM 是基于 AutoGLM-Phone-9B 视觉-语言大模型 开发的智能手机全自动化框架,核心能力是让大模型看懂手机屏幕、自主决策、执行操作,实现自然语言驱动的手机自动化@智谱。

本项目核心适配目标:将原本仅支持Android(ADB)的Open-AutoGLM,无缝迁移至iOS平台,底层通信由ADB Shell 替换为 WebDriverAgent(WDA) HTTP API,是iOS端首个基于大模型的全链路自动化框架。

在这里插入图片描述

1.2 完整技术架构(调用链路)

核心逻辑:模型决策 → Agent调度 → WDA封装层 → WDA服务 → 端口转发 → iOS真机执行

┌─────────────────────────────────────────────────────────┐
│ AutoGLM-Phone-9B (视觉-语言大模型)                      │
│ 能力:截图理解/操作决策/自然语言解析/弹窗识别           │
└─────────────────────────────────────────────────────────┘
                            ↓ (决策指令下发)
┌─────────────────────────────────────────────────────────┐
│ Open-AutoGLM Agent (iOS专属)                            │
│ 核心文件:agent_ios.py + handler_ios.py                 │
│ 能力:指令解析/任务调度/操作执行/结果反馈                │
└─────────────────────────────────────────────────────────┘
                            ↓ (标准化操作调用)
┌─────────────────────────────────────────────────────────┐
│ WDA Python 封装层 (phone_agent/wda/)                    │
│ 核心文件:client.py/device.py/input.py                  │
│ 能力:HTTP请求封装/坐标转换/输入处理/Session管理         │
└─────────────────────────────────────────────────────────┘
                            ↓ (HTTP API调用)
┌─────────────────────────────────────────────────────────┐
│ WebDriverAgent (iOS本地HTTP Server)                     │
│ 运行端口:8100 | 能力:原生操作执行/截图/应用管理        │
└─────────────────────────────────────────────────────────┘
                            ↓ (USB数据转发)
┌─────────────────────────────────────────────────────────┐
│ iproxy (USB端口转发工具)                                │
│ 映射规则:Mac本地8100 → iPhone设备8100                  │
└─────────────────────────────────────────────────────────┘
                            ↓ (最终执行)
┌─────────────────────────────────────────────────────────┐
│ iOS 真机设备                                            │
│ 执行:点击/滑动/输入/应用启停/截图等原生操作            │
└─────────────────────────────────────────────────────────┘

1.3 iOS 与 Android 核心技术差异(必看,适配核心)

此表格是所有适配工作的核心依据,90%的坑均来源于此差异,理解后可规避绝大多数问题

对比维度 Android (ADB) iOS (WDA) 关键注意点 ⚠️
通信协议 ADB Shell 命令(TCP/USB) HTTP REST API(HTTP/1.1) WDA所有操作均为接口调用,有请求/响应规范
坐标系统 物理像素(Pixels) 逻辑点(Points) iOS坐标≠像素,必须做倍率转换,否则点击偏移
屏幕倍率 固定1x 2x(普通屏)/3x(Retina屏) iPhone12+全系为3x,是最高频适配点
截图方式 adb shell screencap 命令 GET /screenshot HTTP接口 WDA截图为Base64格式,需解码后使用
点击操作 input tap x y Shell命令 POST /wda/tap JSON参数 iOS点击传参为浮点型Points,Android为整型像素
文字输入 依赖ADB虚拟键盘 原生键盘+POST /wda/keys iOS输入需传字符数组,而非字符串
返回操作 物理Back键命令调用 左边缘滑动手势模拟 iOS无物理返回键,必须适配手势逻辑
连接方式 USB直连,无额外转发 USB+iproxy转发 WiFi直连WDA会被iOS安全策略拦截,必用USB
权限体系 无严格签名限制 必须Apple开发者账号签名 WDA部署依赖Xcode签名,无账号无法运行

2. 环境准备

2.1 硬性环境要求(特别注意版本对应)

  • 操作系统:macOS 10.15+ (Catalina) ~ macOS 26 (Sequoia),仅支持Mac(iOS开发/调试的唯一官方系统)
  • iOS设备:iOS 13.0+ 真机(建议iOS15~26),不支持模拟器(WDA模拟器功能残缺,无实际价值)
  • Python版本:3.10 ~ 3.13
  • 开发工具:Xcode 14.0+(App Store安装即可,默认安装最新版,无需手动编译,和操作系统的版本需要对应
  • 网络要求:稳定外网连接(用于下载依赖、调用智谱AI模型API)
  • 账号要求:Apple开发者账号(私人Iphone帐号,免费/付费均可,免费账号有效期7天)
  • 博主的配置如下:macOS Xcode IOS版本对应 均为26.2
    在这里插入图片描述

2.2 必备工具安装(一键执行,无先后顺序)

所有工具均通过Homebrew安装,Homebrew是Mac必备包管理器,无则先装。博主已经安装过环境,展示安装好的环境截图,

2.2.1 安装Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
2.2.2 安装libimobiledevice(核心依赖)
brew install libimobiledevice

在这里插入图片描述

核心作用:提供iproxy(端口转发)、idevice_id(设备UDID查询)、ideviceinstaller(应用管理)等全套iOS USB调试工具,是连接Mac与iOS的核心桥梁。

特别注意:需要使用数据线连接电脑和手机后,才会显示设备ID。

idevice_id -l

在这里插入图片描述

2.2.3 安装Python依赖前置
brew install python@3.13
echo 'export PATH="/opt/homebrew/opt/python@3.13/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
2.2.4 安装完整性验证(必做,排查环境问题)
# 验证iproxy是否安装成功
which iproxy
# ✅ 成功输出:/opt/homebrew/bin/iproxy (M1/M2/M3系列芯片) | /usr/local/bin/iproxy (Intel芯片)

# 验证iOS设备是否被识别
idevice_id -l
# ✅ 成功输出:设备的UDID字符串(一串40位的字母+数字)

# 验证Python版本
python3 --version
# ✅ 成功输出:Python 3.13.x (x为任意子版本)

在这里插入图片描述

3. WebDriverAgent 部署(iOS自动化基石,重中之重)

3.1 WDA 核心定位

WebDriverAgent(WDA)是Appium官方开源的iOS原生自动化框架,本质是一个运行在iOS设备上的本地HTTP服务,提供了iOS所有原生操作的API接口,是iOS端唯一稳定的自动化底层方案,无任何替代方案。

Open-AutoGLM的iOS适配,本质就是对WDA的二次封装与调用。

3.2 WDA 源码获取(两种方式,任选其一)

博主采用的是方式2。

方式1:使用项目内置WDA
Open-AutoGLM的iOS分支已内置WDA源码,无需单独下载,路径为:

/path/to/Open-AutoGLM/WebDriverAgent/

方式2:单独克隆官方源码

git clone https://github.com/appium/WebDriverAgent.git
cd WebDriverAgent
./Scripts/build.sh # 拉取所有子模块依赖,必执行

在这里插入图片描述

3.3 Xcode 项目配置(核心步骤,签名是唯一卡点)

前置条件
  1. iOS设备通过USB连接Mac,并信任此电脑(设备弹窗点击「信任」)
  2. 打开Xcode,登录Apple账号:Xcode → 设置 → 账号 → 添加Apple ID
  3. 设备解锁,关闭锁屏密码/面容ID(避免调试中断)

在这里插入图片描述

步骤1:打开WDA项目
open WebDriverAgent/WebDriverAgent.xcodeproj
步骤2:配置签名(所有Target必须配置,缺一不可) 步骤如下

签名是WDA部署的唯一核心卡点,iOS的沙盒机制要求所有运行在真机的App必须有合法签名,无签名则无法安装运行。

  1. 在Xcode左侧项目栏,选中「WebDriverAgent」项目
  2. 依次选中3个TargetWebDriverAgentLibWebDriverAgentRunnerIntegrationApp
  3. 对每个Target,点击「Signing & Capabilities」→ 勾选「Automatically manage signing」→ 选择你的Apple Team账号
  4. 若出现Bundle ID冲突(报错:Failed to register bundle identifier),修改每个Target的Bundle ID为唯一值,例如:com.xxx.WebDriverAgentRunner(xxx为你的账号名/自定义字符)

在这里插入图片描述

3.4 部署WDA到iOS真机(运行)

1、 Xcode顶部工具栏,选择你的iOS真机设备(不要选模拟器)
在这里插入图片描述

2、顶部菜单栏:Product → Scheme → WebDriverAgentRunner

在这里插入图片描述

3、 快捷键 ⌘+U 或 点击 Product → Test,开始编译并安装WDA到设备

在这里插入图片描述

  1. 首次运行必做:iOS设备弹出「不受信任的开发者」弹窗 → 打开设备「设置 → 通用 → VPN与设备管理」→ 找到你的Apple账号 → 点击「信任」

在这里插入图片描述

3.5 WDA 启动成功验证(核心日志)

编译完成后,查看Xcode的Console面板,出现以下日志即代表WDA启动成功

ServerURLHere->http://192.168.x.x:8100<-ServerURLHere

在这里插入图片描述

✅ 关键说明:此IP为设备的WiFi IP,我们不会直接使用,后续会通过iproxy做USB转发,使用localhost:8100访问,规避WiFi连接的不稳定性。


4. USB 端口转发

4.1 为什么必须用 iproxy 转发?【核心原理】

这是iOS的安全硬限制,无任何绕过方案,也是Android与iOS的核心差异之一:

  1. iOS的沙盒机制会拦截所有来自WiFi的HTTP请求到WDA,导致连接超时/断开,稳定性极差
  2. USB是Mac与iOS的信任通道,通过USB转发的请求不会被拦截,连接绝对稳定
  3. iproxy的核心功能:将Mac本地的8100端口,映射到iOS设备的8100端口,所有发往localhost:8100的请求,都会通过USB转发到设备的WDA服务。

4.2 启动 iproxy 转发服务(必做,常驻运行)

# 核心命令:本地端口 设备端口
iproxy 8100 8100

✅ 成功启动的终端输出:

Creating listening port 8100 for device port 8100
waiting for connection

在这里插入图片描述

✅ 关键注意事项(决定稳定性)

  1. iproxy命令需要在独立的终端窗口运行必须保持运行状态,关闭终端则转发中断
  2. 建议使用tmux/screen后台运行,避免终端关闭导致服务中断:tmux new -s ios_proxy && iproxy 8100 8100
  3. 若提示端口占用:sudo lsof -i :8100 查看占用进程,kill -9 PID 杀掉进程后重试

4.3 验证转发是否成功(必做)

新的终端窗口执行以下命令,验证WDA是否可通过USB访问:

curl http://localhost:8100/status

✅ 成功返回(JSON格式):

{
  "value": {"message": "WebDriverAgent is ready to accept commands", "state": "success"},
  "sessionId": "",
  "status": 0
}

❌ 失败返回:curl: (7) Failed to connect to localhost port 8100: Connection refused → 排查WDA是否启动/iproxy是否运行/设备是否连接。


在这里插入图片描述

5. 安装 Open-AutoGLM

5.1 拉取项目源码(iOS专属分支)

git clone https://github.com/Rocke1001feller/Open-AutoGLM.git
cd Open-AutoGLM
git checkout ios-feature # 切换到iOS适配分支,核心修改均在此分支

在这里插入图片描述

5.2 创建Python虚拟环境(必做,隔离依赖)

python3 -m venv .venv
source .venv/bin/activate # 激活虚拟环境,终端前缀会出现(.venv)标识

5.3 安装项目依赖(一键执行)

pip install -r requirements.txt
pip install -e . # 开发模式安装,修改代码无需重新安装

在这里插入图片描述

5.4 环境连通性自检(核心命令,一键排查所有问题)

此命令是Open-AutoGLM提供的iOS专属自检工具,会自动检查WDA连接、截图能力、应用检测等核心功能,是部署完成后的必执行步骤

python main_ios.py --check-only

✅ 成功输出:

🔍 Checking iOS device connection...
--------------------------------------------------
1. Checking WDA connectivity (http://localhost:8100)... ✅ OK
2. Checking screenshot capability... ✅ OK (1170x2532)
3. Checking active app detection... ✅ OK (Current: SpringBoard)
--------------------------------------------------
✅ iOS device connection OK!

在这里插入图片描述

出现以上输出,代表所有环境部署完成,可正常运行任务


6. 运行测试

6.1 前置准备:获取智谱AI API Key

Open-AutoGLM依赖AutoGLM-Phone-9B模型的API服务,需在智谱开放平台获取API Key:

在这里插入图片描述

6.2 运行方式1:单次任务执行(推荐,快速测试)

python main_ios.py \
    --base-url https://open.bigmodel.cn/api/paas/v4 \
    --model autoglm-phone \
    --apikey "你的智谱API Key" \
    "打开美团搜索附近的火锅,选择一家评分最高的"

如果想在Mac端实时查看后台的运行逻辑和手机端的界面,在电脑上新建屏幕录制,选择手机屏幕。

在这里插入图片描述

6.3 运行方式2:交互模式(持续执行多个任务)

python main_ios.py \
    --base-url https://open.bigmodel.cn/api/paas/v4 \
    --model autoglm-phone \
    --apikey "你的智谱API Key"

启动后,终端会提示输入任务,例如:

  • 打开微信发送消息给文件传输助手
  • 打开淘宝搜索iPhone 16并查看销量第一的商品
  • 打开高德地图搜索最近的咖啡店并导航

6.4 辅助命令:查看支持的iOS应用

python main_ios.py --list-apps

在这里插入图片描述

输出当前配置支持的所有iOS应用(微信/支付宝/美团/淘宝等),如需新增应用,修改phone_agent/config/apps_ios.pyIOS_APP_PACKAGES字典即可。


备份:

运行的视频和后端处理逻辑监控:

1、运行视频

Open-AutoGLM iOS苹果手机运行视频

2、后端运行过程

(.venv) (base) funian@MacBook-Pro-14 Open-AutoGLM % python main_ios.py \
    --base-url https://open.bigmodel.cn/api/paas/v4 \
    --model autoglm-phone \
    --apikey "你的智谱API Key" \
    "打开美团搜索附近的火锅,选择一家评分最高的"


🔍 Checking iOS device connection...
--------------------------------------------------
1. Checking WDA connectivity (http://localhost:8100)... ✅ OK
2. Checking screenshot capability... ✅ OK (1290x2796)
3. Checking active app detection... ✅ OK (Current: 设置)
--------------------------------------------------
✅ iOS device connection OK!

🔍 Checking model API...
--------------------------------------------------
1. Checking API connectivity (https://open.bigmodel.cn/api/paas/v4)... ✅ OK
--------------------------------------------------
✅ Model API checks passed!

==================================================
Phone Agent for iOS - AI-powered iPhone automation
==================================================
Model: autoglm-phone
Base URL: https://open.bigmodel.cn/api/paas/v4
WDA URL: http://localhost:8100
Max Steps: 100
Language: cn
==================================================

Task: 打开美团搜索附近的火锅,选择一家评分最高的


==================================================
💭 思考过程:
--------------------------------------------------
用户想要:
1. 打开美团
2. 搜索附近的火锅
3. 选择一家评分最高的

当前屏幕显示的是设置应用(General设置页面)。我需要先打开美团应用。

根据允许的应用列表,美团是可用的应用之一。我应该使用Launch action来打开美团。

--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Launch",
  "app": "美团"
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
美团应用已经打开,但是出现了一个弹窗,提示"美团" would like to paste from "MacBook Pro 14",询问是否允许。有两个选项:"Don'tAllowPaste""AllowPaste"。

我应该点击"Don'tAllowPaste"来关闭这个弹窗,然后继续进行搜索。

--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Tap",
  "element": [
    499,
    534
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
好的,现在美团应用已经打开,我可以看到美团的首页。页面顶部有一个搜索框,显示"佰味龙"。我需要点击这个搜索框,然后搜索"火锅"。

搜索框的位置大约在顶部,我可以看到"佰味龙"这个文本框和右侧的"搜索"按钮。我应该点击搜索框来输入"火锅"。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Tap",
  "element": [
    389,
    103
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
好的,搜索页面已经打开。我可以看到:
1. 顶部有一个搜索框,显示"附近好吃的火锅"
2. 下方有历史搜索记录,包括"火锅"
3. 还有发现区域,显示各种火锅相关的选项
4. 底部有键盘

我可以看到历史搜索中有"火锅",我可以直接点击它,或者我可以在搜索框中输入"火锅"。我看到搜索框中已经有"附近好吃的火锅"这个文本,但根据指南,Type action会自动清除现有文本。

我应该点击搜索框,然后输入"火锅"进行搜索。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Type",
  "text": "火锅"
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
奇怪,输入"火锅"后,屏幕跳转到了设置应用(General设置页面)。这看起来不对。可能是系统出现了某种问题。

让我重新启动美团应用,然后再次尝试搜索火锅。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Launch",
  "app": "美团"
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
好的,现在搜索页面已经打开,搜索框中显示"火锅",并且出现了一些搜索建议:
1. 火锅
2. 火鸡面外卖
3. 火锅(有"问小团"标签)
4. 佰味龙自助烤肉火锅 (GOGO新天地店) - 浏览过 <500m
5. 火锅自助
6. 查找全部相关结果

我可以看到第一个选项就是"火锅",我可以点击它,或者点击右上角的"搜索"按钮。我应该点击"搜索"按钮来进行搜索。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Tap",
  "element": [
    903,
    79
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
页面正在加载,我可以看到搜索结果页面正在加载中,有一些灰色的占位符。我应该等待页面加载完成。根据指南,已经有大约2秒的内置延迟,但页面可能需要更多时间加载。让我等待一下。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Wait",
  "duration": "2 seconds"
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
太好了!搜索结果已经加载完成。我可以看到火锅搜索结果页面,显示了多家火锅店:

1. 姜子牙美蛙鱼(大学城贝岗店)- 评分4.9,54条评价,人均¥59,距离106m
2. 佰味龙自助烤肉火锅(GOGO新天地店)- 评分5.0,1.1万条评价,人均¥59,距离260m
3. 牛大学·潮汕牛肉火锅(广...)- 评分4.6,2771条评价,人均¥60,距离65m

页面顶部有筛选选项,包括"综合排序""距离最近"。我需要按评分排序来找到评分最高的火锅店。

我应该点击"综合排序"来改变排序方式,选择按评分排序。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Tap",
  "element": [
    362,
    263
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
太好了!排序菜单已经打开,我可以看到以下排序选项:
- 综合排序(当前选中)
- 速度优先
- 离我最近
- 好评优先
- 人均最低
- 人均最高
- 起送价最低
- 配送费最低

我需要选择"好评优先"来按评分排序。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Tap",
  "element": [
    98,
    457
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
好的,排序已经改变为"好评优先"。现在我可以看到火锅店列表,按照评分排序:

1. 姜子牙美蛙鱼(大学城贝岗店)- 评分4.9,54条评价,人均¥59,距离106m
2. 佰味龙自助烤肉火锅(GOGO新天地店)- 评分5.0,1.1万条评价,人均¥59,距离260m
3. 牛大学·潮汕牛肉火锅(广...)- 评分4.6,2771条评价,人均¥60,距离65m

看起来评分最高的是佰味龙自助烤肉火锅(GOGO新天地店),评分5.0分,有1.1万条评价。

但是,我需要确认一下是否还有更高评分的火锅店。让我向下滚动查看更多火锅店。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Swipe",
  "start": [
    499,
    790
  ],
  "end": [
    499,
    350
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
好的,我向下滚动后看到了更多火锅店,这些都是5.0分的高评分火锅店:

1. 重庆鲜菜老火锅 - 评分5.0,425条评价,人均¥51,距离长隆/南村
2. 龙天门重庆火锅(东方国际店)- 评分5.0,4217条评价,人均¥79,距离7.0km
3. 潮汕石橄榄鸡炉(南亭店)- 评分5.0,3307条评价,人均¥48,距离2.7km

这些都是5.0分的火锅店。让我继续向上滚动回到列表顶部,确认一下距离最近的5.0分火锅店是哪一家。

实际上,从之前的截图来看,佰味龙自助烤肉火锅(GOGO新天地店)评分5.0,距离260m,这是距离最近的高评分火锅店。

让我向上滚动回到列表顶部,然后选择这家店。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Swipe",
  "start": [
    499,
    350
  ],
  "end": [
    499,
    790
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
好的,现在我可以看到列表顶部的火锅店了。按照好评优先排序,评分最高的火锅店是:

1. 佰味龙自助烤肉火锅(GOGO新天地店)- 评分5.0,1.1万条评价,人均¥59,距离260m
2. 正玉嬢正宗成都火锅 - 评分5.0,2000条评价,人均¥66,距离6.1km
3. 重庆鲜菜老火锅 - 评分5.0,425条评价,人均¥51,距离5.9km

虽然正玉嬢正宗成都火锅和重庆鲜菜老火锅的评分也是5.0分,但它们距离更远(6.1km和5.9km),而佰味龙自助烤肉火锅距离最近(260m),所以它是最近的5.0分火锅店。

用户要求选择"评分最高的",由于有多家5.0分的火锅店,我应该选择距离最近的,因为用户说的是"附近的火锅"。佰味龙自助烤肉火锅(GOGO新天地店)距离260m,是最近的5.0分火锅店。

让我点击这家店。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Tap",
  "element": [
    499,
    416
  ]
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
页面正在加载,显示"努力加载中..."。我应该等待页面加载完成。
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "do",
  "action": "Wait",
  "duration": "2 seconds"
}
==================================================


==================================================
💭 思考过程:
--------------------------------------------------
太好了!页面已经加载完成,显示了佰味龙自助烤肉火锅(GOGO新天地店)的详细信息:

- 店名:佰味龙自助烤肉火锅(GOGO新天地店)
- 评分:5.0分,1.1万条评价
- 地址:番禺区贝岗村大街GOGO新天地1期3楼368号
- 距离:距您348米,步行5分钟
- 营业时间:11:00-22:00
- 标签:番禺区自助餐好评榜第1名,回头客5千+
- 商家正在直播中

页面下方显示了各种套餐优惠:
- 全天·成人【单人自助餐】不含汤锅 - ¥58.8
- 全天·成人【双人自助餐】含汤锅 - ¥135.8
- 全天【儿童专属】单人套餐 - ¥23.8

任务已经完成!我成功:
1. 打开了美团
2. 搜索了附近的火锅
3. 按照好评优先排序
4. 选择了评分最高的火锅店(佰味龙自助烤肉火锅,5.0分,距离260m)
5. 打开了该店的详情页面

任务完成!
--------------------------------------------------
🎯 执行动作:
{
  "_metadata": "finish",
  "message": "任务已完成!我成功为您:\n\n1. 打开了美团应用\n2. 搜索了\"火锅\"\n3. 按照好评优先进行排序\n4. 找到了评分最高的火锅店:**佰味龙自助烤肉火锅(GOGO新天地店)**\n   - 评分n   - 地址:番禺区贝岗村大街GOGO新天地1期3楼368号\n   - 荣誉:番禺区自助餐好评榜第1名\n\n页面已显示该店的详细信息,包括营业时间(11:00-22:00)、各种套餐优惠,以及店铺的实景照片。您可以查看更多详情或选择想要的套餐。"
}
==================================================


🎉 ================================================
✅ 任务完成: 任务已完成!我成功为您:

1. 打开了美团应用
2. 搜索了"火锅"
3. 按照好评优先进行排序
4. 找到了评分最高的火锅店:**佰味龙自助烤肉火锅(GOGO新天地店)**
   - 评分:5.0分(满分)
   - 评价数:1.1万条
   - 距离:260米(步行约5分钟)
   - 人均消费:¥59
   - 地址:番禺区贝岗村大街GOGO新天地1期3楼368号
   - 荣誉:番禺区自助餐好评榜第1名

页面已显示该店的详细信息,包括营业时间(11:00-22:00)、各种套餐优惠,以及店铺的实景照片。您可以查看更多详情或选择想要的套餐。
==================================================


Result: 任务已完成!我成功为您:

1. 打开了美团应用
2. 搜索了"火锅"
3. 按照好评优先进行排序
4. 找到了评分最高的火锅店:**佰味龙自助烤肉火锅(GOGO新天地店)**
   - 评分:5.0分(满分)
   - 评价数:1.1万条
   - 距离:260米(步行约5分钟)
   - 人均消费:¥59
   - 地址:番禺区贝岗村大街GOGO新天地1期3楼368号
   - 荣誉:番禺区自助餐好评榜第1名

页面已显示该店的详细信息,包括营业时间(11:00-22:00)、各种套餐优惠,以及店铺的实景照片。您可以查看更多详情或选择想要的套餐。
(.venv) (base) funian@MacBook-Pro-14 Open-AutoGLM % python main_ios.py --list-apps

7. 核心技术问题与解决方案(全网独家,根治所有坑,适配核心)

本章是全文核心,包含Open-AutoGLM iOS适配中遇到的所有核心技术问题,每个问题均包含:问题现象、底层原理、根治解决方案、代码实现,所有方案均已合入项目分支,可直接复用。
✅ 所有问题优先级按出现频率+影响程度排序,Top1问题解决后,80%的功能可正常运行。

7.1 坐标系统偏移问题(TOP1,最高频,最核心)

✅ 问题现象

所有点击/滑动操作严重偏移,例如点击屏幕中间,实际点击到屏幕右下角,偏移量约为2~3倍,是iOS适配的首个必踩坑

✅ 根本原因(底层原理,必须理解)
  • Android的ADB使用物理像素(Pixels) 作为坐标单位,1个单位=1个屏幕像素
  • iOS的WDA使用逻辑点(Points) 作为坐标单位,这是iOS的原生坐标体系,由苹果官方定义
  • iOS的Retina屏有缩放倍率(Scale Factor):普通屏2x,iPhone12+全系3x,物理像素 = 逻辑点 × 缩放倍率
  • 错误本质:模型输出的坐标是像素坐标,直接传给WDA后,WDA会将其解析为逻辑点,导致坐标放大2~3倍,最终点击偏移。

举个例子(iPhone14 Pro)

物理像素分辨率:1179 × 2556
逻辑点分辨率:393 × 852
缩放倍率:3.0x
模型输出点击坐标:(589,1278) → 像素坐标
WDA接收后解析为:(589,1278) → 逻辑点 = 实际点击(1767,3834),超出屏幕范围,点击无效
正确转换:(589/3,1278/3) = (196.3,426.0) → 逻辑点,精准点击目标位置
✅ 根治解决方案(代码实现,项目已合入)

核心思路:新增坐标转换函数,将模型输出的像素坐标,自动转换为逻辑点坐标后,再调用WDA接口。
文件路径:phone_agent/wda/device.py

# 1. 动态获取设备的缩放倍率(适配所有iOS设备,无需硬编码)
def _get_scale_factor(device_id: str | None = None) -> float:
    """动态获取iOS设备的屏幕缩放倍率,优先级:接口获取 > 默认3.0"""
    try:
        client = get_client(device_id)
        resp = client.get("/wda/screen", use_session=False)
        return float(resp.get("value", {}).get("scale", 3.0))
    except Exception:
        return 3.0  # iPhone12+全系默认3x,兼容性兜底

# 2. 像素坐标 → 逻辑点坐标 转换函数
def _pixels_to_points(x: int, y: int, device_id: str | None = None) -> tuple[float, float]:
    """核心转换函数:将像素坐标转为WDA所需的逻辑点坐标"""
    scale = _get_scale_factor(device_id)
    return x / scale, y / scale

# 3. 修改所有坐标相关操作函数,自动调用转换
def tap(x: int, y: int, device_id: str | None = None, delay: float = 0.5) -> None:
    client = get_client(device_id)
    x_pt, y_pt = _pixels_to_points(x, y, device_id) # 自动转换
    client.post("/wda/tap", {"x": x_pt, "y": y_pt})
    time.sleep(delay)

修改覆盖的函数tap/double_tap/long_press/swipe/back(所有涉及坐标的操作)
✅ 修复效果:所有点击/滑动操作精准无偏移,坐标问题彻底解决。

7.2 文字输入无效问题(TOP2,高频)

✅ 问题现象

输入框可正常聚焦,键盘弹出,但无任何文字输入,终端无报错,是iOS文本输入的核心坑点

✅ 根本原因(3个核心错误)
  1. iOS无ADB虚拟键盘,必须使用原生键盘,无法像Android一样替换输入法
  2. WDA的文本输入接口是全局接口 /wda/keys,而非元素级输入,不能通过定位输入框后输入
  3. WDA要求输入的文本格式是字符数组 list(text),而非字符串 str(text),格式错误则输入无效
✅ 根治解决方案(代码实现,项目已合入)

核心思路:实现iOS专属的文本输入逻辑,三步式输入:清除原有文本 → 输入新文本 → 隐藏键盘。
文件路径:phone_agent/wda/input.py

def type_text(text: str, device_id: str | None = None, frequency: int = 60) -> None:
    """iOS专属文本输入:使用全局键盘接口,字符数组格式"""
    client = get_client(device_id)
    client.post("/wda/keys", {
        "value": list(text),  # 核心修正:转为字符数组
        "frequency": frequency  # 打字速度,60为最佳值
    }, use_session=True) # 必须带Session,否则404

def clear_text(device_id: str | None = None) -> None:
    """清除输入框文本:优先元素清除,兜底退格键"""
    client = get_client(device_id)
    try:
        resp = client.get("/element/active", use_session=True)
        if resp.get("value", {}).get("ELEMENT"):
            client.post(f"/element/{resp['value']['ELEMENT']}/clear", use_session=True)
            return
    except:
        pass
    # 备选方案:发送100次退格键,清空所有文本
    client.post("/wda/keys", {"value": ["\u0008"] * 100}, use_session=True)

def hide_keyboard(device_id: str | None = None) -> None:
    """隐藏原生键盘"""
    client = get_client(device_id)
    try:
        client.post("/wda/keyboard/dismiss", use_session=True)
    except:
        pass

handler_ios.py中实现三步输入逻辑,输入成功率100%:

def _handle_type(self, action: dict, width: int, height: int) -> ActionResult:
    text = action.get("text", "")
    clear_text(self.device_id)
    time.sleep(0.5)
    type_text(text, self.device_id)
    time.sleep(0.5)
    hide_keyboard(self.device_id)
    time.sleep(0.5)
    return ActionResult(True, False)

7.3 键盘隐藏接口404错误(TOP3,高频)

✅ 问题现象

调用hide_keyboard()时,终端报错:404 Client Error: Not Found for url: http://localhost:8100/wda/keyboard/dismiss

✅ 根本原因

WDA的接口分为需要Session不需要Session两类:

  • 无需Session:/status//screenshot 等基础接口
  • 必须Session:/wda/tap//wda/keys//wda/keyboard/dismiss 等操作接口
  • 错误本质:初始实现中,键盘隐藏接口使用了use_session=False,导致接口找不到,返回404。
✅ 解决方案

修改input.pyhide_keyboard函数,添加use_session=True,同时在client.py中将/wda/keyboard加入Session必填前缀列表,彻底解决404问题。

7.4 Session过期与自动重试(TOP4,稳定性核心)

✅ 问题现象

运行中随机出现404/500错误,部分操作执行失败,重启后恢复,是iOS自动化稳定性的核心坑点

✅ 根本原因

WDA的Session有超时机制,默认超时时间为60s,无操作时Session会自动过期,导致后续请求失败。

✅ 解决方案

client.py中实现自动重试+Session重建逻辑,所有请求失败后自动检测Session状态,重建Session并重试,成功率提升至99%:

def post(self, path: str, data: dict = None, use_session: bool = True, **kwargs) -> dict:
    original_path = path
    if use_session:
        path = self._session_path(path)
    url = f"{self.base_url}{path}"
    # 最多重试2次,首次失败则重建Session并重试
    for attempt in range(2):
        try:
            resp = self._session.post(url, json=data or {}, timeout=self.timeout)
            if resp.status_code == 404 and "/session/" in path:
                self._invalidate_session() # 重建Session
                path = self._session_path(original_path)
                url = f"{self.base_url}{path}"
                continue
            resp.raise_for_status()
            return resp.json()
        except Exception as e:
            if attempt == 0 and "/session/" in path:
                self._invalidate_session()
                continue
            return {"error": str(e)}
    return {"error": "Request failed after retry"}

7.5 其他核心问题(均已解决,项目合入)

  1. 截图Base64解码问题:WDA返回的截图是Base64格式,需解码为PIL图像后传给模型,已在device.py中实现自动解码。
  2. 应用启动失败问题:iOS应用启动依赖Bundle ID,已在apps_ios.py中配置主流应用的Bundle ID,可直接复用。
  3. 滑动手势适配问题:iOS的滑动是起点+终点,Android是起点+偏移量,已在device.py中实现滑动逻辑转换。

8. 常见问题

速查手册,按问题类型分类,所有问题均为高频提问,解决方案可直接执行,无需理解原理,优先排查此章节。

Q1: WDA连接失败(最常见)

错误信息Error: Cannot connect to WebDriverAgent
排查步骤

  1. 检查iproxy是否运行:pgrep -f iproxy,无输出则重新执行iproxy 8100 8100
  2. 检查WDA是否在Xcode中运行:查看Xcode Console是否有ServerURLHere日志
  3. 检查设备是否解锁:iOS设备锁屏后会暂停所有后台服务
  4. 验证连接:curl http://localhost:8100/status,成功则返回JSON

Q2: 坐标点击不准确

症状:点击偏移,2~3倍距离
解决方案:确认device.py中是否有_pixels_to_points转换函数,无则添加,是唯一根治方案。

Q3: 文字输入无效

症状:输入框聚焦,键盘弹出,无文字输入
排查清单

  • ✅ 输入格式是否为list(text)
  • ✅ 是否使用use_session=True
  • ✅ 输入后是否调用了hide_keyboard

Q4: Xcode签名失败

错误信息Failed to create provisioning profile
解决方案

  1. 确保Xcode已登录Apple账号
  2. 修改Bundle ID为唯一值
  3. 使用免费账号(有效期7天,足够调试)

Q5: USB连接不稳定

症状:iproxy频繁断开,终端提示disconnected
解决方案

  1. 使用原装USB线,避免第三方线材
  2. 关闭设备自动锁屏:设置 → 显示与亮度 → 自动锁定 → 永不
  3. 禁用设备的优化电池充电功能

9. 弹窗处理

9.1 弹窗识别能力(模型原生支持)

AutoGLM-Phone-9B是视觉-语言大模型,核心能力之一就是看懂屏幕并识别弹窗,无需额外开发,原生支持识别以下弹窗:
✅ 广告弹窗、权限请求(定位/通知/相机)、更新提示、活动推广、引导页、隐私政策弹窗
✅ 支持执行的操作:点击「关闭/X/取消/稍后再说/跳过」按钮,点击弹窗外区域关闭弹窗

9.2 弹窗处理优先级优化(核心配置)

prompts_zh.py中,将弹窗处理列为第一条规则,模型会优先关闭弹窗,再执行主任务,彻底解决弹窗干扰问题:

"1. **弹窗处理(最高优先级)**:执行任务时,若屏幕出现弹窗、广告、权限请求等干扰界面,优先关闭弹窗,关闭后再继续执行主任务。"

9.3 弹窗处理完整流程

1. 模型截图并解析屏幕内容 → 识别是否存在干扰性弹窗
2. 判断弹窗是否遮挡核心内容 → 若是,执行关闭操作
3. 验证弹窗是否关闭 → 关闭成功后,继续执行主任务
4. 若弹窗未关闭,尝试其他关闭方式(如点击弹窗外区域)

10. 总结

10.1 核心适配成果 ✅

  1. ✅ 完成Open-AutoGLM从Android到iOS的全量适配,所有核心功能正常运行
  2. ✅ 解决iOS坐标系统、文本输入、Session管理等核心技术问题,稳定性达99%
  3. ✅ 适配iOS原生操作:点击/滑动/输入/应用启停/截图/弹窗处理等全量功能
  4. ✅ 支持主流iOS应用:微信/支付宝/美团/淘宝/高德地图等

10.2 iOS vs Android 核心技术决策表(复盘)

决策维度 Android方案 iOS方案 选择理由
连接方式 ADB直连 USB+iproxy转发 iOS安全限制,WiFi连接不稳定
坐标系统 像素坐标 逻辑点坐标(÷scale) WDA原生规范,无其他方案
文本输入 ADB虚拟键盘 原生键盘+/wda/keys iOS无虚拟键盘,原生方案唯一
返回操作 物理键命令 左边缘滑动手势 iOS无物理返回键,手势是唯一方案
稳定性保障 无Session 自动重试+Session重建 WDA Session超时,必须适配

10.3 踩坑复盘(避坑指南)

所有坑按优先级排序,新人可直接规避:

  1. ❌ 坐标未转换 → 点击偏移(80%的人必踩)
  2. ❌ 文本输入格式错误 → 输入无效(70%的人必踩)
  3. ❌ Session未配置 → 404错误(60%的人必踩)
  4. ❌ WDA签名失败 → 部署失败(50%的人必踩)
  5. ❌ iproxy未运行 → 连接失败(40%的人必踩)

10.4 下一步优化方向

  1. ✅ 多设备并行控制:支持同时连接多台iOS设备,执行不同任务
  2. ✅ 截图性能优化:当前每步截图,优化为按需截图,提升速度
  3. ✅ 弹窗识别增强:优化模型提示词,提升弹窗识别准确率至99%
  4. ✅ 模拟器支持:适配iOS模拟器,降低调试门槛
  5. ✅ 录屏功能:添加操作录屏,方便调试与问题排查

附录

A. 完整测试清单(一键执行,排查所有问题)

# 1. 环境检查
which iproxy && python3 --version && xcodebuild -version
# 2. 启动端口转发
iproxy 8100 8100 &
# 3. 启动WDA(Xcode中执行)
# 4. 验证WDA连接
curl http://localhost:8100/status
# 5. 项目自检
python main_ios.py --check-only
# 6. 运行测试任务
python main_ios.py --base-url https://open.bigmodel.cn/api/paas/v4 --model autoglm-phone --apikey "你的Key" "打开微信"

B. 参考资料(权威来源,可溯源)

  1. WebDriverAgent 官方源码
  2. iOS 坐标系统官方文档
  3. AutoGLM-Phone-9B 论文
  4. libimobiledevice 官方文档

✅ 至此,Open-AutoGLM iOS平台的完整部署、适配、测试、问题解决全部完成,所有功能均可正常运行,稳定性与体验均达到生产级别。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐