TV App — 适用于智能电视的应用程序,可在 Apple TV(tvOS)和 Android TV(Google TV)平台上运行。与移动应用程序不同,TV App 的开发考虑了遥控器导航、焦点管理(Focus Engine)以及大屏幕界面的特定要求。开发使用 Swift/SwiftUI 进行 Apple TV 开发,使用 Kotlin 和 Leanback Library 进行 Android TV 开发。根据 Statista(2026)的数据,全球有超过 2.5 亿台设备在这些平台上运行,这使 TV App 成为开发人员的一个有前途的细分市场。让我们来看看平台架构、焦点管理、代码示例和发布流程。
要点
TV App — 专为在智能电视平台上运行而设计的应用程序:Apple TV(tvOS)和 Android TV(Google TV)。与移动应用程序的主要区别在于交互方式。用户不触摸屏幕,而是通过遥控器控制界面。所有元素都必须通过定向导航(D-pad)可访问:上、下、左、右和选择按钮。
TV App 开发的特点: 屏幕分辨率 — 从 Full HD(1920x1080)到 4K(3840x2160),密度为 xhdpi(Android)或 @3x(Apple)。必须从边缘保留 5% 的安全区域以补偿过扫描(部分图像可能被电视裁剪)。没有触摸屏 — 所有交互都通过遥控器或游戏手柄进行。焦点始终突出显示活动元素。功耗不受电池限制,但应用程序必须正确处理休眠模式转换。根据 Statista(2026)的数据,全球智能电视市场超过新电视的 80%,Apple TV 和 Android TV 覆盖超过 2.5 亿台设备。
TV 应用程序类别: 视频服务(Netflix、YouTube、Apple TV+)、音乐(Spotify、Apple Music)、游戏(Apple Arcade、Google Play Games)、健身(Apple Fitness+、Peloton)、教育、新闻、天气、照片。最受欢迎的类别是视频流,占智能电视总使用时间的 70%。
tvOS — 基于 iOS 的 Apple TV 设备的 Apple 操作系统。首次发布 — 2015 年,与第四代 Apple TV 一同推出。tvOS 与 iOS 共享 XNU 内核、Foundation 框架、UIKit(适应版本)和 App Sandbox 安全机制。开发使用 Swift 语言,采用 SwiftUI 或 UIKit。
tvOS 的主要组件:
tvOS 应用程序的生命周期 类似于 iOS:notRunning、foregroundActive、foregroundInactive、background。特点:应用程序不应无故请求后台权限 — 系统可能会强制终止后台进程。导航拓扑围绕 UISplitViewController 和 UITabBarController 构建,带有“首页”、“搜索”、“资料库”、“设置”选项卡。
Android TV — 为电视和机顶盒优化的 Android 版本,于 2014 年首次推出。自 2020 年起,存在 Google TV — Android TV 之上的层,具有新界面,但应用程序开发在 Android TV SDK 上进行,与 Google TV 兼容。主要语言 — Kotlin,UI 框架 — Leanback Library(经典)和 Jetpack Compose for TV(实验性)。
Android TV 的关键组件:
Android TV 与移动 Android 的区别: 应用程序必须在清单中强制声明 LEANBACK_LAUNCHER 类别;最小布局宽度 — 1920dp;触摸交互被 D-pad 导航取代;建议使用 Leanback 片段;必须使用硬件加速。构建包括支持 ARM64 和 x86 架构的 APK/AAB。自 2025 年起,现代项目建议使用 Jetpack Compose for TV,包含 TvLazyColumn、TvButton、TvCard 组件。
Focus Engine — 每个 TV 平台的关键组件,负责确定哪个界面元素处于活动状态。在 tvOS 上,Focus Engine 内置于 UIKit 中并自动工作。按下 D-pad 按钮时,系统会分析所有可聚焦元素的位置,计算按压方向上最近的候选者,并通过动画(UIFocusAnimationCoordinator)平滑地将焦点移动到该元素。
Focus Engine 规则: 系统考虑沿运动轴的元素之间的距离、元素投影的交集(如果元素的投影与当前焦点的投影相交,则该元素被视为候选)、相同距离元素的优先级(选择直线距离最近的)。开发人员可以通过 UIFocusGuide 影响焦点 — 一个不可见的引导矩形,当向给定方向按压时,将焦点重定向到特定元素。
在 Android TV 上,焦点通过 Android 标准焦点系统实现,使用 focusable 和 nextFocus*(nextFocusDown、nextFocusUp、nextFocusLeft、nextFocusRight)属性。动画通过 StateListAnimator 配置。Google 建议在所有交互元素上设置 focusable,并使用 nextFocus 进行精确的导航控制。焦点动画对 UX 至关重要 — 焦点过渡时,应发生平滑的缩放动画(1.0 → 1.05–1.2),持续时间为 150–250 毫秒。
使用 SwiftUI 为 Apple TV 编写的简单 TV 应用程序示例,显示电影列表并支持 Focus Engine。
import SwiftUI
struct Movie: Identifiable {
let id = UUID()
let title: String
let subtitle: String
}
struct ContentView: View {
@FocusState private var focusedMovie: UUID?
let movies: [Movie] = [
Movie(title: "Inception", subtitle: "2010, Sci-Fi"),
Movie(title: "Interstellar", subtitle: "2014, Sci-Fi"),
Movie(title: "The Matrix", subtitle: "1999, Action"),
Movie(title: "Blade Runner 2049", subtitle: "2017, Sci-Fi"),
]
var body: some View {
VStack(alignment: .leading, spacing: 40) {
Text("电影").font(.title).padding(.leading, 60)
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 40) {
ForEach(movies) { movie in
VStack {
Image(systemName: "film.fill")
.resizable()
.frame(width: 200, height: 300)
.cornerRadius(12)
.focusable()
.focused($focusedMovie, equals: movie.id)
Text(movie.title).font(.headline)
Text(movie.subtitle).font(.subheadline).foregroundColor(.secondary)
}
.scaleEffect(focusedMovie == movie.id ? 1.15 : 1.0)
.animation(.easeInOut(duration: 0.2), value: focusedMovie)
}
}
.padding(.horizontal, 60)
}
}
.onAppear { focusedMovie = movies.first?.id }
}
}
关键点:@FocusState — 跟踪当前焦点;.focusable() — 使元素可聚焦;.scaleEffect() — 焦点时的放大动画,对于电视上的视觉反馈很重要。
使用 Kotlin 和 Leanback Library 为 Android TV 编写的类似示例:
// MainActivity.kt
class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
class MainFragment : BrowseSupportFragment() {
private val moviePresenter = MoviePresenter()
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
title = getString(R.string.app_name)
headersState = HEADERS_ENABLED
setupAdapter()
}
private fun setupAdapter() {
val rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
val listRowAdapter = ArrayObjectAdapter(moviePresenter)
listRowAdapter.add(Movie("Inception", "2010", R.drawable.poster_1))
listRowAdapter.add(Movie("Interstellar", "2014", R.drawable.poster_2))
rowsAdapter.add(ListRow(HeaderItem(0, "Movies"), listRowAdapter))
adapter = rowsAdapter
}
}
data class Movie(val title: String, val subtitle: String, val imageResId: Int)
class MoviePresenter : Presenter() {
override fun onCreateViewHolder(parent: ViewGroup): ViewHolder {
val cardView = ImageCardView(parent.context).apply {
isFocusable = true
setMainImageDimensions(200, 300)
}
return ViewHolder(cardView)
}
override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) {
val movie = item as Movie
(viewHolder.view as ImageCardView).apply {
titleText = movie.title
contentText = movie.subtitle
}
}
override fun onUnbindViewHolder(viewHolder: ViewHolder) {}
}
关键点:BrowseSupportFragment — 带有标题的主要 Leanback 片段;Presenter — 用于创建 ViewHolder 的抽象,类似于 RecyclerView.Adapter;ImageCardView — 带有图像、标题和副标题的标准卡片;isFocusable = true — TV 元素的必需属性。
常见问题
TV App 使用遥控器(D-pad)而非触摸控制,使用 Focus Engine 进行导航,针对大屏幕(Full HD 或 4K)进行了优化,并且没有电池限制。所有元素都必须通过焦点的定向移动来访问。
Focus Engine — tvOS 上的系统,自动确定活动界面元素。按下 D-pad 按钮时,系统会分析可聚焦元素的位置,计算 最近的候选者,并通过动画将焦点移动到该元素。
主要框架 — Leanback Library(BrowseFragment、DetailsFragment、PlaybackOverlayFragment)。对于现代项目,Jetpack Compose for TV 也提供实验性支持。
对于初始开发,模拟器就足够了:Xcode 包含带有 Siri Remote 的 tvOS 模拟器,Android Studio 包含 Android TV 模拟器。对于最终测试,建议使用物理设备。
Apple TV App 通过 App Store Connect 使用 Xcode Organizer 发布。Android TV App — 通过 Google Play Console,在清单中指定 LEANBACK_LAUNCHER 并提供 1920x1080 的截图。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。