↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama

4 dk okuma #flutter
Dizi · 58/61 Flutter Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
  3. Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
  4. Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
  5. Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
  6. Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
  7. Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
  8. Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
  9. Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
  10. Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
  11. Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
  12. Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
  13. Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
  14. Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
  15. Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
  16. Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
  17. Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
  18. Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
  19. Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
  20. Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
  21. Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
  22. Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
  23. Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
  24. Bölüm 6 — Konu 24: Provider Paketi
  25. Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
  26. Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
  27. Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
  28. Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
  29. Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
  30. Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
  31. Bölüm 7 — Konu 31: Deep Linking
  32. Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
  33. Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
  34. Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
  35. Bölüm 8 — Konu 35: Implicit Animasyonlar
  36. Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
  37. Bölüm 8 — Konu 37: Hero Animasyonları
  38. Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
  39. Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
  40. Bölüm 9 — Konu 40: Platform Channels
  41. Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
  42. Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
  43. Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
  44. Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
  45. Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
  46. Bölüm 10 — Konu 46: CI/CD
  47. Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
  48. Bölüm 10 — Konu 48: DevTools Profiling
  49. Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
  50. Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
  51. Bölüm 11 — Konu 51: Supabase Alternatifi
  52. Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
  53. Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
  54. Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
  55. Bölüm 12 — Konu 55: Flutter Web / Desktop
  56. Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
  57. Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
  58. Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
  59. Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
  60. Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
  61. Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
Dizinin sayfası →
İçindekiler 11 başlık
  1. Paket mi, Plugin mi? Terim Farkı
  2. Kendi Paketini Oluşturma
  3. Plugin Oluşturma — Federated Plugin Mimarisi
  4. example/ Klasörü — Zorunlu Bir Kanıt
  5. pub.dev'e Yayınlama
  6. pubspec.yaml — Metadata
  7. CHANGELOG.md — Zorunlu Şeffaflık
  8. Yayınlama Komutları
  9. Pub Points — pub.dev'in Kalite Skoru
  10. 🎯 Bu Dersten Çıkarılması Gerekenler
  11. 📝 Ödevler

Bölüm 1'den beri flutter pub add ile başkalarının yazdığı paketleri kullanıyoruz — http, provider, go_router, camera... Bu derste, madalyonun öbür yüzüne geçiyoruz: kendi paketini yazıp pub.dev'e yayınlamak.

Paket mi, Plugin mi? Terim Farkı

  • Paket (package): Sadece saf Dart kodu içerir — örneğin bir string işleme yardımcı kütüphanesi. Platforma özgü hiçbir şey yoktur.
  • Plugin: Paketin, native koda (Bölüm 9 Konu 40'ta öğrendiğimiz platform channel'lar aracılığıyla) bağlandığı özel bir türüdür — camera, geolocator gibi paketlerin hepsi aslında plugin'dir.

Bu ders, her ikisini de kapsayacak, ama plugin tarafı Konu 40'taki bilgini doğrudan kullanacağın için daha çok oraya odaklanacağız.

Kendi Paketini Oluşturma

bash
flutter create --template=package benim_paketim
metin
benim_paketim/
├── lib/
│   └── benim_paketim.dart     # DIŞARIYA açılan tek giriş noktası
├── test/
│   └── benim_paketim_test.dart
├── pubspec.yaml
├── README.md
├── CHANGELOG.md
└── LICENSE

