网鱼AI电商助手  ·  面向闲鱼卖家的 AI 铺货与发布自动化 工作日 09:00–18:00  ·  试用与部署 免费

手机 APP 自动化通道,把发布写成可回查的流程

手机 APP 通道只做一件事:把闲鱼客户端里那一串重复的点击写成流程文件,让每一次发布都按同一套字段、同一套顺序走完。这页不讲概念,讲怎么判断一台手机值不值得接进来、YAML 流程怎么分段、中文输入为什么是第一个坑、界面文案改版之后从哪改起,以及提交前那道复检闸门为什么默认要拦住。每一节都给可以照着做的判断点,不讲原则,只讲哪一步会坏、坏了怎么看出来。

ADB 驱动YAML 流程中文输入控件定位拟人化节奏复检闸门
固定在三脚架上的手机
App channel · 设备端流程、拟人化操作与发布回执

01  /  通道定位

先说清楚它替代的是哪一段手工

闲鱼的商品发布主要发生在手机客户端。电脑网页版通道走 HTTP API,速度快、可以并行提交,但客户端里有些入口在接口层面并不完全等价:编辑页的字段展示顺序、图片上传之后的裁剪位、草稿状态的保存时机、部分只在 APP 内出现的活动入口。手机 APP 通道解决的就是这一段——用 ADB 驱动一台安卓真机或模拟器,把「打开应用、进入发布、填标题、填描述、选类目、传图、定价、提交」这一串动作写成 YAML 流程,按顺序执行,每一步留下日志。

它的价值不在点得快,而在点得一样。手工发布时,同一个人上午和下午填字段的顺序都会变,漏填包邮、漏选成色、图片顺序颠倒,全靠记忆维持;换成流程文件之后,字段与顺序是写死的,跳过一步就会在日志里显出来,事后能回查是哪一条商品在哪个环节停住。判断自己该不该用这条通道,主要看三件事:

发布动作是否重复

同一套字段、同一批图片反复填,重复才有写流程的收益。如果每次字段都不同、一个季度只发几条,维护流程的成本会高于收益。

是否必须在手机端走完

某些类目在客户端里的字段比接口更完整,或者你的账号只在 APP 里能走通整条发布链路。这种情况下手机通道不是可选项,而是唯一路径。

能否留出一台稳定设备

流程跑到一半断网、锁屏、弹系统更新提示,这一轮就作废。设备要能长期插电、接固定网络、关掉自动更新与锁屏密码弹窗。

如果只有第一条成立,先看电脑网页版通道更划算:两条通道共用同一套选品、文案、闸门与台账,换通道不需要重做内容,两者的分工写在产品功能总览里。反过来说,手机通道也不是「另一套系统」,它读的是同一份发布计划,只是执行端换成了屏幕上的点按。

还有一个容易被忽略的判断点:你打算发布的是「新品」还是「同一批货的多个链接」。前者字段每次不同,流程的价值在于不遗漏必填项;后者是同一份内容复制到不同链接,流程的价值在于顺序与配图完全一致。两种诉求都能满足,但流程的写法不同——前者的分支多,后者更依赖去重与分散。

还有一类场景容易被忽略:同一条商品要在不同账号或不同城市重复上架。这时候流程的价值不在省点击,而在于每一条的配图顺序、成色标注、运费模板完全一致,不会因为换个人操作就出现「这条写包邮、那条不写」的差异。判断这条通道值不值得接,最后可以落到一句话:你的发布动作里,有多少是可以被写成「先判断、再执行」的?这个比例越高,接进来的收益越明显;如果绝大多数步骤都要临场决定,那先别接,先把发布规范写出来。

另外要接受一件事:这条通道不会让发布变得「快很多」,它的收益是可核对。原来靠人记的字段顺序、配图顺序、运费模板,现在写在一个文件里;原来出错只能事后发现,现在提交前有断言、有闸门。如果你的目标是「今天多发一批」,那么要管的其实是节奏,不是通道。

02  /  环境准备

设备与环境:先排除三类会反复失败的配置

