Skip to content

Releases: yaxiaiyuting/Arris

Arris v3.8.18-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 18:35

v3.8.18-gpl(versionCode 138)

音频流三段计时进日志

MediaHttp 挂上了 EventListener,每条音频请求都会打:

I MediaHttp: audio headers code=200 host=aqqmusic.tc.qq.com elapsed=449ms
I MediaHttp: audio call end elapsed=1321ms
I MediaHttp: audio call failed after 10012ms: SocketTimeoutException …

配合已有的 SongUrlFetcher: level=… ok in Xms 与 NcrustHttpTiming,
「点了歌之后那几秒花在哪」现在是三条可对齐的线:取链 → 建连/响应头 → 传输/解码。

实测参考(手机裸连):QQ 的 CDN TTFB 0.45s、877 KB 共 1.3s —— 服务端侧不慢。

补掉最后一个裸 OkHttpClient

AmllTtmlClient(TTML 歌词拉取)此前是 OkHttpClient().newBuilder() ——
唯一一个绕过 AppHttp 的客户端。本机 IPv6 不通时它会白等到超时,表现为「歌词一直不出来」。
现已并入 AppHttp。

HttpClientDnsAuditTest 也扩容了:OkHttpClient() 与 .newBuilder() 一并禁止 ——
它正是从这个缝里漏过去的。

校验

全量 JVM 单测 3505 项 0 失败。

Arris v3.8.17-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 18:22

v3.8.17-gpl(versionCode 137)

音源不可播时,不再是一行「看不出原因」的日志

排查 B站/QQ 失效时,logcat 里只有:

W PlayerViewModel: no playable url ... kind=UNKNOWN source=bilibili code=-

既没有网络请求记录,也没有原因 —— 分不清是「音源被关掉」「未登录」还是「接口失败」。

原因在 MusicSourceProvider.resolveUrlOutcome:provider 返回 null 时直接构造 UNKNOWN,不打日志。
现在补一条:

W MusicSourceProvider: resolveUrl returned null source=bilibili id=… level=…
(可能是该音源未启用、未登录,或该档位没有可播 URL)

这次 B站/QQ 失效的真实根因是设备上的 ncrust_settings.xml 被清空
(bilibili_enabled 丢失 ⇒ B站按 v3.1.0 的设计默认关闭),已恢复并验证。
这条日志是为了让下次不必再靠猜。

一并包含(3.8.16)

彩蛋「推荐一首」、AppHttp 统一网络入口(IPv4 优先 / 超时 / 共享连接池)、封面与艺人图修复。

校验

全量 JVM 单测 3505 项 0 失败。

Arris v3.8.16-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 17:41

v3.8.16-gpl(versionCode 136)

彩蛋里能推荐一首了

自由听众席(关于页版本号连点七次)原来只有标题和「继续听歌」,点开没什么可做的。
现在:

  • 从你自己的收藏里随机挑一首(连续两次不重复),显示「为你推荐 / 歌名 / 艺人」
  • 就听这首 直接进播放队列(与搜索、歌单同一个播放入口)
  • 换一首 换下一首推荐
  • 收藏为空时如实提示「收藏里还没有歌,先去挑一首吧」,不假装推荐

网络客户端统一接管:AppHttp

「本机 IPv6 到外网完全不通」这个坑,我们手动补了六次 dns ——
ncm 取链 → 音频流 → B站 → 检查更新 → 应用内下载 → 封面/艺人/专辑图。
每次都是有人新建了一个裸 OkHttpClient.Builder()。

现在把默认值收进 network/AppHttp:

AppHttp.builder()   // 已带:IPv4 优先 DNS、连接 8s / 读 15s、retryOnConnectionFailure、共享连接池
  • 15 个文件 18 处 builder 全部改走它;主源码里裸 OkHttpClient.Builder() 绝迹
  • 补齐此前漏掉的客户端:Coil(封面/艺人头像/专辑图)、QqClient×2、QqQrClient、
    MqttWebSocketTransport、NeteaseRecognizeProvider、163cn.tv 短链 HEAD
  • 防回归:HttpClientDnsAuditTest 扫描源码,裸建即红;
    AddressPreference.ipv4First 改成具名类 IPv4FirstDns,测试可断言「默认客户端确实用了它」