Bölüm 1 Konu 3'te öğrendiğimiz proje yapısına çok benziyor, ama fark var: bir uygulama (flutter create .) main() fonksiyonuyla çalıştırılabilir; bir paket, başka projelerin import'layacağı, kendi başına çalıştırılamayan bir kütüphanedir (Dart Bölüm 12'de öğrendiğimiz library/export mekanizmasını hatırla).

dart
// lib/benim_paketim.dart
library benim_paketim;

export 'src/hesaplayici.dart';  // Dart Bölüm 12 — hangi dosyaların DIŞARIYA açık olacağını belirler

export, Dart Bölüm 12'de öğrendiğimiz kritik bir kavram — paketinin lib/src/ altındaki iç detayları (implementasyon), sadece bilinçli olarak export ettiğin kısımlar dışarıdan erişilebilir olur. Bu, Bölüm 7'de öğrendiğimiz Interface Segregation'a benzer bir disiplin: kullanıcına sadece ihtiyacı olanı göster, iç detayları gizle.

Plugin Oluşturma — Federated Plugin Mimarisi

bash
flutter create --template=plugin --platforms=android,ios benim_pluginim

Modern Flutter plugin'leri, "federated" (dağıtık) bir mimariyle yazılır — Konu 40'ta öğrendiğimiz MethodChannel mantığının, paket seviyesinde organize edilmiş hali:

metin
benim_pluginim/                    # ana paket — kullanıcının import ettiği
benim_pluginim_platform_interface/ # SOYUT arayüz (Bölüm 7 Konu 34'teki Dependency Inversion!)
benim_pluginim_android/            # Android implementasyonu
benim_pluginim_ios/                # iOS implementasyonu

Bunu neden bu kadar parçalıyoruz? Bölüm 7 Konu 34'te öğrendiğimiz Dependency Inversion prensibini hatırla — benim_pluginim_platform_interface, soyut bir sözleşme (tıpkı bir abstract class Repository gibi) tanımlar; _android ve _ios paketleri, bu sözleşmenin somut implementasyonlarıdır. Bu mimarinin büyük faydası: bir üçüncü kişi, senin izin vermene bile gerek kalmadan, kendi benim_pluginim_windows paketini yazıp aynı arayüze uyarak, plugin'ini Windows'a da genişletebilir — tıpkı Bölüm 7'de bir ProfilRepository arayüzüne, senin bilmediğin yeni bir implementasyonun (örn. bir FakeProfilRepository) sorunsuzca eklenebilmesi gibi.

dart
// benim_pluginim_platform_interface/lib/benim_pluginim_platform_interface.dart
abstract class BenimPluginimPlatform extends PlatformInterface {
  static BenimPluginimPlatform _instance = MethodChannelBenimPluginim();
  static BenimPluginimPlatform get instance => _instance;

  Future<String?> platformVersiyonuAl(); // her platformun UYGULAMASI gereken sözleşme
}
dart
// benim_pluginim_android/lib/... — Konu 40'taki MethodChannel'ı hatırla!
class MethodChannelBenimPluginim extends BenimPluginimPlatform {
  final _kanal = const MethodChannel('benim_pluginim');

  @override
  Future<String?> platformVersiyonuAl() async {
    return await _kanal.invokeMethod<String>('getPlatformVersion');
  }
}

Basit bir plugin için (tek platform, karmaşık olmayan) bu tam ayrım gerekmez — flutter create --template=plugin komutu, senin ihtiyacına göre daha basit, tek paketli bir yapı da üretebilir. Federated mimari, büyük/topluluk odaklı plugin'ler (birden fazla platformu, birden fazla katkıcıyla desteklemek) için değerlidir.

example/ Klasörü — Zorunlu Bir Kanıt

metin
benim_pluginim/
└── example/
    └── lib/main.dart   # plugin'i KULLANAN, çalıştırılabilir bir örnek uygulama

Her paket/plugin, kendi içinde bir example/ klasörü barındırmalıdır — bu sadece iyi bir pratik değil, pub.dev'in puanlama sistemi (birazdan göreceğiz) bunu doğrudan ödüllendiriyor. example/, hem senin (paketi geliştirirken gerçek bir uygulamada test etmek için) hem kullanıcıların (paketi nasıl kullanacaklarını çalışan bir kod üzerinden görmek için) işine yarar.

pub.dev'e Yayınlama

pubspec.yaml — Metadata

yaml
name: benim_pluginim
description: Cihazın pil seviyesini basitçe okuyan bir Flutter plugin'i.
version: 0.1.0
homepage: https://github.com/kullaniciadi/benim_pluginim
repository: https://github.com/kullaniciadi/benim_pluginim

environment:
  sdk: '>=3.0.0 <4.0.0'
  flutter: '>=3.10.0'

version: 0.1.0 — Konu 53'te öğrendiğimiz semantic versioning kuralları burada da birebir geçerli; 0.x.x sürümü, "henüz kararlı değil, API değişebilir" anlamına gelen bir topluluk kuralıdır (Konu 53'teki 1.0.0'a geçiş, "artık kararlıyım" demenin yoludur).

CHANGELOG.md — Zorunlu Şeffaflık

markdown
## 0.1.0
- İlk sürüm: pil seviyesi okuma desteği eklendi.

## 0.1.1
- Android 14 uyumluluğu düzeltildi.

Bu, Konu 53'te öğrendiğimiz "sürüm notları" kavramının, paket geliştiricileri için olan versiyonu — bir paketi güncelleyen geliştiricinin, neyin değiştiğini görmesi gerekir. pub.dev, bu dosyanın var olmasını ve güncel tutulmasını bekler.

Yayınlama Komutları

bash
flutter pub publish --dry-run   # ÖNCE dene — hataları/uyarıları gerçek yayınlamadan gör
flutter pub publish             # gerçekten yayınla — GERİ ALINAMAZ!

--dry-run, Bölüm 10 Konu 46'da öğrendiğimiz CI pipeline'ındaki "önce test et, sonra deploy et" disiplinin, paket yayınlama bağlamındaki karşılığı. Kritik uyarı: pub.dev'de bir sürüm yayınlandıktan sonra silinemez (sadece "retract" edilip, "bu sürümü kullanmayın" olarak işaretlenebilir) — bu yüzden --dry-run ile önce doğrulamak zorunludur.

Pub Points — pub.dev'in Kalite Skoru

pub.dev, her paketi otomatik olarak puanlar (0-160 arası, birkaç kategoriye bölünmüş) — bu puan, kullanıcıların hangi paketlere güveneceğine karar vermesinde önemli bir sinyal:

  • Dokümantasyon: README.md'nin kalitesi, her public API'nin doc comment (///) içermesi.
  • Platform desteği: Kaç platformda (Android/iOS/Web/Windows/macOS/Linux) çalıştığı beyan edilmiş.
  • Analiz/statik kontrol: Bölüm 10 Konu 46'da öğrendiğimiz flutter analyze'ın temiz geçmesi.
  • Güncel bağımlılıklar: pubspec.yaml'daki paketlerin güncel sürümlere işaret etmesi (tam da bu tutorial boyunca yaptığımız "güncellik taraması" disiplininin, paket ekosistemi seviyesindeki karşılığı!).
  • example/ klasörünün varlığı — yukarıda vurguladığımız gibi.

Pratik gerçek: Bir paket yayınlamadan önce, flutter analyze ve flutter pub publish --dry-run'ı temiz geçirmek, hem kullanıcı güvenini hem pub.dev'deki görünürlüğünü doğrudan etkiler — bu, Bölüm 10'da öğrendiğimiz kalite disiplininin, artık senin sorumluluğun olan bir paket için uygulanmasıdır.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Bir "paket", saf Dart kodu içerir; bir "plugin", Bölüm 9 Konu 40'taki platform channel'lar aracılığıyla native koda bağlanır.
  • lib/paket_adi.dart içindeki export'lar, paketin hangi iç detaylarının dışarıya açık olacağını (Interface Segregation'a benzer bir disiplinle) belirler.
  • Federated plugin mimarisi, Bölüm 7'deki Dependency Inversion prensibini paket seviyesinde uygular — soyut bir platform_interface paketi, her platform için ayrı, bağımsız implementasyon paketleri tarafından karşılanır.
  • example/ klasörü hem geliştirme hem pub.dev puanlaması için neredeyse zorunludur.
  • Yayınlama, semantic versioning (Konu 53) ve güncel CHANGELOG.md gerektirir; --dry-run ile önce doğrulamak, gerçek yayınlamanın geri alınamaz olması nedeniyle kritiktir.
  • Pub Points, dokümantasyon, platform desteği, temiz analiz ve güncel bağımlılıklar gibi kriterlere göre otomatik hesaplanır.

📝 Ödevler

  • [ ] flutter create --template=package ile basit bir yardımcı paket oluştur (örn. bir tarih biçimlendirme fonksiyonu), export ile dışarıya aç, en az bir unit test (Bölüm 10 Konu 45) yaz.
  • [ ] Paketine bir example/ klasörü ekle, paketi gerçekten kullanan çalıştırılabilir bir uygulama yaz.
  • [ ] README.md ve CHANGELOG.md'yi doldur, flutter pub publish --dry-run çalıştırıp çıkan uyarıları (varsa) düzelt.
  • [ ] Kendi cümlelerinle, "federated plugin mimarisinin, Bölüm 7'de öğrendiğimiz Dependency Inversion prensibiyle nasıl aynı fikri paylaştığını" açıkla.
  • [ ] pub.dev'deki popüler bir paketin (örn. http veya provider) sayfasına git, Pub Points bölümünü incele, hangi kriterlerde tam puan aldığını gözlemle.

Sıradaki konu: Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)