From afd92289f272428fd4bf978b83b18c3545a69d9c Mon Sep 17 00:00:00 2001 From: no_gen_mu Date: Tue, 30 Jun 2026 17:22:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=98=E7=BD=91=E4=B8=8B=E8=BD=BD=20APK=20?= =?UTF-8?q?=E7=9B=B4=E9=93=BE:=E5=BC=BA=E5=88=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=A4=B4=20+=20=E5=8F=91=E5=B8=83=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 落地页「官网下载」指向 /media/shaguabijia.apk,但该文件靠手动 cp、且 StaticFiles 给 .apk 的 Content-Type 不对又无 attachment 头,部分国产浏览器不触发下载转甩应用市场。新增 download_apk 路由(挂在静态目录之前),显式回 application/vnd.android.package-archive + Content-Disposition:attachment 强制下载,文件缺失回 404。新增 scripts/publish_apk.sh 把「编 release 包 + 放到 data/media/shaguabijia.apk」固化成一条命令。 Co-Authored-By: Claude Opus 4.8 --- app/main.py | 45 ++++++++++++++++++++++++++++++++---------- scripts/publish_apk.sh | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 scripts/publish_apk.sh diff --git a/app/main.py b/app/main.py index 7b5e376..6aded37 100644 --- a/app/main.py +++ b/app/main.py @@ -2,18 +2,23 @@ 通过 `uvicorn app.main:app --reload` 启动。 """ + from __future__ import annotations import logging from collections.abc import AsyncIterator from contextlib import asynccontextmanager - from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles +from app.api.internal.app_version import router as internal_app_version_router +from app.api.internal.launch_confirm import router as internal_launch_confirm_router +from app.api.internal.price import router as internal_price_router +from app.api.internal.store import router as internal_store_router from app.api.v1.ad import router as ad_router from app.api.v1.analytics import router as analytics_router from app.api.v1.auth import router as auth_router @@ -21,12 +26,8 @@ from app.api.v1.compare import router as compare_router from app.api.v1.compare_milestone import router as compare_milestone_router from app.api.v1.compare_record import router as compare_record_router from app.api.v1.coupon import router as coupon_router -from app.api.v1.device import router as device_router from app.api.v1.cps_redirect import router as cps_redirect_router -from app.api.internal.app_version import router as internal_app_version_router -from app.api.internal.launch_confirm import router as internal_launch_confirm_router -from app.api.internal.price import router as internal_price_router -from app.api.internal.store import router as internal_store_router +from app.api.v1.device import router as device_router from app.api.v1.feedback import router as feedback_router from app.api.v1.invite import router as invite_router from app.api.v1.meituan import router as meituan_router @@ -40,14 +41,14 @@ from app.api.v1.user import router as user_router from app.api.v1.wallet import router as wallet_router from app.api.v1.wxpay import router as wxpay_router from app.core.config import settings -from app.core.heartbeat_monitor_worker import ( - start_heartbeat_monitor, - stop_heartbeat_monitor, -) from app.core.daily_exchange_worker import ( start_daily_exchange_worker, stop_daily_exchange_worker, ) +from app.core.heartbeat_monitor_worker import ( + start_heartbeat_monitor, + stop_heartbeat_monitor, +) from app.core.logging import setup_logging from app.core.pricebot_client import aclose_pricebot_client, get_pricebot_client from app.core.withdraw_reconcile_worker import ( @@ -137,6 +138,30 @@ app.include_router(cps_redirect_router) # 用户上传文件(头像)静态服务。生产可改由 nginx 直接 serve MEDIA_ROOT。 _media_root = Path(settings.MEDIA_ROOT) _media_root.mkdir(parents=True, exist_ok=True) + + +# 官网下载的 APK 直链(落地页 dl.html「官网下载」按钮指向 /media/shaguabijia.apk)。 +# 必须在 StaticFiles 挂载【之前】注册,否则被静态挂载吃掉。 +# StaticFiles 给 .apk 的 Content-Type 不对、且无 attachment 头 → 部分国产浏览器不触发下载、转甩应用市场; +# 这里显式回 application/vnd.android.package-archive + Content-Disposition:attachment 强制浏览器下载。 +# 文件由 scripts/publish_apk.sh 编 release 包后放到 data/media/shaguabijia.apk(*.apk 不入 git,需部署时放)。 +_APK_PATH = _media_root / "shaguabijia.apk" + + +@app.get(f"{settings.MEDIA_URL_PREFIX}/shaguabijia.apk", tags=["meta"], include_in_schema=False) +def download_apk() -> FileResponse: + if not _APK_PATH.is_file(): + from fastapi import HTTPException + + raise HTTPException(status_code=404, detail="安装包未就绪") + return FileResponse( + _APK_PATH, + media_type="application/vnd.android.package-archive", + filename="shaguabijia.apk", + headers={"Content-Disposition": 'attachment; filename="shaguabijia.apk"'}, + ) + + app.mount( settings.MEDIA_URL_PREFIX, StaticFiles(directory=str(_media_root)), diff --git a/scripts/publish_apk.sh b/scripts/publish_apk.sh new file mode 100644 index 0000000..3cc5c96 --- /dev/null +++ b/scripts/publish_apk.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# 编 release 正式包并发布到官网下载位 data/media/shaguabijia.apk。 +# +# 背景:落地页 dl.html「官网下载」按钮指向 /media/shaguabijia.apk(见 app/main.py download_apk 路由)。 +# 该 apk 不入 git(.gitignore 忽略 *.apk),也没有 CI 自动放 —— 以前全靠手动 cp,常忘/放成 debug 包。 +# 本脚本把"编 release + 放到位"固化成一条命令。发版时跑一次即可。 +# +# 用法: bash scripts/publish_apk.sh +# 产物: /data/media/shaguabijia.apk(release 签名、指向生产后端的正式包) +# +# 注意:① 需要 app/jishisongfu-release.jks 存在(release 签名,仅 CTO 持有);缺失会编译失败。 +# ② 服务器部署不在本脚本职责内 —— 它只把 apk 放到本仓 data/media/;上线由部署流程把 +# data/media/ 同步到生产(或 nginx serve 同目录)。 +set -euo pipefail + +# 路径全部相对脚本位置算,跟 CWD 无关。 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVER_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +ANDROID_DIR="$(cd "$SERVER_DIR/../shaguabijia-app-android" && pwd)" +DEST="$SERVER_DIR/data/media/shaguabijia.apk" +APK_OUT="$ANDROID_DIR/app/build/outputs/apk/release/app-release.apk" + +# Android Studio 自带 JBR(本机构建环境约定)。已设 JAVA_HOME 则尊重现有值。 +export JAVA_HOME="${JAVA_HOME:-D:/android-studio/jbr}" + +echo "[publish_apk] Android 工程: $ANDROID_DIR" +if [ ! -f "$ANDROID_DIR/app/jishisongfu-release.jks" ]; then + echo "[publish_apk] ✗ 缺 app/jishisongfu-release.jks(release 签名),无法出正式包。" >&2 + exit 1 +fi + +echo "[publish_apk] 编 release 包(assembleRelease,R8+release 签名,BASE_URL=生产)…" +( cd "$ANDROID_DIR" && ./gradlew :app:assembleRelease ) + +if [ ! -f "$APK_OUT" ]; then + echo "[publish_apk] ✗ 没找到产物 $APK_OUT" >&2 + exit 1 +fi + +mkdir -p "$(dirname "$DEST")" +cp "$APK_OUT" "$DEST" +SIZE_MB=$(( $(wc -c < "$DEST") / 1024 / 1024 )) +echo "[publish_apk] ✓ 已发布 → $DEST (${SIZE_MB}MB)" +echo "[publish_apk] 官网下载链接(生产):https://app-api.shaguabijia.com/media/shaguabijia.apk" +echo "[publish_apk] 部署:把 data/media/ 同步到生产服务器(本脚本不负责上线)。"