news 2026/9/2 12:38:49

一按遥控器就能换台:my-tv 电视直播应用装与用要点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一按遥控器就能换台:my-tv 电视直播应用装与用要点

一按遥控器就能换台:my-tv 电视直播应用装与用要点

【免费下载链接】my-tv我的电视 电视直播软件,安装即可使用项目地址: https://gitcode.com/GitHub_Trending/my/my-tv

家里的智能电视只带一个遥控器,你想让它在沙发上像机顶盒一样直接看央视、卫视的直播,my-tv 就是干这个的——一个「安装即可使用」的 Android TV 直播应用,内置央视/地方/港澳台/国际四组频道,靠遥控器的上下键换台。本文带你把它装进电视、看懂它是怎么把遥控器按键变成换台动作的,以及改代码时最容易踩的几个坑;不讲后端协议细节和加密算法的内部实现。

全局地图:先看结论再抠细节

要解决的问题项目里的做法对应文件
电视上没有鼠标,怎么启动应用用 Leanback 的LEANBACK_LAUNCHER让 TV 端识别为电视应用app/src/main/AndroidManifest.xml
遥控器按键怎么变成换台动作onKeyDown里把CHANNEL_UP/DOWN映射到切台方法app/src/main/java/com/lizongying/mytv/MainActivity.kt
频道从哪来、怎么分组Map<String, List<TV>>静态内置,mustToken过滤app/src/main/java/com/lizongying/mytv/TVList.kt
换完台记得住上次看到哪个SharedPreferencesitemPositionapp/src/main/java/com/lizongying/mytv/SP.kt
一个频道有多个片源、断了要能恢复videoUrl存成列表,onStart里自动prepare重播app/src/main/java/com/lizongying/mytv/PlayerFragment.kt

上图是作者标注的小米遥控器按键位:中间方向盘负责「上一频道/下一频道」和「打开菜单/确认频道」,下方三个小键负责关闭菜单和帮助。理解了这张图,下面看代码就知道每个键对应哪段逻辑了。

把应用装进电视:先让 TV 端认得它

结论先行:电视直播应用和普通手机应用最大的区别是「没有鼠标」,所以启动方式必须声明成电视应用,否则有些盒子根本装不上或点不开。

看清单文件里的两段声明,这是 TV 应用的「身份证」:

<uses-feature android:name="android.software.leanback" android:required="true" /> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>

LEANBACK_LAUNCHER是电视端的启动器类别,加了它 TV 主界面才会把它当成「电视应用」展示出来;同时touchscreen被声明成required="false",意思是「没触屏也能跑」,这正契合电视盒子。

反例提示:很多坑出在这一步。如果你只留LAUNCHER类别、漏掉LEANBACK_LAUNCHER,应用在部分电视上会以「手机应用」身份出现,甚至被系统判定为不兼容而拒绝安装。另外别把largeHeap="true"这种针对直播长播放的内存配置随手删掉,长会话容易因为内存不足闪退。

安装本身有三种路子:能开 ADB 的盒子直接adb install my-tv.apk;小米电视可以走「小米电视助手」;其它就 U 盘拷进电视里装。想改代码再打包,仓库地址是 https://gitcode.com/GitHub_Trending/my/my-tv ,git clone下来即可。

配置遥控器按键的 5 个动作

结论先行:换台、返回、开设置这些手感好不好,全看onKeyDown里按键码映射得对不对,这里是整个遥控器交互的心脏。

MainActivity把物理键码翻译成具体动作,核心就这五个分支:

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_CHANNEL_UP -> channelUp() KeyEvent.KEYCODE_CHANNEL_DOWN -> channelDown() KeyEvent.KEYCODE_DPAD_CENTER -> switchMainFragment() KeyEvent.KEYCODE_MENU -> showSetting() KeyEvent.KEYCODE_BACK -> back() } return super.onKeyDown(keyCode, event) }

为什么这么写:CHANNEL_UP/DOWN是机顶盒遥控器上的专用换台键,很多 TV 盒子的「上下方向键」并不会触发它,所以这里同时接了方向键和换台键两套来源,避免「有的盒子好使、有的不使」。BACK键被拦截成自定义back(),实现「连按两次才退出」,防止用户看球时一个误触就把直播关掉了。

反例提示:新手常犯的错误是只处理KEYCODE_DPAD_UP、忘了KEYCODE_CHANNEL_UP,结果换台键在不少品牌盒子上完全失灵。另一个坑是back()里用doubleBackToExitPressedOnce做二次确认时,2 秒后没把标志位复位,下次按返回键直接退出——这段延迟复位逻辑别删。

组织频道列表并记住上次停在哪个台

结论先行:频道不是从服务器拉的,而是内置成一个「分组名 → 频道数组」的 Map,换台时靠一个下标在拍平的列表里前后移,最后把下标存进本地就能「断点续看」。

频道数据集中在 TVList.kt,结构一目了然:

var list = mapOf( "央视" to listOf(TV(0, "CCTV1 综合", "CCTV1", listOf(), "央视", ..., ProgramType.Y_PROTO, false, mustToken = false), ...), "地方" to listOf(TV(0, "东方卫视", "东方卫视", listOf(), "地方", ..., ProgramType.Y_PROTO, true, mustToken = false), ...), "港澳台" to listOf(TV(0, "凤凰卫视资讯台", "", listOf(), "港澳台", ..., ProgramType.F, false, mustToken = false), ...) )

