From fa07ed08041ea68bdf57d30a3e42e73cd3400e64 Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Sun, 13 Sep 2026 15:38:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(platform):=20=E8=AE=BE=E5=A4=87=E7=AB=AF?= =?UTF-8?q?=E5=95=86=E5=BA=97=E6=94=AF=E6=8C=81"=E8=AF=B7=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E9=9D=99=E9=BB=98=E8=A3=85"=E2=80=94=E2=80=94=20?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E8=AF=B7=E6=B1=82=E3=80=81=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E8=B5=B0=20adb=20=E8=90=BD=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 背景:设备端自己调系统安装器在 MIUI 上要过「继续 → 勾选未经安全检测 → 继续更新」 甚至 ICP 备案检查好几步;而平台用 adb(推送 + pm install)装是**静默**的,实测 升级 2.7s、全新安装 7.9s、336MB 大包也没弹过一次框。 所以给设备端商店补一个"请求平台装"的出口:用户还是在手机上选应用(应用商店体验), 真正干活的是平台,几秒钟装完、零弹窗。 - web/device_agent_api.py 新增 `POST /api/device/agent/install`: 设备带令牌调它 → 平台复用应用管理的安装器(`apk_mgr.install`,本身已是 推送 + pm install、并发 5 台)→ 返回是否受理;失败时设备端自行退回本机安装 - 鉴权与设备识别沿用同一套(令牌 + 指纹),未登记设备拒绝并说明原因 注:设备端 APK 那边的对应按钮改动已暂停(用户决定先不动 Agent), 这个接口属于平台侧能力,先落在本次分支里,等 Agent 恢复时直接可用。 --- web/device_agent_api.py | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/web/device_agent_api.py b/web/device_agent_api.py index 357ac93..82c0b0b 100644 --- a/web/device_agent_api.py +++ b/web/device_agent_api.py @@ -162,6 +162,48 @@ def api_dev_agent_apk(apk_id): mimetype="application/vnd.android.package-archive") +@bp.route("/api/device/agent/install", methods=["POST"]) +def api_dev_agent_install(): + """设备请求**平台**帮它装这个应用(平台走 adb,静默,没有系统安装框)。 + + 为什么这么设计:普通 App 自己调系统安装器,MIUI 上要过「继续 → 勾选未检测 + → 继续更新」甚至 ICP 备案检查好几步;而 `adb install` 在同一台设备上实测是 + **静默**的(升级 2.7s、全新安装 7.9s,零弹框)。 + + 所以设备端商店的「安装/更新」按钮走这里:**用户还是在手机上选**(应用商店体验), + 真正干活的是平台,几秒钟装完。万一 adb 被 MIUI 拦了,返回 ok=false, + 设备端自己退回本地安装(有弹框,但至少能装)。 + """ + deny = _deny() + if deny: + return deny + data = request.json or {} + apk_id = str(data.get("apk_id", "")) + if not apk_id: + return jsonify({"ok": False, "error": "缺少 apk_id"}), 400 + + fp, serial, name, known = _identify() + if not serial: + return jsonify({"ok": False, "error": "无法识别设备"}), 400 + if not known: + return jsonify({"ok": False, "error": "这台设备还没登记进平台设备池"}), 409 + + from core.models import ApkFile + if not ApkFile.query.get(apk_id): + return jsonify({"ok": False, "error": "apk not found"}), 404 + + from web import context + try: + ok, msg = context.apk_mgr.install(apk_id, [serial]) + except Exception as e: + _log.error("设备端请求安装失败: %s", e) + return jsonify({"ok": False, "error": "平台安装任务启动失败"}), 500 + _log.info("设备端请求安装: %s(%s) apk=%s -> %s", name or "未登记", serial, apk_id, msg) + if not ok: + return jsonify({"ok": False, "error": msg}), 400 + return jsonify({"ok": True, "msg": msg, "serial": serial}) + + @bp.route("/api/device/agent/report", methods=["POST"]) def api_dev_agent_report(): """设备上报下载/安装结果,平台侧留下记录(应用管理页可见)。