手机通道的失败,多数不是流程写错,而是运行环境没弄干净。上线前必须把三类问题先排掉:设备本身的状态、ADB 服务怎么寻址、多个进程怎么分端口。这三类的共同点是:出问题时表现得很像流程 bug(某一步一直超时),但改流程永远改不好。

真机还是模拟器

真机最接近真实客户端环境,代价是电量、网络、系统弹窗都要人管;模拟器可快照回滚、批量复制,但部分客户端能力(摄像头、定位、机型信息)与真机不同。惯常做法是:主发布路径用真机,回归测试与批量压测用模拟器,两边的流程文件保持同一份。

驱动必须跑在 Windows 侧

已知的工程坑是 WSL 到 Windows 的 TCP 不通。如果驱动跑在 WSL 里,ADB 连不上 Windows 侧的设备服务端,表现为「设备在,但命令一直超时」。所以驱动进程放在 Windows 侧执行,不要绕一层。

ADB 服务端显式寻址

不要依赖默认端口碰运气。服务端地址与端口在配置里写死,命令带超时封顶,避免一条卡住的命令拖死整轮流程。判断设备是否存活只认一次 shell 往返的结果,不看进程列表里有没有那个名字。

一个设备一条端口,加端口锁

uiautomator2 一个进程只绑一个 adb server 端口,多设备并行时必须一机一端口。同一端口被两个进程同时打开会互相踢掉,所以还要加端口锁,拿不到锁就排队等,不要重试抢。

下面这五条是上线前的固定检查项。它们看起来琐碎,但每一条都对应过真实的「偶发失败」:

  • 设备固定固定机型、固定充电位、固定网络,别每天换一台手机测同一份流程
  • 系统弹窗清干净关闭系统更新、应用商店自动升级、锁屏密码与指纹弹窗
  • 权限一次给全存储、通知、悬浮窗、输入法切换权限,缺一项会在某个步骤突然卡住
  • 路径先于环境变量配置里的数据目录用绝对路径,不要依赖启动之后再设置的环境变量
  • 写生产数据前留备份任何会改动正式台账的操作,先落一份 .bak 再动手

设备数量超过一台之后,端口分配与设备编号要成体系地管,做法见多设备并行管理;在只有一台设备的时候,先用一台把全流程跑顺,是更快的一条路。

环境还有一个隐性条件:时间。设备时间与运营电脑的时间不一致,会让发布时间戳、台账记录与平台显示的时间对不上。排查时人会先怀疑流程写错了,实际只差了几分钟。所有设备统一对时,并且让流程启动前先读一次设备时间写进日志,这一条在跨设备并行时尤其重要,否则几条记录谁先谁后都说不清。

03  /  流程设计

YAML 流程怎么分段,一段只做一件事

流程文件的写法决定它好不好维护。经验规则是一屏 3 到 6 步,一步只做一个动作,每步之前先确认目标在不在。把所有点击塞进一个长步骤里,失败时只知道「这一步错了」,不知道错在第几下。流程动作是可枚举的,用法有明确边界:

动作作用什么时候用
by_any给一组候选选择器,任一命中即通过按钮文案在版本之间会变,或同一功能有两种控件类型
if_enabled控件可点击才点提交按钮在图片未传完时是灰的,先判后点
if_exists存在就执行,不存在跳过关掉版本更新提示、网络异常弹窗这类偶发遮挡
require必须存在,否则判失败发布页的标题输入框、价格输入框
abort主动中止并记账闸门没过、类目选错、关键字段为空
reset回到干净起点上一轮中途失败,避免带着半屏表单进下一轮
dump导出当前界面结构定位失败时抓现场,用来改选择器
shot截图留证提交结果页、异常弹窗

分段建议按页面切:进入发布页、填基本信息、选类目与成色、传图与排序、定价与运费、提交与回执。每段结束加一个断言,比如「标题框的内容长度与源文本一致」「图片数量等于计划数量」「价格与计划价一致」。分段的另一个好处是失败可以定点重试:只有传图那段失败,就只重跑那一段,不必从打开应用开始。

