Tüm Yazılar
KategoritvOS
Okuma Süresi
18 dk
Yayın Tarihi
2024-04-25
Kelime Sayısı
1.367kelime

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

tvOS Development: Apple TV Uygulamaları Geliştirme

Özet

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

  • tvOS'ta dokunmatik yok; Siri Remote ile focus-based navigation kullanılır.
  • Kalıcı depolama sadece 500KB; büyük veriler CloudKit veya on-demand resources'ta.
  • Top Shelf, TVTopShelfContentProvider ile ana ekranda sectioned içerik gösterir.
  • Game Controller framework Siri Remote, MFi, PS DualSense ve Xbox controller'ı destekler.
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


tvOS Geliştirmeye Giriş

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

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

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, 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

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

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

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

🔑 Çı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ı

Lead Mobile Engineer

12+ yıllık deneyime sahip Lead Mobile Engineer. Swift, SwiftUI, Kotlin ve Flutter ile iOS, Android ve cross-platform mimarilerde uzman. Performanslı ve kullanıcı dostu mobil uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

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

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik