8.5 KiB
1. Temel Teknoloji Yığını ve Kütüphaneler
| Kategori | Kütüphane / Teknoloji | Neden Bu Tercih Edilmeli? |
|---|---|---|
| State Management | flutter_riverpod |
SOLID'in Dependency Inversion (D) prensibini uygulamak ve servisleri izole etmek için en modern ve güvenli yöntem. |
| Cihaz Keşfi (mDNS) | nsd veya bonsoir |
Zero-config ağ keşfi için endüstri standardı. TV kendini yayınlar, telefon bulur. |
| Ağ İletişimi | shelf (Local HTTP Server) |
TV tarafında raw TCP socket yerine küçük bir REST API (HTTP Server) kurmak hata yönetimini ve loglamayı inanılmaz kolaylaştırır. |
| Video Oynatıcı | media_kit |
Chewie/Video_player yerine kesinlikle bunu kullanmalısın. libmpv tabanlıdır. HLS (.m3u8), MKV ve özel codec'leri Android TV'de kusursuz oynatır. |
| Link Yakalama | receive_sharing_intent |
Mobil cihazda tarayıcıdan "Paylaş" aksiyonunu dinlemek için. |
| Video Extraction | flutter_inappwebview & html |
Sayfa içindeki gizli .m3u8 veya .mp4 linklerini headless (gizli) bir tarayıcıda yakalamak için. |
| Lokal Depolama | shared_preferences |
Cihazın "TV" mi yoksa "Mobil" mi olduğunu ilk seçimden sonra hatırlamak için. |
2. Proje Klasör Yapısı (Clean Architecture)
Kodun test edilebilir ve modüler olması için Feature-First (Özellik Odaklı) bir Clean Architecture yapısı kurmalıyız:
lib/
├── core/ # Tüm projede ortak kullanılan yapılar
│ ├── constants/ # Port numaraları, API endpoint'leri
│ ├── error/ # Custom exception sınıfları
│ └── network/ # Temel ağ arayüzleri
├── features/
│ ├── setup/ # Cihaz rolü (TV/Telefon) seçim ekranı
│ ├── discovery/ # mDNS ile cihaz arama ve eşleşme (Mobil)
│ ├── receiver/ # TV tarafı: Local server ve oynatıcı
│ └── sender/ # Mobil taraf: Link yakalama ve gönderme
└── main.dart # Riverpod ProviderScope ve Init işlemleri
Her feature (özellik) kendi içinde şu üç katmana ayrılmalıdır (SOLID uygulamasının kalbi):
- domain: Sadece saf Dart kodları. Arayüzler (
abstract class), entity'ler. - data: Dış dünyayla iletişim. API çağrıları, paket implementasyonları.
- presentation: UI (Widget'lar) ve State (Riverpod Notifier'lar).
3. Kritik İş Akışları ve "Best Practice" Yöntemler
A. İlk Açılış ve Rol Seçimi (Setup)
Kullanıcı uygulamayı ilk açtığında karşısına iki dev buton çıkar: "Ben bir Telefonum (Gönderici)" ve "Ben bir TV'yim (Alıcı)".
- Best Practice: Bu seçim yapıldığı an
SharedPreferences'a kaydedilir (role = 'sender' | 'receiver'). Uygulamanın bir sonraki açılışındamain.dartbu değeri okur ve kullanıcıyı doğrudan ilgili ana ekrana yönlendirir.
B. Cihaz Eşleştirme (Discovery - mDNS)
Bluetooth yerine aynı ağda mDNS (Zero-conf) kullanmak en stabil "Best Practice" yöntemdir.
- TV (Receiver): Uygulama açılır açılmaz arka planda
nsdile bir servis kaydeder. Örnek servis adı:FastWatcher._http._tcp. Ayrıcashelfile 8080 portunda bir HTTP server dinlemeye başlar (POST /play). - Mobil (Sender): "Eşleş" butonuna basıldığında ağı tarar. Bulunan cihazların IP'sini bir listeye koyar. Kullanıcı TV'sine dokunduğunda IP adresi telefona kaydedilir.
C. İletişim Protokolü (HTTP üzerinden)
Raw Socket'ler veriyi bölebilir veya bağlantı kopmalarında sorun yaratabilir. TV'de mini bir HTTP sunucusu kurmak çok daha "Solid" bir çözümdür.
- Mobil'in Gönderdiği Payload (JSON):
{ "url": "https://site.com/master.m3u8", "title": "The Instigators (Opsiyonel)", "timestamp": 1714415045 } - TV'nin Yanıtı:
200 OK(Başarıyla aldım, oynatmaya başlıyorum).
D. Video Linki Ayrıştırma (Video Extraction)
Tarayıcıdan paylaşılan link bir web sayfası olduğunda, içindeki asıl videoyu bulmak için şu hiyerarşi uygulanır:
- Headless WebView (En Garanti Yöntem): Kullanıcı linki paylaştığında, arka planda gizli bir
InAppWebViewaçılır.onLoadResourceveyashouldInterceptRequestmetodları ile ağ trafiği dinlenir..m3u8veya.mp4uzantılı bir istek yakalandığı an sayfa kapatılır ve link TV'ye gönderilir. - Open Graph & Meta Tags: Sayfa HTML'i
htmlpaketi ile indirilir.<meta property="og:video" content="...">veya<video src="...">etiketleri taranır. - Site Özelinde Çözücüler (Scrapers): YouTube için
youtube_explode_dart, Twitter/X için özel Regex paternleri gibi "Provider" tabanlı sınıflar kullanılır.
- SOLID Notu: Bu işlemi bir
LinkParserinterface'inden türetilenHeadlessParser,RegexParserveMetaParsergibi sınıflara bölmeliyiz.
4. SOLID Prensiplerinin Projeye Uygulanması
Bu projeyi "Solid" yapacak mimari kararlar şunlardır:
- S (Tek Sorumluluk):
DiscoveryServicesadece ağı tarar. UI'a karışmaz. Ekrana yazdırma işiniDiscoveryNotifier(State) veDiscoveryScreenyapar. - O (Açık/Kapalı): İletişim katmanını bir
abstract class NetworkClientolarak tanımla. Şu an Wi-Fi (HTTP) kullanıyoruz. Yarın Bluetooth eklemek istersen, mevcut kodu bozmadan yeni birBluetoothClientimplementasyonu ekleyebilirsin. - L (Liskov Yerine Geçme): Eğer TV tarafında birden fazla oynatıcı motoru kullanma ihtimalin varsa (örn:
MediaKitPlayerve yedek olarakExoPlayer), ikisi de birabstract class AppVideoPlayerarayüzünden türemelidir. - I (Arayüz Ayrımı): Sender ve Receiver çok farklı işler yapar. Her iki rol için devasa tek bir arayüz yazmak yerine,
ILinkSenderveILinkReceiverolarak küçük arayüzlere böl. - D (Bağımlılıkların Tersine Çevrilmesi): UI sınıfların (Widget'lar) asla doğrudan
nsdveyashelfpaketini bilmemelidir. Araya yazdığın soyut Repository sınıflarını (Riverpod üzerinden) UI'a enjekte etmelisin.
5. Tasarım ve Arayüz (UI Mockups)
Uygulamanın premium ve modern hissettirmesi için tasarlanan ekranlar şunlardır:
6. Geliştirme Adımları (Faz Planı)
Faz 1: Çekirdek ve İletişim (UI Olmadan)
- Proje yapısını ve Riverpod kurulumunu tamamla.
- TV tarafı için
shelfile basit bir HTTP server yaz ve Postman ile test et. - TV tarafında
nsdservisini başlat. - Mobil tarafta ağı tarayıp TV'nin IP'sini bulan kodu yaz.
Faz 2: Gönderim ve Oynatma
- Mobil cihazdan HTTP POST ile TV'ye manuel bir test linki (.m3u8) gönder.
- TV tarafında
media_kitpaketini kur ve gelen linki tam ekranda (kumanda odaklamalarına dikkat ederek) oynatan sayfayı tasarla.
Faz 3: Entegrasyon ve Link Extraction
- Mobil tarafa
receive_sharing_intentpaketini kur ve Android Manifest ayarlarını yap. LinkExtractionServiceoluştur:- Gelen URL eğer doğrudan video ise (
.mp4,.m3u8,.mkv) direkt TV'ye gönder. - Eğer bir web sayfası ise,
InAppWebView(headless) ile sayfayı yükleyip ağ trafiğini dinleyerek gerçek video linkini "crawle" et.
- Gelen URL eğer doğrudan video ise (
- Yakalanan linki ve sayfa başlığını (Title) eşleşmiş olan TV'ye fırlat.
- Hatalı/Desteklenmeyen linkler için kullanıcıya "Video bulunamadı" uyarısı göster.
Bu mimariyle yazdığın bir kod hem çok hızlı çalışacak hem de aylar sonra dönüp baktığında nerede ne olduğunu saniyeler içinde bulabileceksin.
İlk olarak projeyi ayağa kaldırdıktan sonra, shelf ile TV tarafındaki o mini HTTP sunucusunun arayüzünü (Interface) tasarlayarak başlamak ister misin? Sana o kısmın Dependency Inversion'a uygun örnek kodunu yazabilirim.



