const apkUrl = "https://down.pics/down/shizuku.zip";
const savePath = "/sdcard/Download/shizuku.zip";
if (!files.exists(savePath)) {
log("📥 开始下载 Shizuku");
//showStatus("📥 开始下载 Shizuku",2);
let res = http.get(apkUrl);
files.writeBytes(savePath, res.body.bytes());
log("✅ 下载完成");
//showStatus("✅ 下载完成",2);
} else {
log("✅ 使用本地安装包");
} 这个下载代码为什么会出错

测试脚本 · 8 小时前
第 1 条补充
·
8 小时前

发生错误:JavaException: okhttp3.internal.http2.ConnectionShutdownException: null
出现这个错误,什么原因?

回答

Hamibot AI
1
· 8 小时前

这段代码在 Hamibot 环境中运行出错,通常由以下几个核心原因导致:

  1. 存储权限未授予:这是最常见的原因。Android 系统要求应用访问外部存储(如 /sdcard/Download/)时必须获得“存储权限”。如果未在系统设置或 Hamibot 授权弹窗中允许,files.writeBytes 会抛出异常。
  2. 缺乏异常处理:代码没有使用 try-catch 包裹网络请求和文件写入操作。一旦网络波动、DNS 解析失败或磁盘空间不足,脚本会直接中断且无法定位具体错误。
  3. 未校验 HTTP 状态码http.get 建立连接成功不代表资源获取成功。如果服务器返回 404 或 500,res.body.bytes() 可能获取到错误的数据包,导致文件损坏。
  4. 父目录不存在风险:虽然 files.writeBytes 通常会自动创建缺失的父目录,但在某些 Android 版本或特定路径下,如果父目录不可写,写入仍会失败。

以下是优化后的代码示例,增加了权限检查提示、异常捕获和状态码验证:

// 文档地址 https://docs.hamibot.com/
try {
    const apkUrl = "https://down.pics/down/shizuku.zip";
    const savePath = "/sdcard/Download/shizuku.zip";

    // 检查文件是否已存在
    if (!files.exists(savePath)) {
        log("📥 开始下载 Shizuku");
        
        // 发起网络请求
        let res = http.get(apkUrl);
        
        // 检查响应状态码是否为 200
        if (res.statusCode !== 200) {
            throw new Error("下载失败,服务器返回状态码:" + res.statusCode);
        }

        // 写入二进制文件
        files.writeBytes(savePath, res.body.bytes());
        
        log("✅ 下载完成");
    } else {
        log("✅ 使用本地安装包");
    }
} catch (e) {
    // 捕获并打印错误信息,方便调试
    log("❌ 发生错误:" + e);
    toast("下载出错,请检查网络和权限");
}

关键改进说明:

  • 增加 try-catch:捕获网络超时、IO 异常等运行时错误,防止脚本崩溃且能输出具体报错信息。
  • 校验 statusCode:确保只有当服务器返回 200 OK 时才进行文件写入,避免下载错误页面。
  • 权限提醒:如果运行时报错 Permission denied,请前往手机设置 -> 应用管理 -> Hamibot -> 权限,开启“存储”或“文件和媒体”权限。
  • 兼容性:代码遵循 Rhino 引擎规范,未使用箭头函数或默认参数,确保在 Hamibot 云端或本地环境稳定运行。

如果问题依旧,建议尝试将保存路径改为 files.cwd() + '/shizuku.zip' 测试是否为特定目录权限问题。

ℹ️ 内容由 AI 生成,可能不准确,请注意核实
Hamibot AI
1
· 8 小时前

这个错误 JavaException: okhttp3.internal.http2.ConnectionShutdownException: null 表明底层网络库 OkHttp 的 HTTP/2 连接被意外中断了。这通常不是代码逻辑错误,而是网络环境或服务器交互层面的问题。

常见原因:

  1. 网络不稳定:手机在网络切换(如 Wi-Fi 切到移动数据)或信号弱时,TCP 连接可能重置,导致正在进行的 HTTP/2 流中断。
  2. 服务器主动断开:目标服务器可能因为超时、负载过高或安全策略,主动关闭了长连接。
  3. HTTP/2 协议兼容性问题:部分老旧服务器或特定配置对 HTTP/2 支持不佳,容易在传输过程中断开。
  4. 中间设备干扰:某些路由器、防火墙或杀毒软件可能会拦截并切断长时间空闲的连接。

解决方案:

  1. 增加重试机制:这是最有效的办法。将网络请求包裹在循环中,遇到此类异常时自动重试几次。
  2. 检查网络连接:确保设备网络通畅,尝试切换 Wi-Fi 或流量测试。
  3. 缩短超时时间:如果请求耗时过长,更容易触发连接断开,尽量优化请求效率。
  4. 避免大文件直接下载:如果是下载大文件,考虑分块下载或使用更稳定的 CDN 链接。

以下是增加了重试逻辑的优化代码,能够自动处理临时的网络中断:

// 文档地址 https://docs.hamibot.com/
function downloadFileWithRetry(url, savePath, maxRetries) {
    var retries = 0;
    while (retries < maxRetries) {
        try {
            log("📥 开始下载,尝试次数:" + (retries + 1));
            var res = http.get(url);
            
            if (res.statusCode !== 200) {
                throw new Error("状态码异常:" + res.statusCode);
            }
            
            files.writeBytes(savePath, res.body.bytes());
            log("✅ 下载成功");
            return true;
        } catch (e) {
            retries++;
            log("⚠️ 下载失败:" + e);
            if (retries >= maxRetries) {
                log("❌ 已达到最大重试次数,放弃下载");
                return false;
            }
            log("⏳ 等待 3 秒后重试...");
            sleep(3000);
        }
    }
}

// 调用示例
var apkUrl = "https://down.pics/down/shizuku.zip";
var savePath = "/sdcard/Download/shizuku.zip";

if (!files.exists(savePath)) {
    var success = downloadFileWithRetry(apkUrl, savePath, 3);
    if (!success) {
        toast("下载失败,请检查网络");
    }
} else {
    log("✅ 使用本地安装包");
}

代码改进点:

  • 封装重试函数:将下载逻辑封装为 downloadFileWithRetry,便于复用和管理重试次数。
  • 异常捕获与循环:使用 while 循环配合 try-catch,捕获 ConnectionShutdownException 等网络异常并自动重试。
  • 延时等待:在重试前加入 sleep(3000),避免频繁请求导致被封禁或加重网络负担。
  • 变量声明:使用 var 声明变量,确保在 Rhino 1.7.15 引擎下的最大兼容性。

如果多次重试后仍然报错,建议检查该下载链接在手机浏览器中是否能正常打开,以排除服务器端问题。

ℹ️ 内容由 AI 生成,可能不准确,请注意核实