25、Android TV OTA实践:电视设备升级特点、后台静默升级、用户交互设计

电视OTA升级,跟手机还真不太一样。

我最早做TV OTA时,心想不就是个Recovery升级嘛,能有多大区别?结果第一次在客户那边演示,升级到一半用户把电源拔了——电视嘛,很多人觉得跟关显示器一样,随手就断电。那次之后我才意识到,TV的升级场景,远比手机复杂。

说白了,电视是一个“全家共用”的设备。它不像手机那样属于个人,用户对升级的容忍度也低得多。你想想看,一家人正看着剧,突然弹个升级提示,谁受得了?

25.1 电视设备升级的独特挑战

电视和手机虽然都是Android设备,但升级场景差异很大。我归纳了几个核心区别:

  • 使用场景不同:电视是“被动观看”设备,用户不希望被打断。手机升级可以放一边,电视升级意味着全家都不能看。
  • 交互能力弱:电视没有触摸屏,全靠遥控器。输入文字、确认弹窗都很麻烦。
  • 网络环境复杂:很多电视用Wi-Fi,信号不稳定。有些甚至是用有线电视的同轴电缆上网,带宽有限。
  • 电源不可控:手机有电池,升级中断大不了重启。电视一旦断电,可能直接变砖。
  • 后台运行时间长:电视通常不关机,只是待机。这给后台静默升级提供了机会,但也带来了新问题。

核心观点:TV OTA设计的首要原则是——不要打扰用户。如果升级影响了用户正常观看,那这个设计就是失败的。

25.2 后台静默升级的实现方案

后台静默升级,说白了就是让电视在用户不知道的情况下完成升级。我参与过的项目中,主要有两种方案:

方案一:Idle模式下后台下载+待机时安装

这个方案最常用。流程是这样的:

  1. 电视开机后,后台Service检查是否有新版本。
  2. 如果有,在系统空闲时(比如深夜没人看)开始下载升级包。
  3. 下载完成后,标记为“待安装”。
  4. 当电视进入待机状态(用户按遥控器关机),系统执行升级操作。
  5. 升级完成后自动重启,回到待机状态。

嗯,这里要注意:待机状态下的升级,必须保证电源不会断。我遇到过一个问题——有些电视的待机其实是“假待机”,系统还在跑,但电源管理模块会定时休眠。如果升级过程中休眠了,那就麻烦了。

代码层面,核心逻辑是这样的:

// 后台下载服务
public class OTADownloadService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 检查网络状态
        if (!isWifiConnected()) {
            Log.w(TAG, "Wi-Fi未连接,暂停下载");
            return START_NOT_STICKY;
        }
        
        // 检查是否在空闲时段(例如凌晨2点-5点)
        if (!isIdleTime()) {
            Log.d(TAG, "非空闲时段,延迟下载");
            scheduleRetry(30 * 60 * 1000); // 30分钟后重试
            return START_NOT_STICKY;
        }
        
        // 开始下载
        downloadPackage(getUpdateUrl());
        return START_STICKY;
    }
    
    private boolean isIdleTime() {
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        return hour >= 2 && hour <= 5;
    }
}

方案二:双分区无缝切换(A/B分区)

这个方案更高级,也是Google推荐的。电视有两个系统分区(A和B),当前运行在A区时,升级包直接写入B区。下次重启时,系统自动切换到B区启动。

好处很明显:

  • 用户完全无感知。升级在后台完成,下次开机就是新系统。
  • 如果升级失败,自动回滚到旧分区,不会变砖。
  • 不需要进入Recovery模式,减少了交互复杂度。

但缺点也有:需要额外的存储空间(多一个分区),对低端电视不太友好。

我的经验:如果电视存储空间足够(8GB以上),我强烈建议用A/B分区方案。虽然实现复杂一些,但用户体验是最好的。我曾经在一个项目里用方案一,结果用户投诉说“电视半夜自己重启了”,后来改成A/B分区就再没出过问题。