有一种常见误区是把断言写成截图人工看。截图只能证明流程跑过,不能证明字段填对了;断言必须读控件的实际文本或实际数量。反过来也不要断言过度——如果每一步都断言,一处界面文案变化就会连着报十几条失败,日志反而看不清到底哪一环出了问题。断言只放在「错了会出事故」的位置:标题、价格、类目、图片数量、提交结果。

流程文件要能被人读懂,也要能被重复使用。变量、类目、文案都应该从外部读取(发布计划、商品池),流程只负责动作与断言;如果流程里写死了某条商品的标题,这份文件就只能跑一次。判断标准很简单:换一条商品,需要改流程文件吗?需要改,说明职责分错了;不需要改,才是可复用的流程。

流程还要考虑幂等:某一段失败重试时,必须能判断这一步到底做没做过。比如传图这一段,重试前先读一次已有图片数量,已经传了 4 张就从第 5 张开始,而不是从头再传一遍,否则最后一张链接上会出现重复图,数量超限被闸门挡住,人还以为是闸门误判。

04  /  中文输入

中文输入是第一个坑,三条通道各有边界

ADB 自带的文本输入打不出中文,原因是它只按 ASCII 键位发送,中文会变成空白或者一串问号。这一点不解决,后面所有步骤都没有意义——标题框是空的,提交流程照样能走完,但发出去的商品没有标题。系统里准备了三条输入通道,按场景选:

uiautomator2 通道

这是主力通道,中文已经实测可以完整输入,长短文本都稳。默认先用它,除非设备上出现输入法冲突。

adbkey 通道

模拟按键输入法逐字敲。设备上装了第三方输入法、u2 输入被吞的时候切到这条;代价是长文本慢,遇到生僻字可能漏。

adb_input 通道

通过输入法广播接收整段文本。适合一次贴入长描述,前提是设备端已装好配套输入法并切为当前输入法。

三条通道都要配同一个验证动作:输入完成后,把输入框里的实际文本读出来,与源文本逐字比对,不一致就中止,不要带着错文本提交。这条断言比截图有用得多,因为它能抓到「输入框只进去前几个字」「换行被截断」「末尾空格被吞」这些真实故障。

另外两种常见失败要提前处理:输入框拿到了焦点但软键盘没弹出来(先点一次输入区域再发文本),以及长文本粘贴被剪贴板权限拦住(改用逐段输入,每段之间加一个短确认)。描述里如果有分段换行,换行符在三条通道里的处理并不一致,需要在描述段单独测一次,而不是假设它能通用。

文案本身怎么写、怎么规避绝对化用语与重复表述,属于另一个环节,见AI 商品文案改写。这里只保证一件事:写好的那段中文,能原样落进客户端的输入框里。

中文输入还有一个细节:候选词。用按键模拟逐字敲的时候,同音字会被候选词替换,标题里的型号、编号尤其容易出错,而且错得毫无提示。所以凡是含型号、字母与数字混排的字段,输入之后必须逐字比对,不能只看长度——长度相同但内容不同的错误,是这套流程里最难被发现的一类。

输入通道的切换要写在流程配置里,而不是每次手动改。同一批设备里如果有两台必须用按键通道,配置就要按设备编号区分,而不是全局改成一条——全局改会把原本正常的那几台也拖慢。

05  /  控件定位

控件定位:界面改版是常态,不是事故

客户端更新一次,控件层级、文案、控件类型都可能变。流程能不能活下来,取决于选择器怎么组织。这里有四个必须做的事,顺序也就是排查顺序:

dump 要带重试

设备端 dump 偶发返回空或者连接被重置,一次失败就判流程失败会制造大量假警报。做法是重试若干次,仍失败才放弃,并把最后一次的原始结构落盘。

launcher 屏先试压缩模式

已知现象:在 launcher 屏上直接 dump 会失败。处理顺序是先试压缩模式,不成就退回普通 dump,两条都失败再判环境问题,而不是判流程问题。

选择器给候选,用序号消歧

