#!/bin/bash # K线训练 · macOS 一键安装 # # /bin/bash -c "$(curl -fsSL https://static.yyqyx.com/kline-trainer/download/install-macos.sh)" # # ⚠️ 脚本与它拉的 zip 都在 COS(`static.yyqyx.com/kline-trainer/download/`, # 由 tool/release.dart 的 `--upload` 一次传上去)。旧的 # `www.yyqyx.com/kt/download/` 与 `www.dabolang.net/download/` 是 101 上 # 那份,作为回退保留 —— 但**这个脚本里的 BASE 只能有一个**:写成旧域名时, # 包传到 COS 也没人从 COS 下,而页面上一切正常(唯一症状是 COS 没有下载量)。 # # ⚠️ 为什么是「跑一条命令」而不是「下个 zip 双击」: # # 这个包是 **adhoc 签名**(没有 Apple 开发者账号,无法签名+公证)。 # 而 adhoc + quarantine = AMFI **硬拒** —— 只要包经过任何会打 # quarantine 的通道(浏览器 / 微信 / QQ / AirDrop),到用户机器上就是 # **双击闪退**,而且不给任何提示,看着像「这软件坏了」。 # # curl 落地的文件**不带 quarantine**(实测:浏览器下载 156 字节的 # com.apple.quarantine 属性,curl 是 0)。所以这条路能走通。 # # ⚠️ 用 ditto 而不是 unzip:ditto 保留符号链接、扩展属性与签名, # 普通 unzip 会破坏 .app 的结构,双击直接报「已损坏」。 set -euo pipefail BASE="${KT_BASE:-https://static.yyqyx.com/kline-trainer/download}" INSTALL_DIR="${KT_INSTALL_DIR:-/Applications}" APP_NAME="kline_trainer.app" ZIP_URL="$BASE/KLineTrainer-macos.zip" WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT echo "→ 下载 K线训练…" curl -fSL --progress-bar -o "$WORK/app.zip" "$ZIP_URL" # ⚠️ 先在临时目录展开并检查完整性,**再**动 /Applications。 # 直接往 /Applications 解压的话,下到一半的包会覆盖掉好的那份, # 而「半个包」的症状(启动即 SIGKILL)跟 quarantine 几乎分不出来。 echo "→ 校验…" ditto -x -k "$WORK/app.zip" "$WORK/unpacked" STAGED="$WORK/unpacked/$APP_NAME" [ -d "$STAGED" ] || { echo "✗ 包里没有 ${APP_NAME},安装中止"; exit 1; } [ -x "$STAGED/Contents/MacOS/kline_trainer" ] || { echo "✗ 可执行文件缺失或不完整,安装中止"; exit 1; } echo "→ 安装到 ${INSTALL_DIR}…" # 旧版本先挪走再放新的:直接覆盖会留下上一版的残余文件 if [ -d "$INSTALL_DIR/$APP_NAME" ]; then rm -rf "$INSTALL_DIR/$APP_NAME.old" 2>/dev/null || true mv "$INSTALL_DIR/$APP_NAME" "$INSTALL_DIR/$APP_NAME.old" fi ditto "$STAGED" "$INSTALL_DIR/$APP_NAME" rm -rf "$INSTALL_DIR/$APP_NAME.old" 2>/dev/null || true # curl 落地的本来就没有 quarantine;这一句是防「这个脚本自己被下载过」 # 之类的间接传播。⚠️ quarantine 记在**这一份拷贝**上,不是记在版本上 —— # 换台机器、换个传输方式就又有了。 xattr -dr com.apple.quarantine "$INSTALL_DIR/$APP_NAME" 2>/dev/null || true echo "✓ 装好了:$INSTALL_DIR/$APP_NAME" echo " 正在启动…" open "$INSTALL_DIR/$APP_NAME"