25.3 用户交互设计要点

电视的交互设计,跟手机完全是两码事。手机可以弹全屏对话框,电视不行——遥控器操作太慢了。

我总结了几条原则:

原则一:尽量减少弹窗

能不弹就不弹。如果必须弹,用半透明浮层,不要遮挡全部画面。用户正看着节目呢,你弹个全屏升级提示,这不是找骂吗?

原则二:升级提示要“轻”

如果必须提示用户,用Toast或者底部通知栏。比如:

// 轻量级升级提示
public class OTAUpdateNotification {
    public void showUpdateAvailable(Context context) {
        // 使用系统通知栏,不要弹Dialog
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_update)
                .setContentTitle("系统更新可用")
                .setContentText("新版本已准备好,将在待机时自动安装")
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setAutoCancel(true);
        
        NotificationManager manager = 
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(NOTIFICATION_ID, builder.build());
    }
}

原则三:强制升级要“软”

有些安全更新必须强制升级,但也不能太强硬。我建议的做法是:

  • 第一次提示:通知栏显示,用户可以选择“稍后”
  • 第二次提示:24小时后,弹半透明浮层,用户可以选择“今晚安装”
  • 第三次提示:48小时后,弹确认对话框,用户可以选择“立即重启”或“4小时后提醒”
  • 最终强制:72小时后,自动在待机时安装

这个节奏,用户一般都能接受。我见过有些厂商直接弹全屏强制升级,结果被用户骂上论坛。

避坑指南:我曾经在一个项目中,把强制升级的等待时间设成了24小时。结果有用户出差一周,回来发现电视还在等升级——因为电视一直没待机。后来我改成“累计待机时间达到X小时”才触发强制升级,问题就解决了。

25.4 升级流程的SVG结构图

下面这张图,展示了TV OTA的完整升级流程。我把它分成三个阶段:下载、准备、安装。

Android TV OTA升级流程 阶段一:后台下载 检查更新 空闲时段判断 下载升级包 校验 阶段二:安装准备 标记待安装状态 等待待机信号 用户交互(可选提示) 阶段三:安装与重启 进入Recovery/切换分区 安装升级包 重启系统 完成

25.5 升级策略对比表

我把几种常见的TV OTA策略做了个对比,方便你选型时参考:

策略 用户感知 安全性 存储要求 实现复杂度 推荐场景
后台下载+待机安装 低端电视、存储有限
A/B分区无缝切换 中高端电视、旗舰机型
强制升级(全屏提示) 安全补丁、紧急更新
用户手动触发 完全可控 低(用户可能不升级) 可选更新、功能增强

我的建议:实际项目中,我通常把“后台下载+待机安装”作为默认策略,同时提供“手动检查更新”入口。如果遇到安全漏洞,再临时启用强制升级。这样既保证了用户体验,又不会错过关键更新。

25.6 几个容易踩的坑

最后分享几个我踩过的坑,希望能帮你少走弯路:

  • 下载失败重试机制:电视的Wi-Fi信号可能不稳定,下载到一半断了怎么办?我建议用断点续传,并且重试间隔要递增(比如第一次5分钟,第二次15分钟,第三次1小时),避免频繁重试耗电。
  • 存储空间检查:升级包下载前一定要检查剩余空间。我遇到过用户电视存储快满了,下载到99%报错,用户体验极差。
  • 遥控器电池电量:升级过程中如果用户按遥控器,系统可能会响应。我建议在升级期间屏蔽遥控器的大部分按键,只保留电源键(用于紧急关机)。
  • 多语言支持:电视可能卖给不同国家,升级提示文案要支持多语言。我见过一个项目,英文文案写对了,中文翻译错了,结果用户看到“系统将自动销毁”,吓得直接拔电源。

嗯,TV OTA这块内容差不多就这些了。核心就一句话:把用户当用户,别把用户当测试员。升级做得好,用户根本感觉不到;做得不好,那就是灾难。


公众号:蓝海资料掘金营,微信deep3321