同一句文案在页面上可能出现多处(比如两个「发布」)。每个选择器配 instance 序号定位到具体那一个;同类控件用一组候选,任一命中即可,避免为一种控件类型写死一条流程。

改版只改一处

把选择器集中在流程文件的一小段,界面改版时只动这里。如果选择器散落在几十个步骤里,一次改版就要通读全文——这也是流程要分段的实际理由。

怎么判断定位稳不稳:连续跑三轮全部通过才算稳;偶发失败要记频率和当时的界面结构,频率高的先怀疑选择器太具体(依赖某个版本独有的文案),而不是怀疑设备。反过来,如果失败了却一直重试成功,说明选择器已经脆了,趁还能跑的时候改成候选式,别等到彻底断掉。

还有一种情况值得单独说:选择器命中了,但点下去没反应。原因通常不是定位错,而是控件在视觉上存在、实际被遮挡(弹窗、遮罩、软键盘),或者点击坐标落在了不可点区域。这类问题靠 dump 结构看不出来,要用 shot 留一张现场图,再对着图判断遮挡层是什么,然后为它加一条 if_exists 关闭动作。

选择器应该跟着语义走,而不是跟着界面走。它描述的是「价格输入框」这个角色,不是「页面上第 7 个输入框」这个位置。前者在界面微调之后仍然有效,后者一次调整就全断。语义化的选择器第一次写起来慢一点,但改版时省下的是整段时间,也不会因为换了一台分辨率不同的设备就失效。

跨机型的时候还有一个坑:同一份流程在两台分辨率不同的设备上,同一个控件的位置会变,但结构里的层级关系不变。这也是选择器必须按语义写的直接理由——按坐标写的流程换个机型就全错,按结构写的一直有效。多设备并行时,流程文件应当只有一份。

06  /  操作节奏

拟人化参数:每个取值都有具体理由

机械化的操作有很明显的特征:点击间隔是一模一样的常数、每次都落在同一个像素、按下与抬起之间没有停留。引擎在这一层做了四件事,参数都是实测收敛出来的:

参数取值解决什么
点击间隔0.34 到 1.30 秒之间随机固定间隔是最容易被识别的特征,随机区间让节奏不呈现周期
滑动曲线smoothstep线性滑动在起止处速度突变,缓入缓出更接近手指
落点目标坐标正负 4 像素每次点在同一像素上属于机器特征,微抖动是正常人的手
按压时长72 到 155 毫秒瞬时点击几乎没有按下过程,短按需要有真实停留

需要说清楚的是,这一层的作用是让操作不呈现机器特征,不是账号安全的全部。账号安不安全,更取决于发布节奏上限、商品是否合规、同款链接是否堆在同一账号上——这些属于另一种控制,见防封控与账号安全。

另一个方向上的误区是把间隔拉到很长,觉得越慢越安全。一条商品如果卡十分钟,设备占用时间变长、失败重试窗口变短,实际稳定性反而下降。参数应该停在「不像周期」而不是「尽可能慢」的位置。还有一点:随机区间要真的随机,不要用固定序列循环,否则连续几十次操作之后仍会出现肉眼可辨的节律。

滑动这一项最容易被忽略。商品详情页经常需要下滑才能看到提交按钮,如果滑动速度恒定、距离每次相同,这一段就是整条流程里最像机器的片段。smoothstep 解决的是速度曲线,距离本身也应该按目标位置算,而不是每次滑固定距离。

参数不是越细越好。把每一次点击都单独算一遍随机,代价是流程不可重放:出了问题没法复现同一段操作。惯常做法是随机源可固定——调试时用固定种子复现,正式跑用真随机。这一点直接决定你能不能在事后重演一次失败,也是排查「偶发」问题时的唯一抓手。

记录参数时把「间隔区间」和「落点抖动」分开记。合并成一个「拟人化开关」,出问题时就无法判断是哪一项调过头了,只能整体回退。

这四项参数在配置里应该各自独立可调,并且写进注释说明理由。改的时候一次只动一项,动完跑一轮看断言是否仍然全过,才有办法知道是哪一项带来的变化。

07  /  发布闸门

提交前的复检闸门,默认是拦住而不是放行

