Tüm Yazılar
KategoritvOS
Okuma Süresi
18 dk
Yayın Tarihi
...
Kelime Sayısı
1.378kelime

Kahveni hazırla - bu içerikli bir makale!

Apple TV için uygulama geliştirme. Focus-based navigation, TVUIKit, Top Shelf extensions, multi-user ve game controller desteği.

tvOS Development: Apple TV Uygulamaları Geliştirme

Oturma odasının en büyük ekranı Apple TV'de. 4K HDR, Dolby Atmos, büyük ekran deneyimi... Ve SwiftUI ile geliştirmesi sandığından kolay. Tek fark: dokunmatik ekran yok, uzaktan kumanda var. Bu da tamamen farklı bir interaction model demek.

İçindekiler

  1. tvOS Geliştirmeye Giriş
  2. Focus Engine: tvOS'un Kalbi
  3. SwiftUI ile tvOS UI
  4. Top Shelf Extensions
  5. Video Playback ve AVKit
  6. Multi-User Desteği
  7. Game Controller
  8. Production Best Practices

tvOS Geliştirmeye Giriş {#tvos-giris}

tvOS, iOS'un büyük ekran versiyonu. Ama temel fark: dokunmatik yok. Kullanıcı Siri Remote ile gezinir - bu da "focus-based navigation" demek.

Özellik
iOS
tvOS
**Input**
Multi-touch
Siri Remote + Focus
**Ekran**
Küçük-orta
Büyük (40-85")
**Mesafe**
30cm
2-5 metre
**Font boyutu**
17pt
29pt+
**Etkileşim**
Tap, swipe
Focus, select, menu
**Storage**
Sınırlı değil
500KB kalıcı
⚠️ Dikkat: tvOS'ta kalıcı depolama sadece 500KB! Büyük veriler CloudKit veya on-demand resources ile yönetilmeli.

Dış Kaynaklar:


Focus Engine {#focus-engine}

tvOS'un en önemli kavramı focus. Ekranda bir anda sadece bir öğe "focused" olabilir. Siri Remote ile yön tuşlarıyla focus hareket ettirilir.

swift
1struct MovieGridView: View {
2 let movies: [Movie]
3 @FocusState private var focusedMovie: Movie.ID?
4 
5 var body: some View {
6 ScrollView(.horizontal) {
7 LazyHStack(spacing: 40) {
8 ForEach(movies) { movie in
9 MovieCard(movie: movie)
10 .focusable()
11 .focused($focusedMovie, equals: movie.id)
12 // Focus'ta büyütme efekti
13 .scaleEffect(focusedMovie == movie.id ? 1.1 : 1.0)
14 .shadow(
15 radius: focusedMovie == movie.id ? 20 : 5
16 )
17 .animation(.easeInOut(duration: 0.2), value: focusedMovie)
18 .onSubmit {
19 // Siri Remote'ta tıklama
20 navigateToMovie(movie)
21 }
22 }
23 }
24 .padding(.horizontal, 50)
25 }
26 }
27}
28 
29struct MovieCard: View {
30 let movie: Movie
31 @Environment(\.isFocused) var isFocused
32 
33 var body: some View {
34 VStack {
35 AsyncImage(url: movie.posterURL) { image in
36 image.resizable().aspectRatio(2/3, contentMode: .fill)
37 } placeholder: {
38 Rectangle().fill(.gray.opacity(0.3))
39 }
40 .frame(width: 220, height: 330)
41 .clipShape(RoundedRectangle(cornerRadius: 10))
42 
43 if isFocused {
44 Text(movie.title)
45 .font(.caption)
46 .transition(.opacity)
47 }
48 }
49 }
50}

SwiftUI ile tvOS UI {#swiftui-tvos}

swift
1struct ContentView: View {
2 var body: some View {
3 TabView {
4 // tvOS tab'ları ekranın üstünde
5 HomeView()
6 .tabItem { Label("Ana Sayfa", systemImage: "house") }
7 
8 MoviesView()
9 .tabItem { Label("Filmler", systemImage: "film") }
10 
11 SearchView()
12 .tabItem { Label("Ara", systemImage: "magnifyingglass") }
13 
14 SettingsView()
15 .tabItem { Label("Ayarlar", systemImage: "gear") }
16 }
17 }
18}
19 
20// Büyük ekran için özel layout
21struct HomeView: View {
22 var body: some View {
23 ScrollView {
24 VStack(alignment: .leading, spacing: 50) {
25 // Hero banner
26 FeaturedCarousel(items: featuredMovies)
27 .frame(height: 500)
28 
29 // Kategoriler
30 ForEach(categories) { category in
31 VStack(alignment: .leading, spacing: 20) {
32 Text(category.name)
33 .font(.title2)
34 .padding(.leading, 50)
35 
36 ScrollView(.horizontal, showsIndicators: false) {
37 LazyHStack(spacing: 40) {
38 ForEach(category.movies) { movie in
39 MovieCard(movie: movie)
40 }
41 }
42 .padding(.horizontal, 50)
43 }
44 .focusSection() // Bu section içinde focus yatay hareket eder
45 }
46 }
47 }
48 }
49 }
50}

Top Shelf Extensions {#top-shelf}

Top Shelf, Apple TV ana ekranında uygulamanın üst kısmında gösterilen içerik:

swift
1import TVServices
2 
3class TopShelfProvider: TVTopShelfContentProvider {
4 override func loadTopShelfContent() async -> TVTopShelfContent? {
5 // Sectioned content (dizi/film kategorileri gibi)
6 let sections = try? await loadCategories()
7 
8 let items = sections?.map { category -> TVTopShelfSectionedItem in
9 let sectionItems = category.items.map { item -> TVTopShelfSectionedItem.Item in
10 let topShelfItem = TVTopShelfSectionedItem.Item(identifier: item.id)
11 topShelfItem.title = item.title
12 
13 let image = TVTopShelfSectionedItem.Item.Image()
14 image.url = item.imageURL
15 topShelfItem.setImage(image, for: .screenScale2x)
16 
17 return topShelfItem
18 }
19 
20 let section = TVTopShelfSectionedItem(identifier: category.id)
21 section.title = category.name
22 section.items = sectionItems
23 return section
24 } ?? []
25 
26 return TVTopShelfSectionedContent(sections: items)
27 }
28}

Video Playback {#video}

swift
1import AVKit
2 
3struct VideoPlayerView: View {
4 let videoURL: URL
5 @StateObject private var playerVM = VideoPlayerViewModel()
6 
7 var body: some View {
8 VideoPlayer(player: playerVM.player) {
9 // Overlay UI
10 VStack {
11 Spacer()
12 HStack {
13 Text(playerVM.currentTimeString)
14 Spacer()
15 Text(playerVM.durationString)
16 }
17 .padding()
18 .background(.ultraThinMaterial)
19 }
20 }
21 .onAppear {
22 playerVM.setup(url: videoURL)
23 playerVM.player.play()
24 }
25 .onDisappear {
26 playerVM.player.pause()
27 }
28 }
29}

Multi-User Desteği {#multi-user}

tvOS, aynı Apple TV'yi kullanan birden fazla kullanıcıyı destekler. Her kullanıcının kendi profili, tercihleri ve önerileri olabilir:

swift
1import TVServices
2 
3class UserManager {
4 // Aktif kullanıcıyı tespit et
5 func getCurrentUser() async -> TVUserManager.User? {
6 let userManager = TVUserManager()
7 return userManager.currentUser
8 }
9 
10 // Kullanıcı değişikliğini dinle
11 func observeUserChanges() {
12 NotificationCenter.default.addObserver(
13 forName: .TVUserManagerCurrentUserDidChange,
14 object: nil,
15 queue: .main
16 ) { [weak self] _ in
17 Task {
18 await self?.handleUserChange()
19 }
20 }
21 }
22 
23 private func handleUserChange() async {
24 // Kullanıcı değişince:
25 // 1. Profil verilerini yükle
26 // 2. Önerileri güncelle
27 // 3. İzleme geçmişini değiştir
28 }
29}

Multi-User Kuralları

Kural
Açıklama
Kullanıcı başına veri
Her kullanıcının tercihleri ayrı tutulmalı
Geçiş hızı
Kullanıcı değiştiğinde UI anında güncellenmeli
Varsayılan profil
Giriş yapılmadığında ortak profil göster
iCloud entegrasyonu
Her kullanıcının kendi iCloud hesabı farklı

Game Controller Desteği {#game-controller}

Apple TV'de oyun geliştirmek için Game Controller framework'ü kullanılır. Siri Remote'un yanı sıra MFi controller ve PlayStation/Xbox gamepad'leri de desteklenir:

swift
1import GameController
2 
3class GameControllerManager: ObservableObject {
4 @Published var connectedController: GCController?
5 
6 init() {
7 setupControllerObservers()
8 }
9 
10 private func setupControllerObservers() {
11 // Controller bağlantısı
12 NotificationCenter.default.addObserver(
13 forName: .GCControllerDidConnect,
14 object: nil,
15 queue: .main
16 ) { [weak self] notification in
17 if let controller = notification.object as? GCController {
18 self?.configureController(controller)
19 }
20 }
21 
22 // Zaten bağlı controller'ları kontrol et
23 if let controller = GCController.controllers().first {
24 configureController(controller)
25 }
26 }
27 
28 private func configureController(_ controller: GCController) {
29 connectedController = controller
30 
31 // Extended gamepad (PS/Xbox controller)
32 if let gamepad = controller.extendedGamepad {
33 gamepad.buttonA.pressedChangedHandler = { _, _, pressed in
34 if pressed { self.handleAction() }
35 }
36 gamepad.leftThumbstick.valueChangedHandler = { _, xValue, yValue in
37 self.handleMovement(x: xValue, y: yValue)
38 }
39 }
40 
41 // Siri Remote (micro gamepad)
42 if let remote = controller.microGamepad {
43 remote.buttonA.pressedChangedHandler = { _, _, pressed in
44 if pressed { self.handleSelect() }
45 }
46 }
47 }
48 
49 private func handleAction() { /* Aksiyon butonu */ }
50 private func handleSelect() { /* Seçim */ }
51 private func handleMovement(x: Float, y: Float) { /* Hareket */ }
52}

Desteklenen Controller Türleri

Controller
Kullanım
API
**Siri Remote**
Temel navigasyon + basit oyunlar
`microGamepad`
**MFi Controller**
Tam oyun desteği
`extendedGamepad`
**PS DualSense**
Haptic feedback + adaptive triggers
`extendedGamepad` + `physicalInputProfile`
**Xbox Controller**
Standart gamepad
`extendedGamepad`

Production Best Practices {#best-practices}

🔑 Çıkarımlar

  1. Focus engine tvOS'un temeli - her UI elemanı focusable olmalı
  2. Büyük fontlar kullan - 2+ metre mesafeden okunmalı
  3. Focus section ile navigation akışını kontrol et
  4. Top Shelf içeriğini taze tut - kullanıcının ilk gördüğü yer
  5. 500KB storage limiti - büyük veri CloudKit'te
  6. Siri Remote gesture desteği ekle - swipe ile hızlı navigation

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?

Okuyucu Ödülü

Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Etiketler

#tvos#apple-tv#focus-engine#swiftui#top-shelf#game-controller#tutorial
Muhittin Çamdalı

Muhittin Çamdalı

Senior iOS Developer

12+ yıllık deneyime sahip iOS Developer. Swift, SwiftUI ve modern iOS mimarileri konusunda uzman. Apple platformlarında performanslı ve kullanıcı dostu uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

Bunu da begenebilirsiniz