校验

  • 全量 JVM 单测 3505 项 0 失败

Arris v3.8.15-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 17:01

v3.8.15-gpl(versionCode 135)

应用内下载:4 段并发

APK 16 MB,在裸连(手机 → Cloudflare,RTT 450–560ms、丢包 50–66%)上单连接要好几分钟。
服务端其实一直支持 Range(实测 8 段并发各返回精确 1 MB),只是客户端没用。

现在:

  1. 先 Range: bytes=0-0 探测,拿总长与 ETag;
  2. 4 段并发,每段独立 RandomAccessFile 写自己的区间(互不重叠);
  3. 收尾校验文件长度与 ETag(资产被替换就整体重来,不拼混合包)。

分流规则(什么时候不用多线程):服务端不支持 Range / 体积 ≤4 MB / 存在可续传残包 → 仍走原单流下载器;
任一段失败或用户取消 → 全体放弃并回落单流。快是加分项,下载成功是底线。

服务端改动

/api/releases 与 /api/latest 里的资产地址从 /dl/ 改为 /get/:

路径 行为
/dl/x.apk Cloudflare 静态直出,不认 Range(curl -r 返回整包)
/get/x.apk 走 Worker,自己实现 206 + Content-Range,支持续传与多线程

手机实测:HTTP/1.1 206,Content-Range: bytes 0-0/16069004,带 ETag。

一并修掉的

  • 一起听成员侧漂移窗口 5 秒(3.8.14)
  • 应用内下载补 IPv4 优先(3.8.13)
  • 检查更新单对象归一化 + 11KB 响应(3.8.12)

Arris v3.8.14-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 16:48

v3.8.14-gpl(versionCode 134)

一起听:不再「一同步就暂停」

成员侧的漂移容差原来是 800ms —— 网络抖动 + 房主时间戳误差就能超过它,
于是成员每隔一两份快照就被纠正一次,听感就是「一直在被同步打断、老是暂停」。

现在的分层:

偏差 行为
≤ 5s 完全不动(人耳在这个量级听不出差别)
5s – 12s 温和纠正:只把进度对到目标位置,不动播放/暂停态
≥ 12s 强制对齐:位置与播放态一起同步

另外播放/暂停态现在要求连续两次快照一致才跟随(TRANSPORT_CONFIRMATIONS=2),
房主瞬时缓冲不会再顺手把成员一起停掉。

顺带修掉的两处网络问题(3.8.12 / 3.8.13 的内容)

  • 检查更新:单对象响应归一化真正接上(此前一直判「解析失败」);
    更新客户端补 IPv4 优先;响应从 509KB 压到 11KB,源按体积从小到大取。
  • 应用内下载:下载客户端同样补 IPv4 优先 —— 修「第一次必失败、重试才成功」
    (本机 IPv6 到 Cloudflare 完全不通,IPv4 200 / IPv6 15s 超时,实测记录在仓库里)。

校验

  • 全量 JVM 单测 3503 项;唯一失败项是 QqLiveProbeTest 的实时探针(本机出口 IP 被限,返回 403/500)
  • 新增 DriftWindowTest 6 例钉住窗口边界(2s / 恰好 5s / 16s / 硬阈值 / 未起播 / 播放态)

Arris v3.8.13-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 16:07

v3.8.13-gpl(versionCode 133)

应用内下载:第一次必失败,第二次才连上

你报的现象 —— 第一次失败、重试成功 —— 是同一个根因的另一种表现:

真机实测(同一台手机、裸连):

请求 结果
curl -4 https://arris.de5.net/... HTTP 200,conn 0.39s
curl -6 同一地址 15 秒超时