流程能点完,不代表这条商品该发。发布计划可能是几小时前排的,这中间商品改了价、链接被下过、同类目已经在售同款。所以到点提交之前要用当下的数据重跑一遍闸门,不通过就不发,这个策略叫 fail-closed——失败时的默认动作是停止,不是继续。

合规

标题与描述里的绝对化用语、功效宣称、侵权表述,逐条比对规则库,命中就拦。规则怎么分层见下面的检查清单与合规页。

商品指纹去重

按标题、描述、价格、主图算指纹,与台账里已有的记录比对,重复的直接不发,避免同一件货在两个链接上互相抢流量。

分散度

类目、发布时间、标题、主图相似度要拉开。同一批商品挤在同一时段、同一类目、同一套图,是最明显的批量特征。

结构约束

同款链接在一个账号内不超过 3 条;单条链接配图 3 到 9 张。少图信息不足,多图容易混入重复图。

除了商品侧的闸门,还有平台健康闸:平台侧出现异常(接口报错率升高、页面结构大面积变化)时暂停整批发布,不硬发。硬发的代价是拿一批真实商品去试探平台状态,试探失败留下的是账号记录,不是日志。

闸门的位置要放在提交动作的前一步,而不是流程开始时。放在开始时会漏掉排期之后发生的所有变化,也漏掉图片上传过程中才发现的问题(比如某张图上传失败导致只有 2 张,低于下限)。规则库的组织方式与每条规则判什么,见商品合规检查。

  • 闸门在最后一步提交前跑,不用排队时的旧数据
  • 不通过就 abort不降级、不「先发出去再说」,失败记进台账
  • 平台异常整批暂停不是只跳过当前这一条
  • 规则库可追溯每条拦截要能说出命中了哪条规则

闸门不通过之后的处理也要写清楚:是丢掉这条商品,还是退回队列等下一轮?退回队列更合理,但要带上退回原因与重试次数上限。否则一条永远不过闸的商品会被反复排进计划、占满槽位,把真正能发的商品挤出去,表现出来的现象是「计划排得很满,实际一条没发」。

闸门的结果要写回台账,不只是拦住就完了。记录里保留「哪条规则、哪个时刻、什么数据」,下次同一批商品再排进来时,能直接看出是规则变严了还是商品本身变了。没有这一步,闸门就只是一道黑箱,人会开始绕过它。

08  /  台账与证据

台账、证据,以及那些踩过一次的坑

两条通道写同一本台账,口径只有一处,记录里包含 item_id、标题、描述、价格与时间戳。共用一本台账的意义在于:换通道发布、补发、核账时看到的是同一份事实,不会出现「手机发的在一张表、网页发的在另一张表」这种对不上的情况。具体的表结构与看板用法见发布数据台账。

失败要留现场

定位失败时导出界面结构,提交异常时截图。日志里只有「第 5 步失败」,事后无从判断是改版还是网络,有了 dump 才能改选择器。

自检不能碰生产

曾经出现过自检污染生产发布记录的问题,根因是路径解析早于环境变量生效,自检写到了正式数据文件上。现在的做法是:写生产数据前留 .bak,自检进程带标记时写生产直接抛错,整轮自检前后对生产文件做哈希比对。

自检要有具体数字

当前手机通道自检 24 项全过,引擎自检在三台设备上各 13 项全过。数字的意义是回归基线,每次改动后跑一遍,掉一项就说明改坏了什么。

  • 端口不抢多设备并行时一机一端口,加锁排队,不重试硬抢
  • 驱动在 Windows 侧不要放进 WSL,TCP 不通会表现为满屏超时
  • dump 有降级路径先压缩模式,再普通模式,最后才判失败
  • 断言读文本标题、价格、图片数量都读控件值比对,不靠截图
  • 每轮结束 reset中途失败也要回到干净起点,避免半屏表单进下一轮

把这五条做扎实,这条通道就能长期跑;哪一条松了,故障会以「偶发失败」的形式出现,而偶发故障最难查——它不留下稳定复现的路径,只留下一条条对不上的台账记录。发布节奏怎么排、每天发几条、间隔怎么定,属于另一层控制,见定时发布与节奏控制。

