From b3b17210f1697c32124b0803d7355c30005d4ec1 Mon Sep 17 00:00:00 2001 From: zijunchiang Date: Sat, 26 Sep 2026 21:00:21 +0800 Subject: [PATCH] =?UTF-8?q?V1.4.9:=20=E4=BF=AE=E5=A4=8D=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E8=A2=AB=E8=AF=AF=E5=88=A4=E4=B8=BA"=E6=96=AD=E7=BD=91?= =?UTF-8?q?=E6=81=A2=E5=A4=8D"=EF=BC=88=E5=B9=B6=E8=A1=A5=E9=BD=90=20WebVi?= =?UTF-8?q?ew=20=E5=A4=B1=E6=95=88=E5=8E=9F=E5=9B=A0=E5=8F=96=E8=AF=81?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现场日志(1.4.8)显示启动瞬间就出现: 20:46:59.636 NET-UP 设备网络已恢复, 重建歌曲源会话 20:46:59.647 NET-REFRESH reason=net-up retried=0 20:46:59.980 BOOT 即 NET-UP 出现在 BOOT 之前 —— 启动被当成了"断网后恢复"。 根因: KtvNetworkMonitor.start() 末尾无条件 onChange(initial), 注册 ConnectivityManager 回调时系统会回报一次初始状态,上层把它当成了状态跃迁。 而启动流程(onCreate)已经做过 startRemoteServer()/updateMobileQrOverlay()/ refreshLogDeviceContext()/DeviceMac 解析,所以这次"恢复"是纯粹重复劳动,且有副作用: - SongApiClient.resetSourceSession() 白清掉刚建立的歌曲源会话; - Eac19WindowGuard.noteUrlOk() 语义错误(还没取到任何地址就标记窗口正常, 可能掩盖真正的歌曲源窗口到期提示); - 状态栏被写成"网络已恢复"(启动瞬间就显示,用户可见的错误文案)。 修复: - KtvNetworkMonitor.start/refresh 的回调签名改为 (online, initial), initial=true 表示"注册时的初始状态"; - MainActivity.onNetworkStateChanged(online, initial): 初始状态**只更新断网角标**, 不做任何恢复动作;恢复动作(重建会话/重启点歌服务/刷新二维码/重试下载) 只在真正的 offline→online 跃迁时执行。 同时补齐 WebView 失效原因的取证(旧日志只有"KtvApi 未导出"这一句,无法定因): - wrapHtml 注入特性探测: 上报 WEBVIEW ua=... asyncFunction=yes|no promise=... (用 new Function 探测,避免探测语句自身引起语法错误)。Android 5.x 的 WebView 可能是 Chrome 39~4x,不支持 async/await 会让**整个 ktv_api.js 语法报错** → window.KtvApi 未定义、桥永远不就绪,这条日志可直接确证; - window.onerror 上报脚本解析/运行错误(JS-ERROR ... @line:col),语法错误也会触发; - 合并重复的失败行: "JS-BRIDGE 初始化返回 false" 与 "JS-BRIDGE 判定本机 WebView 不可用" 只保留后者(含原因)。 版本 1.4.8(28) 到 1.4.9(29);签名证书不变。ktv_api.js 未改动,KTV_BRIDGE_API 仍为 8。 --- AGENTS.md | 9 +++++++- app/build.gradle | 4 ++-- .../main/java/com/local/ktv/KtvJsBridge.kt | 23 ++++++++++++++++--- .../java/com/local/ktv/KtvNetworkMonitor.kt | 19 ++++++++++----- .../main/java/com/local/ktv/MainActivity.kt | 17 ++++++++++++-- .../main/java/com/local/ktv/SongApiClient.kt | 2 +- 6 files changed, 59 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 11daaf0..e3af43e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,7 +160,7 @@ $BT/apksigner verify 目标名.apk ### 版本号 -- `app/build.gradle`:`versionName "1.4.8"` / `versionCode 28`(18~21 被本机临时诊断包占用过) +- `app/build.gradle`:`versionName "1.4.9"` / `versionCode 29`(18~21 被本机临时诊断包占用过) - App 内显示统一用纯版本号(不加 `(versionCode)` 括号) - ⚠️ **发布构建已开启 NewApi 闸门**(`lint { checkReleaseBuilds true; fatal += ['NewApi'] }`): 任何「调用了高于 `minSdk 21` 且未做版本守卫的 API」都会让 `assembleRelease` 直接失败。 @@ -321,6 +321,13 @@ $BT/apksigner verify 目标名.apk - 恢复 → `refreshNetworkState()`:重解析网卡 MAC + 日志上下文、**重建歌曲源会话**、 复位 `Eac19WindowGuard`、重启本地点歌服务并刷新二维码、自动重试断网期间失败的下载(最多 8 首)。 换网/换 IP 时 `remoteNetworkMonitor` 走同一个 `refreshNetworkState()`(静默,不弹提示)。 + - ⚠️ **启动 ≠ 网络恢复**:`KtvNetworkMonitor.start()` 的回调带 **`initial`** 参数, + `initial=true` 表示"注册回调时系统回报的初始状态"。**绝不能**把它当成"断网后恢复"—— + 启动流程(`onCreate`)自己已经做过 `startRemoteServer()`/二维码/设备上下文, + 再走一遍恢复逻辑会:白清刚建立的歌曲源会话、语义错误地 `noteUrlOk()`(掩盖真正的 + 窗口到期提示)、把状态栏错写成"网络已恢复"(启动瞬间就显示,用户可见)。 + 初始状态**只更新断网角标**,恢复动作只在真正的 offline→online 跃迁时执行 + (2026-09-26 由现场日志 `NET-UP` 出现在 `BOOT` 之前而发现)。 ⚠️ **「断网重连后再也下载不了、日志却显示歌曲源获取成功」的根因**: `SongApiClient.clearTokenCache()` 原本是**空实现**,JS 侧 `window.api.tokens` 与 `_apiInitPromise` 会被一直复用;而歌曲源按「出口 IP + device」识别、试用窗口也记在出口 IP 上, diff --git a/app/build.gradle b/app/build.gradle index 2598518..44db3de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "com.local.ktv" minSdk 21 targetSdk 25 - versionCode 28 - versionName "1.4.8" + versionCode 29 + versionName "1.4.9" ndk { // 双 ABI 打包:兼容 64 位(Exynos 1580 等 arm64-v8a)与 32 位设备(极米 Play 超越版 // 的 Amlogic 950X2/S905X2 采用 32 位 Android 用户态,必须包含 armeabi-v7a,否则 diff --git a/app/src/main/java/com/local/ktv/KtvJsBridge.kt b/app/src/main/java/com/local/ktv/KtvJsBridge.kt index 2326cf8..2e7ca98 100644 --- a/app/src/main/java/com/local/ktv/KtvJsBridge.kt +++ b/app/src/main/java/com/local/ktv/KtvJsBridge.kt @@ -388,11 +388,28 @@ class KtvJsBridge(context: Context) { private fun wrapHtml(script: String): String { val escaped = script.replace("