UpdateDownloader 自建的 OkHttp 没有 AddressPreference:第一次下载把 20s 预算全花在死掉的
IPv6 地址上 → 失败;重试时系统已把那个地址标记为不可用,才轮到 IPv4 → 成功。

修:下载客户端补 AddressPreference.ipv4First + retryOnConnectionFailure,连接超时 20s → 10s。

顺带加诊断日志(下次直接看得到卡在哪):

I UpdateDownloader: start host=arris.de5.net resumeFrom=0
I UpdateDownloader: response code=200 len=16069004 elapsed=3211ms
I UpdateDownloader: failed after 10012ms: SocketTimeoutException timeout

一并包含(3.8.9–3.8.12)

  • 检查更新链路打通:单对象归一化、IPv4 优先、响应 509KB→11KB
  • 浏览器入口与下载地址都指向官网(site_url),GitHub 只作数据来源
  • B站音源:BiliApi 客户端硬化(IPv4 / h1 / 读超时)
  • 音频流走 OkHttp(读 10s、连接池可清)、回前台刷新、取链阶梯记忆

校验

真机裸连实测检查更新:evaluate=Found(version=3.8.12, assetUrl=https://arris.de5.net/dl/...),
3.1 秒完成。

Arris v3.8.12-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 15:59

v3.8.12-gpl(versionCode 132)

这一版把「检查更新」整条链路真正打通,顺带修掉 B站音源。

应用内检查更新(真机裸连实测通过)

联调测试:临时发过一版 3.8.12,手机(3.8.11、无代理)冷启动后日志:

update-source ok host=arris.de5.net pages=1 bytes=360 elapsed=3104ms
update: head=[{"tag_name":"v3.8.12-gpl",...}]
update: evaluate=Found(version=3.8.12, assetName=Arris-v3.8.12-gpl.apk, ...)

测完已把那一版删除,编号不留洞(正式就是本版 3.8.12)。

过程中修掉的真问题:

  1. 单对象归一化没接线 —— /api/latest 返回的是对象,normalizePage() 写了却没被调用,
    于是每次都判「解析失败」(日志里的 evaluate=null(解析失败) 就是它)。
  2. 更新客户端没有 IPv4 优先 —— 本机实测:IPv4 到 CF 是 200(0.39s 建连),
    IPv6 是 15 秒超时;系统把 IPv6 排前面,请求全耗在死地址上。
  3. 响应太大 —— /api/releases 509KB → 11KB;源按体积从小到大试:
    /api/latest(1.5KB) → /api/releases → jsDelivr 镜像 → 静态快照 → GitHub。
  4. 浏览器入口指向 GitHub —— 国内打不开。现在 Worker 给每条 release 附
    site_url = https://arris.de5.net/#download,应用优先用它,老载荷才回落 html_url。

B站音源失效

用你自己的 B 站 cookie 验过服务端整条链路都正常(search/view/playurl 全 code 0、
CDN 带 Referer 取流 206)。问题在 BiliApi 那条裸 OkHttp 客户端:
没有 IPv4 优先、自动协商 h2、30s 才超时。现已对齐 ncm:IPv4 优先、强制 HTTP/1.1、
连接 8s / 读 15s,并加 BiliApi.evictConnections()。

校验

  • 全量单测 3497 项;5 项 QqLiveProbeTest 是直连腾讯服务器的实时探针(本机出口 IP 被限,返回 500),与改动无关

Arris v3.8.9-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 09:14

v3.8.9-gpl(versionCode 129)

修:取链 0.7 秒,播放却卡十几秒才出声

真机日志:

NcrustHttpTiming: path=/eapi/.../player/url/v1  ttfb=264ms  total=411ms
SongUrlFetcher:   level=jymaster ok in 745ms
MediaSession:     state=BUFFERING(6) position=138024 buffered=138024 speed=0.0

URL 拿到了、播放器进了 BUFFERING,但音频一个字节都没下来。

根因在音频流的数据源:media3 默认的 DefaultHttpDataSource 底层是 HttpURLConnection——

  1. 不认我们的 DNS 策略(代理 fake-ip、坏的 IPv6 地址照样往上连);
  2. 没有读超时 —— 半死连接只能等系统 TCP 超时(分钟级);
  3. 连接池不归我们管 —— evictConnections() 清不到它,网络切换后旧连接继续被复用。

网络一变(开关代理 / 后台唤醒),音频流就挂在那条半死连接上。

改为 OkHttpDataSource:

项 值
DNS AddressPreference.ipv4First
连接超时 6s
读超时 10s(半死连接 10s 内报错,交给 ExoPlayer 换新连接)
连接保活 pingInterval(15s)
连接池 独立,网络变化 / 回前台时 MediaHttp.evict() 一并清

一并包含(3.8.5–3.8.8)

  • 检查更新修好(资产名规则过时,此前永远「已是最新」)+ 裸连可用的三级取数
  • 代理开关后未缓存的歌放不出来(清 JVM DNS 缓存)
  • 回前台 ≥10s 自动刷新(清池 + 预热当前曲目)
  • 首次取链提速(降级档位按账户记忆)

校验

  • 全量 JVM 单测 3497 项 0 失败
  • 16 KB page 合规(p_align=0x4000、.so 未压缩、zipalign -P 16 通过)

Arris v3.8.6-gpl

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 01 Nov 09:03

回前台就刷新:离开 ≥10s 回来清连接池 + DNS 并预热当前曲目;修好应用内检查更新;修代理开关后未缓存的歌放不出来。

LTS 3.7.x · 长期维护线(滚动更新)

Choose a tag to compare

@yaxiaiyuting yaxiaiyuting released this 31 Oct 13:36

LTS 3.7.x · 长期维护线(滚动更新)

这条 Release 不是某个具体版本,而是 LTS 线的固定入口:每次 LTS 出包都会替换下面这些附件,
版本号看附件文件名。本页不会被标记为 Latest,也不会顶掉主线的「最新版」徽章。

当前 LTS 版本:v3.7.15-gpl(versionCode 102)

项 值
最低系统 Android 7.0(minSdk 24) —— 想装 3.8.x 需要 Android 10+
附件 Arris-v3.7.15-gpl.apk(≈ 12 MB)
官网直链 https://arris.de5.net/get/lts-latest.apk(支持断点续传/多线程,永远指向最新 LTS)
旧版 v3.7.14-gpl、v3.7.13-gpl 仍在 Releases 里,可回退

本版(3.7.15)回移的内容

  • 开关代理后未缓存的歌放不出来:代理的 fake-ip(198.18.0.0/15)与真实 IP 是两套解析结果,
    而 JVM 的 DNS 缓存不随网络切换失效 —— 关掉代理后取链仍往假地址上连。
    新增 DnsCache(反射清缓存)并在网络切换与取链重试两处调用。
  • 检查更新不再依赖 GitHub:首选 https://arris.de5.net/api/releases,
    GitHub 原接口仅作兜底;api.github.com 在国内经常裸连失败。
  • 按发布通道过滤:3.7.x 只看到 3.7.x 与 lts-3.7,不会被推 minSdk 29 的 3.8.x。

LTS 线的取舍

LTS 只回移「设备兼容 / 正确性」修复,不带新功能:

  • ✅ 会回移:竖屏封面遮挡、自动旋转默认值、地址族回退、主线程 socket 崩溃、DNS 缓存、视觉统一
  • ❌ 不回移:听歌识曲、一起听(依赖 3.8 的协议与后端,且在 Android 7 设备上没有验证过)

校验

  • 全量 JVM 单测 3399 项 0 失败
  • 与 3.8.x 同一证书(CN=Ncrust, OU=Dev, O=Ncrust),可直接覆盖安装