台账要能反查一次发布的完整过程:谁排的、哪条通道执行的、闸门放行的时间、提交返回的 item_id、失败时停在哪一步。缺了其中任何一项,事后复盘就只能靠记忆。字段宁多不缺,但每条记录只能有一处来源,不要两个模块各写一半,否则早晚出现两份互相矛盾的事实。

这也解释了为什么台账要放在通道之外:通道是可以换的,台账不能跟着换。哪条通道写的记录,字段口径都应当一致,否则换一次执行方式,历史数据就对不上了。

手机 APP 通道一定要用真机吗,模拟器行不行?
两条都用得上,但要分开用途。主发布路径建议用真机,因为客户端的摄像头、定位、机型信息与真机一致,踩不到模拟器特有的差异;回归测试与批量压测用模拟器,可快照回滚、可复制多份。两边的流程文件保持同一份,不要为模拟器单独维护一套。
为什么 ADB 打不出中文,页面上的标题会变成空白?
ADB 自带的文本输入只按 ASCII 键位发送,中文会被丢掉,于是流程能走完但标题框是空的。系统里备了三条输入通道:uiautomator2 通道中文已验证可完整输入,是默认选择;adbkey 通道模拟按键逐个敲;adb_input 通道通过输入法广播整段贴入。三条都要配同一个验证动作——输入后读回输入框文本,与源文本逐字比对,不一致就中止。
客户端版本更新之后流程全断了,要重写吗?
多数情况不用重写,只需改选择器。这也是流程要按页面分段、选择器要集中在一处的理由。修的顺序是:先用 dump 拿到新版界面结构,比对旧选择器差在哪(文案变了还是控件类型变了),把选择器改成一组候选并用序号消歧,然后连续跑三轮确认稳定。如果选择器散落在几十个步骤里,一次改版就要通读全文,那说明结构本身需要重排。
点击间隔随机到 0.34 到 1.30 秒,是不是越长越安全?
不是。这一层的作用是让操作节奏不呈现周期,不是账号安全的全部。把间隔拉到很长会让单条商品的占用时间变长、重试窗口变短,稳定性反而下降。账号安全更依赖发布节奏上限、商品合规、同款链接是否堆在同一账号这些控制,做法在防封控那页。
两条通道能不能同时用,会不会重复发布同一条商品?
可以同时用,不会重复。同一份发布计划里,每个槽位归属哪条通道是算出来的,用的是同一个判定函数,不是靠人事先标注。加上商品指纹去重和提交前的复检闸门,同一条商品在两侧都不会被重复提交。
流程跑到一半失败了,下一次会不会接着上次的半屏表单继续?
不会,前提是你用了 reset。中途失败时应该先把界面恢复到干净起点再进下一轮,否则残留的草稿、已经填好的标题会串到下一次。reset 属于流程里的常规动作,不是异常处理才想起的东西。
自检会不会影响正式发布数据?
曾经会,已经修掉。当时的问题是路径解析早于环境变量生效,自检进程写到了正式数据文件上。现在的防护有三层:写生产数据前留 .bak 备份;自检进程带标记时写生产直接抛错;整轮自检前后对生产文件做哈希比对,前后不一致就说明被改过。

D—01 / 判断标准

先跑通一条,再谈第二台设备

手机通道的成本不在代码,在设备与环境。一台设备、一份流程、一本台账跑顺了,复制第二台才有意义;顺序颠倒,故障会成倍出现却找不到源头。

上线前的最小验收

用一台真实设备,把一条真实商品从流程起始跑到提交成功,中间不改任何配置;然后用同一条商品重跑一次,确认指纹去重把它拦住;再故意改坏一个选择器,确认流程会 abort 而不是蒙混提交。三件事都成立,这条通道才算可用。

先跑通一条真实发布,再谈铺量

把账号、设备、商品素材交给我们的部署流程,先跑通一条真实发布并留下可核对的日志,确认没问题再谈规模化。