补充说明
本方案基于 fnOS(Debian 体系) 部署 Shell 监控脚本,实现小米电视上电开机后自动启动指定 TV APP(以飞牛影视 com.trim.tv 为例),全程后台常驻运行、崩溃自动重启、支持开机自启、断电后自动重置状态。
本教程涵盖:方案原理与核心功能、环境依赖安装、APK 包名与启动 Activity 获取、监控脚本部署、Systemd 服务配置、运维与卸载等完整内容。
工作原理
监控脚本常驻运行,通过小米电视局域网控制接口完成目标 APP 的拉起:
电视上电开机
│
▼
恢复网络、可被 ping 通 ← 监控脚本每 5 秒探测一次
│
▼
检测到"上线" → 调用电视 HTTP 接口启动指定 APP
│
▼
接口返回 success → 锁定本次开机,不再重复请求
│
▼
电视断电 / 离线 → 自动重置状态,等待下次开机
核心功能
- 每 5 秒 ping 检测电视在线状态
- 电视离线 → 自动重置启动状态,等待下次开机
- 电视上线瞬间调用电视接口启动目标 APP
- APP 启动成功后,本次开机不再重复请求
- systemd 托管,常驻守护、开机自启、完整日志记录
实例
一、前期踩坑总结(关键避坑)
-
Windows 编辑脚本换行符报错
Windows 保存脚本为 CRLF 换行,Linux 识别异常,报
$'\r': command not found。修复命令:
sed -i 's/\r$//' 脚本路径 -
CIFS 共享卷无法执行脚本 status=203/EXEC
/vol1/1000、/vol2/1000属于 SMB/CIFS 挂载目录,不支持 Linux 可执行权限位,chmod +x无效,systemd 直接权限拒绝。解决方案:脚本放置系统本地目录
/opt/scripts/,避开 NAS 共享存储。 -
fnOS 环境 APK 信息查看踩坑
- Debian 官方源没有 aapt2
- GitHub 外部 jar 下载经常 404
- fnOS 默认未安装 Java,apktool / AXMLPrinter2 无法运行
最优方案:使用
androguard(Python 实现,无需 Java,apt 直接安装)。
二、环境依赖安装
# 脚本依赖 ping curl
apt install iputils-ping curl -y
# APK 解析工具,无需 Java
apt install androguard -y
三、APK 包名 / 启动 Activity 快速查看(fnOS 专用)
不要使用
apktool d xxx.apk完整反编译,解压全部资源速度慢、产生大量临时文件。
获取包名、版本号
androguard apkid FNTV_1.3.4_0408121705.apk
输出示例:
{
"FNTV_1.3.4_0408121705.apk": [
"com.trim.tv",
"13404",
"1.3.4"
]
}
字段说明:[包名, versionCode, versionName]
当前 FNTV APK 关键信息
- 包名:
com.trim.tv - Leanback TV 主 Activity:
com.trim.tv.modules.splash.SplashActivity
不同版本 SplashActivity 可能变化,可重新用 androguard 核对后再使用 ADB/am 命令。
一键提取包名(可嵌入脚本)
androguard apkid FNTV_1.3.4_0408121705.apk | python3 -c "import json,sys;print(list(json.load(sys.stdin).values())[0][0])"
若你的 androguard 输出为单引号格式(旧版本),json 解析会报错,改用:
androguard apkid FNTV_1.3.4_0408121705.apk | python3 -c "import sys,ast;print(list(ast.literal_eval(sys.stdin.read()).values())[0][0])"
通过 ADB 启动(电视端需开启开发者选项 ADB 调试)
adb connect 10.10.10.14
adb shell am start -n com.trim.tv/.modules.splash.SplashActivity
四、手动验证电视接口(推荐先测)
部署监控脚本前,先手动调用一次接口,确认电视在线且接口可用:
curl --silent --show-error --max-time 5 "http://10.10.10.14:6095/controller?action=startapp&&type=packagename&packagename=com.trim.tv"
- 返回内容包含
success表示启动成功 - 连接被拒绝,说明电视未开机或 6095 端口未监听(部分电视需在系统设置中开启"局域网控制/快速启动")
URL 中的双
&&是小米电视控制协议的特殊写法,请勿删减为单个。
五、部署监控脚本
1. 创建本地脚本目录
mkdir -p /opt/scripts
2. 写入完整监控脚本
cat > /opt/scripts/monitor.sh <<'EOF'
#!/bin/sh
# ============================================================
# Xiaomi TV Auto Start APP
# fnOS / Linux 常驻监控脚本
# ============================================================
# 配置区(可自行修改)
# ============================================================
TV_IP="10.10.10.14"
APP_PACKAGE="com.trim.tv"
CHECK_INTERVAL=5
TV_PORT=6095
START_APP_URL="http://${TV_IP}:${TV_PORT}/controller?action=startapp&&type=packagename&packagename=${APP_PACKAGE}"
# ============================================================
# 状态变量
# ============================================================
TV_ONLINE=0
APP_STARTED=0
# ============================================================
# 启动日志输出
# ============================================================
echo "========================================================"
echo " Xiaomi TV Auto Start APP"
echo "========================================================"
echo
echo "TV IP : ${TV_IP}"
echo "APP Package : ${APP_PACKAGE}"
echo "Check : ${CHECK_INTERVAL} 秒"
echo "URL : ${START_APP_URL}"
echo
echo "========================================================"
echo "开始监控..."
echo "按 Ctrl+C 停止。"
echo "========================================================"
echo
# ============================================================
# 依赖检测
# ============================================================
if ! command -v ping >/dev/null 2>&1; then
echo "错误:系统中没有 ping 命令。"
exit 1
fi
if ! command -v curl >/dev/null 2>&1; then
echo "错误:系统中没有 curl 命令。"
exit 1
fi
# ============================================================
# APP 启动函数
# ============================================================
start_app()
{
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 正在尝试启动 APP..."
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 包名: ${APP_PACKAGE}"
RESPONSE=$(curl \
--silent \
--show-error \
--max-time 5 \
"${START_APP_URL}" 2>/dev/null)
CURL_RESULT=$?
if [ ${CURL_RESULT} -ne 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 请求失败。5秒后重试。"
return 1
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 请求发送成功。"
echo "${RESPONSE}" | grep -qi "success"
if [ $? -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] APP 启动成功,本次开机不再重复启动。"
APP_STARTED=1
return 0
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] APP 未启动成功,返回内容: ${RESPONSE}"
return 1
fi
}
# ============================================================
# 主循环常驻监控
# ============================================================
while true
do
ping -c 1 -W 1 "${TV_IP}" >/dev/null 2>&1
if [ $? -ne 0 ]; then
if [ "${TV_ONLINE}" -eq 1 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 电视离线,重置启动状态。"
TV_ONLINE=0
APP_STARTED=0
fi
sleep ${CHECK_INTERVAL}
continue
fi
if [ "${TV_ONLINE}" -eq 0 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 检测到电视上线。"
TV_ONLINE=1
fi
if [ "${APP_STARTED}" -eq 0 ]; then
start_app
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 电视在线,APP 已启动。"
fi
sleep ${CHECK_INTERVAL}
done
EOF
3. 授权 + 清洗换行符
chmod +x /opt/scripts/monitor.sh
sed -i 's/\r$//' /opt/scripts/monitor.sh
启动成功后返回内容若不含
success关键字,可根据实际返回格式调整脚本中的grep -qi "success"匹配词。
六、配置 Systemd 开机自启服务
1. 创建服务配置文件
cat > /etc/systemd/system/monitor.service <<'EOF'
[Unit]
Description=Xiaomi TV AutoStart Monitor Service
After=network.target
[Service]
Type=simple
User=root
ExecStart=/opt/scripts/monitor.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
2. 生效服务、开启开机自启、启动运行
systemctl daemon-reload
systemctl enable monitor.service
systemctl start monitor.service
若开启
Restart=always,即使正常退出也会不断重启;on-failure仅在异常退出时重启,适合本脚本的exit 1依赖检测场景。
七、状态查看与运维命令
| 功能 | 命令 |
|---|---|
| 查看服务运行状态 | systemctl status monitor.service |
| 实时跟踪日志 | journalctl -u monitor.service -f |
| 查看最近 100 行日志 | journalctl -u monitor.service -n 100 |
| 修改脚本后重启服务 | systemctl restart monitor.service |
| 停止服务 | systemctl stop monitor.service |
| 取消开机自启 | systemctl disable monitor.service |
正常运行标识:
active (running)。
八、修改配置方法
修改电视 IP、包名、检测间隔:
nano /opt/scripts/monitor.sh
保存退出后必须重启服务生效:
systemctl restart monitor.service
九、部署成功判定标准
- systemd 服务状态:
active (running) - 无 203/EXEC 权限报错、无换行符语法报错
- 电视上线可识别并成功启动目标 APP
- fnOS 整机重启后服务自动运行
十、最终运行效果
- fnOS 开机自动后台拉起监控进程,无需手动干预
- 电视未开机:持续识别离线
- 电视上电上线:自动调用 API 启动目标 APP
- 启动成功锁定状态,不会重复调用接口
- 电视断电重启,状态自动重置,下次上电重新拉起 APP
- 脚本异常崩溃,systemd 5 秒自动重启进程
十一、卸载完整一键脚本
#!/bin/bash
systemctl stop monitor.service 2>/dev/null
systemctl disable monitor.service 2>/dev/null
rm -f /etc/systemd/system/monitor.service
systemctl daemon-reload
rm -f /opt/scripts/monitor.sh
rmdir /opt/scripts 2>/dev/null
echo "✅ monitor.service 已经彻底卸载完成"
十二、查看状态
monitor_status_show() {
gl_hui='\033[38;5;59m'
gl_hong='\033[38;5;9m'
gl_lv='\033[38;5;10m'
gl_huang='\033[38;5;11m'
gl_lan='\033[38;5;32m'
gl_bai='\033[38;5;15m'
gl_zi='\033[38;5;13m'
gl_bufan='\033[38;5;14m'
log_info() { echo -e "${gl_lan}[信息]${gl_bai} $*${gl_bai}"; }
log_ok() { echo -e "${gl_lv}[成功]${gl_bai} $*${gl_bai}"; }
log_warn() { echo -e "${gl_huang}[警告]${gl_bai} $*${gl_bai}" >&2; }
log_error() { echo -e "${gl_hong}[错误]${gl_bai} $*${gl_bai}" >&2; }
local SERVICE="monitor.service"
local STATUS
STATUS=$(systemctl status "$SERVICE" --no-pager --lines=5 2>/dev/null)
if [ $? -ne 0 ]; then
log_error "服务 ${SERVICE} 不存在或未安装"
return 1
fi
local ACTIVE=$(echo "$STATUS" | awk '/Active:/ {print $2}')
local STATE
if [[ "$ACTIVE" == "active" ]]; then
STATE="${gl_lv}运行中 ✅${gl_bai}"
else
STATE="${gl_hong}已停止 ❌${gl_bai}"
fi
local PID=$(echo "$STATUS" | awk '/Main PID:/ {print $3}')
local MEM=$(echo "$STATUS" | awk '/Memory:/ {print $2}')
local CPU=$(echo "$STATUS" | awk '/CPU:/ {print $2}')
local LAST_LOG
LAST_LOG=$(echo "$STATUS" | grep -E "^[[:space:]]*[A-Za-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}" | tail -1 | sed 's/^[[:space:]]*//' | cut -d' ' -f4-)
[[ -z "${LAST_LOG:-}" ]] && LAST_LOG="暂无日志输出"
local TV_STATUS
if echo "$LAST_LOG" | grep -q "电视上线\|检测到电视上线"; then
TV_STATUS="${gl_lv}电视已上线 📺${gl_bai}"
elif echo "$LAST_LOG" | grep -q "电视离线"; then
TV_STATUS="${gl_huang}电视离线 💤${gl_bai}"
elif echo "$LAST_LOG" | grep -q "启动成功"; then
TV_STATUS="${gl_lv}APP 已启动 🚀${gl_bai}"
elif echo "$LAST_LOG" | grep -q "启动失败\|请求失败"; then
TV_STATUS="${gl_hong}启动失败 ❌${gl_bai}"
else
TV_STATUS="${gl_hui}未知状态${gl_bai}"
fi
echo ""
echo -e "${gl_zi}>>> 电视自动启动监控服务状态${gl_bai}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
echo -e "${gl_bai}服务状态 : $STATE"
echo -e "${gl_bai}主进程 PID: ${PID:-—}"
echo -e "${gl_bai}内存占用 : ${MEM:-—}"
echo -e "${gl_bai}CPU 耗时 : ${CPU:-—}"
echo -e "${gl_bai}电视状态 : $TV_STATUS"
echo -e "${gl_bai}最近活动 : ${LAST_LOG}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
break_end
}
monitor_status_show
相关命令
systemd:Linux 系统与用户管理器,服务开机自启的基础systemctl:Systemd 服务控制命令(enable / start / status 等)ping:网络连通性探测,脚本在线状态检测的基础adb:Android 调试桥,可替代/补充电视端应用调试apk:APK 工具集,结合androguard解析包名与 Activitynohup:无需 systemd 时的常驻进程替代方案ubuntu-install-fntv:飞牛影视(FNMedia)桌面版安装