注意mustToken = true的频道(比如某些综艺频道)会在setup()里被直接过滤掉,不放进最终列表——这是「暂时播不了的就不显示」的取舍。每条TV还带programType,标记走央视 proto 协议、JCE 协议还是凤凰的 F 协议,后面拉取 EPG 时按这个分发。

换台动作在 MainFragment.kt 里就是一个下标的循环移动,退出时把下标存进 SP.kt:

fun next() { view?.post { itemPosition++ if (itemPosition == tvListViewModel.size()) itemPosition = 0 // 到末尾回到开头 tvListViewModel.setItemPosition(itemPosition) tvListViewModel.getTVViewModel(itemPosition)?.changed() } } // 在 onStop() 里: SP.itemPosition = itemPosition

为什么这样写:把「换台」抽象成对itemPosition的自增和回绕,配合SPitemPosition存取,应用一冷启动就停在用户上次看到的台,体验上就像传统电视。

反例提示:如果给每个频道各发一个网络请求去切台,既慢又容易撞并发。这里统一由MainFragment持有「当前下标」这一个真源,其它 Fragment 只读不写。千万别在PlayerFragment里再维护一份「当前台号」,两边一不一致,换台就会跳到错的台。

处理多片源切换和播放失败恢复

结论先行:直播最让人抓狂的是「切到某台黑屏」,项目靠「一个频道挂多个片源 + 生命周期里自动重播」两招来兜底。

每个频道的videoUrl是一个列表而不是单条,TV.kt 里是List<String>,PlayerFragment.kt 只负责取当前下标那条去播:

fun play(tvViewModel: TVViewModel) { playerView?.player?.run { setMediaItem(MediaItem.fromUri(tvViewModel.getVideoUrlCurrent())) prepare() } } override fun onStart() { if (playerView?.player?.isPlaying == false) { playerView?.player?.prepare() // 恢复播放 playerView?.player?.play() } }

为什么这样写:getVideoUrlCurrent()videoIndex取当前片源,一旦某条源失效,可以把videoIndex切到列表里的下一条;而onStart里的prepare()重播,专门处理「切后台再切回来」时播放被挂起的情况——更新日志里的「恢复播放」就是指它。

反例提示:典型错误是把播放地址存成一个String,源一旦失效就彻底黑屏且无法自愈。正确姿势是像这里一样存成List<String>,把「当前用第几路」和「一共有哪些路」分开管理。另外onPause里要记得stop()释放解码器,否则从设置页返回时新旧两路音频叠在一起、内存也跟着涨。

📋 上手自检清单

  • 清单里同时声明了LEANBACK_LAUNCHERLAUNCHER两个类别,电视端能正确识别为 TV 应用
  • onKeyDown同时接了CHANNEL_UP/DOWN和方向键,换台在不同盒子都不失灵
  • BACK键走二次确认退出,且 2 秒后复位了doubleBackToExitPressedOnce标志
  • 频道按「央视/地方/港澳台/国际」分组,mustToken=true的已被过滤不显示
  • 换台只改itemPosition一个下标,退出时写进SP.itemPosition实现断点续看
  • 每个频道videoUrl是列表而非单条,失效时能切到下一条源
  • onStart里有prepare()恢复播放,onPause里有stop()释放解码器
  • adb install或 U 盘把 apk 装进实际要用的电视盒子,真机验证过换台

想真正搞明白它怎么把遥控器变成一台「能换台、记得住、断网能自愈」的电视,最该先读的就是 MainActivity.kt 的按键分发和 MainFragment.kt 的下标换台。建议你先把 apk 装到一台真电视上换几个台试试手感,再回头对照代码找对应分支,比干读文档快得多。

【免费下载链接】my-tv我的电视 电视直播软件,安装即可使用项目地址: https://gitcode.com/GitHub_Trending/my/my-tv

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 12:38:42

AI 助手团队协作怎么落地:OMX 用 5 个阶段把并行开发管住

AI 助手团队协作怎么落地&#xff1a;OMX 用 5 个阶段把并行开发管住 【免费下载链接】oh-my-codex OmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more. 项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex 3 个…

作者头像 李华
网站建设 2026/9/2 12:35:02

Sunshine 快速上手指南:15 分钟把 PC 变成家庭游戏串流服务器

Sunshine 快速上手指南&#xff1a;15 分钟把 PC 变成家庭游戏串流服务器 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 想在客厅电视上打 3A 大作&#xff0c;或在地铁里用平板接…

作者头像 李华
网站建设 2026/9/2 12:30:24

Carbon 语言上手指南:从装好工具链到跑通素数筛

Carbon 语言上手指南&#xff1a;从装好工具链到跑通素数筛 【免费下载链接】carbon-lang Carbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README) 项目地址: https://gitcode.com/…

作者头像 李华
网站建设 2026/9/2 12:26:12

SpringCloudAlibaba 基于Nacos Config的配置中心

关于 Spring Cloud Config Spring Cloud Config 用于跨多个应用程序和环境存储和提供分布式配置。此配置存储理想地在Git版本控制下进行版本管理&#xff0c;并且可以在应用程序运行时进行修改。虽然它非常适合使用所有支持的配置文件格式以及Environment、PropertySource 或 V…

作者头像 李华