随机
Enter 搜索 ↑↓ 切换 Esc 清空

xiaomi-tv

命令

fnOS 部署电视开机自动启动指定 APP

补充说明

本方案基于 fnOS(Debian 体系) 部署 Shell 监控脚本,实现小米电视上电开机后自动启动指定 TV APP(以飞牛影视 com.trim.tv 为例),全程后台常驻运行、崩溃自动重启、支持开机自启、断电后自动重置状态。

本教程涵盖:方案原理与核心功能、环境依赖安装、APK 包名与启动 Activity 获取、监控脚本部署、Systemd 服务配置、运维与卸载等完整内容。

工作原理

监控脚本常驻运行,通过小米电视局域网控制接口完成目标 APP 的拉起:

电视上电开机
   │
   ▼
恢复网络、可被 ping 通      ← 监控脚本每 5 秒探测一次
   │
   ▼
检测到"上线" → 调用电视 HTTP 接口启动指定 APP
   │
   ▼
接口返回 success → 锁定本次开机,不再重复请求
   │
   ▼
电视断电 / 离线 → 自动重置状态,等待下次开机

核心功能

实例

一、前期踩坑总结(关键避坑)

  1. Windows 编辑脚本换行符报错

    Windows 保存脚本为 CRLF 换行,Linux 识别异常,报 $'\r': command not found。

    修复命令:sed -i 's/\r$//' 脚本路径

  2. CIFS 共享卷无法执行脚本 status=203/EXEC

    /vol1/1000、/vol2/1000 属于 SMB/CIFS 挂载目录,不支持 Linux 可执行权限位,chmod +x 无效,systemd 直接权限拒绝。

    解决方案:脚本放置系统本地目录 /opt/scripts/,避开 NAS 共享存储。

  3. 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 关键信息

不同版本 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"

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

九、部署成功判定标准

十、最终运行效果

  1. fnOS 开机自动后台拉起监控进程,无需手动干预
  2. 电视未开机:持续识别离线
  3. 电视上电上线:自动调用 API 启动目标 APP
  4. 启动成功锁定状态,不会重复调用接口
  5. 电视断电重启,状态自动重置,下次上电重新拉起 APP
  6. 脚本异常崩溃,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

相关命令