---
title: 'Paket Yönetimi'
source: 'https://academia.sh/tr/kurslar/flutter/paket-yonetimi'
course: Flutter
language: tr
updated: '2026-10-21T05:02:53+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Paket deposunu, bağımlılığı, sürüm kısıtını ve kilit dosyasını birbirinden ayırır'
    - 'Sürüm kısıtı ile düzen kısıtının ayrı kavramlar olduğunu söyler'
    - 'Bir paketin iki sürümünün aynı bileşen için verdiği varsayılan genişliği ölçülen kayıtla karşılaştırır'
    - 'Sürüm yükseltmesinin düzen kuralını değil yalnız bileşenin isteğini değiştirdiğini açıklar'
---

# Paket Yönetimi

Bir uygulama başkalarının yazdığı paketlerle büyür. Ders paket deposunu, sürüm kısıtını ve kilit dosyasını anlatır; bir paketin yeni sürümünün bileşen genişliğini nasıl etkilediğini ölçer.

Önceki ders uygulamanın kendi ağacını hedefledi. Ama bir uygulama yalnız kendi kodundan oluşmaz: derecelendirme çubuğu, görsel önbelleği ya da bir tarih seçici başkalarının yazdığı paketlerden gelir. Bir paketin yeni sürümü çıktığında uygulamada ne değişir? Bu ders önce paket düzeninin dört parçasını sıralar, sonra bir sürüm yükseltmesinin bir bileşenin genişliğine nasıl yansıdığını ölçer.

## Dört Parça

**Paket deposu**, paketlerin sürümleriyle birlikte yayımlandığı ve araçların onları indirdiği ortak yerdir. **Bağımlılık**, uygulamanın bir pakete ihtiyaç duyduğunu söyleyen bildirimdir. **Sürüm kısıtı**, bağımlılığın hangi sürümlerle kabul edileceğini bir aralık olarak yazar. **Kilit dosyası** ise çözümlemenin sonucunu saklar: araç bir kez hangi sürümü seçtiyse onu kaydeder ve sonraki kurulumlar aynı sürümü getirir.

Çerçevenin belgesine göre bir uygulamanın bildirimi `pubspec.yaml` dosyasıdır ve çözülmüş sürümler `pubspec.lock` dosyasında durur. Belge, uygulamalarda kilit dosyasının sürüm denetimine eklenmesini önerir; böylece her geliştirici ve her derleme aynı sürümlerle çalışır.

## Ölçülen Katman

Kursun her dersi aynı düz Dart modelini kullanır. Model bir bileşen ağacına ekran genişliğini verir ve her düğümün genişliğini kimin belirlediğini dört adla kaydeder. Aşağıdaki dosya çıktı üretmez; ölçülen bloklar onu içe alır.

```dart
// sizing.dart — bir bilesenin genisligini kimin belirledigini siniflandirir
const sizings = ['dayatilan', 'secilen', 'kirpilan', 'esnetilen'];

class Limit {
  final int min;
  final int? max; // null: sinirsiz
  const Limit(this.min, this.max);

  bool get tight => max == min;
  Limit loosen() => Limit(0, max);
  Limit deflate(int by) => Limit(_floor(min - by), max == null ? null : _floor(max! - by));
  String bounds() => '$min..${max ?? 'sonsuz'}';
}

int _floor(int value) => value < 0 ? 0 : value;

class Part {
  final String kind;
  final String name;
  final int? width; // null: alabildigi kadar genis
  final List<Part> children;
  final int factor;
  final bool tightFlex;
  const Part(this.kind, this.name, this.width, this.children,
      {this.factor = 0, this.tightFlex = true});
}

Part leaf(String name, int width) => Part('leaf', name, width, const []);
Part fill(String name) => Part('leaf', name, null, const []);
Part pad(String name, int padding, Part child) => Part('pad', name, padding, [child]);
Part center(String name, Part child) => Part('center', name, null, [child]);
Part fixed(String name, int width, Part child) => Part('fixed', name, width, [child]);
Part column(String name, List<Part> children) => Part('column', name, null, children);
Part row(String name, List<Part> children) => Part('row', name, null, children);
Part flex(String name, int factor, Part child, {bool tight = true}) =>
    Part('flex', name, null, [child], factor: factor, tightFlex: tight);

class Sizing {
  final String sizing;
  final String path;
  final int width;
  final Limit limit;
  const Sizing(this.sizing, this.path, this.width, this.limit);
}

Sizing classify(String path, int? desire, Limit limit) {
  if (limit.tight) return Sizing('dayatilan', path, limit.min, limit);
  if (desire == null) {
    return limit.max == null
        ? Sizing('kirpilan', path, limit.min, limit)
        : Sizing('esnetilen', path, limit.max!, limit);
  }
  if (desire < limit.min) return Sizing('kirpilan', path, limit.min, limit);
  if (limit.max != null && desire > limit.max!) {
    return Sizing('kirpilan', path, limit.max!, limit);
  }
  return Sizing('secilen', path, desire, limit);
}

int layout(Part part, Limit limit, List<Sizing> log, [String path = '']) {
  final here = '$path/${part.name}';
  final below = <Sizing>[];
  if (part.kind == 'fixed') {
    final own = classify(here, part.width, limit);
    layout(part.children.first, Limit(own.width, own.width), below, here);
    log..add(own)..addAll(below);
    return own.width;
  }
  int? desire;
  switch (part.kind) {
    case 'leaf':
      desire = part.width;
    case 'pad':
      final space = 2 * part.width!;
      desire = layout(part.children.first, limit.deflate(space), below, here) + space;
    case 'center':
      final inner = layout(part.children.first, limit.loosen(), below, here);
      desire = limit.max == null ? inner : null;
    case 'flex':
      desire = layout(part.children.first, limit, below, here);
    case 'column':
      var widest = 0;
      for (final child in part.children) {
        final width = layout(child, limit.loosen(), below, here);
        if (width > widest) widest = width;
      }
      desire = widest;
    case 'row':
      final logs = [for (final _ in part.children) <Sizing>[]];
      final bounded = limit.max != null;
      var used = 0;
      var factors = 0;
      for (var i = 0; i < part.children.length; i++) {
        final child = part.children[i];
        if (child.kind == 'flex' && bounded) {
          factors += child.factor;
        } else {
          used += layout(child, const Limit(0, null), logs[i], here);
        }
      }
      final left = bounded ? _floor(limit.max! - used) : 0;
      var given = 0;
      var seen = 0;
      for (var i = 0; i < part.children.length; i++) {
        final child = part.children[i];
        if (child.kind != 'flex' || !bounded) continue;
        seen += child.factor;
        final share = (seen == factors ? left : left * seen ~/ factors) - given;
        given += share;
        final room = child.tightFlex ? Limit(share, share) : Limit(0, share);
        used += layout(child, room, logs[i], here);
      }
      for (final entries in logs) {
        below.addAll(entries);
      }
      desire = bounded ? null : used;
  }
  final own = classify(here, desire, limit);
  log..add(own)..addAll(below);
  return own.width;
}

List<Sizing> measure(Part root, int screen) {
  final log = <Sizing>[];
  layout(root, Limit(screen, screen), log);
  return log;
}

void printSizes(List<Sizing> log) {
  for (final entry in log) {
    print('${entry.sizing}: ${entry.path} genislik=${entry.width} kisit=${entry.limit.bounds()}');
  }
}

void countSizings(List<Sizing> log) {
  for (final name in sizings) {
    print('$name: ${log.where((entry) => entry.sizing == name).length}');
  }
  print('ebeveyn: ${log.where((entry) => entry.sizing != 'secilen').length}');
}
```

Bu derste model, bu boyutlanmanın kuralını kurar; model çerçevenin kendisi değildir. Modelde bir paket sürümü, bir bileşenin varsayılan genişliğini veren bir sayıdır. Model paket çözümlemesini, sürüm aralıklarını ve indirmeyi taşımaz.

## Bildirim

Aşağıdaki parça bildirimdeki bağımlılığı gösterir. Paket adı kurguseldir.

```yaml
# Platform kodu: paket bildirimi
dependencies:
  ornek_paket: ^1.3.0
```

`^1.3.0`, sürüm 1.3.0 ve onunla uyumlu sonraki sürümleri kabul eder. Bu bir sürüm kısıtıdır. Sürüm kısıtı ile düzen kısıtı iki ayrı şeydir: birincisi hangi paket sürümünün kurulacağını, ikincisi bir bileşenin hangi genişlik aralığında ölçüleceğini söyler ve aralarında bir bağ yoktur.

## Paketin İki Sürümü

Kurgusal paketin derecelendirme bileşeni sürüm 1'de 96 birim, sürüm 2'de 112 birim varsayılan genişlikle gelir. Uygulama bileşeni bir başlığın altına koyar ve genişliği kendisi vermez. Ağaç, sürümü alan bir işlevle kurulur.

```dart
// package_model.dart — paketin iki surumunun verdigi varsayilan genislik
import 'sizing.dart';

int ratingWidth(int version) => version == 1 ? 96 : 112;

Part buildRating(int version) => pad('Screen', 16, column('Body', [
      leaf('Title', 120),
      leaf('Rating', ratingWidth(version)),
    ]));
```

## Eski Sürüm

İlk ölçüm sürüm 1 için tüm kaydı basar. Ekran 360 birimdir.

```dart
// main.dart
import 'sizing.dart';
import 'package_model.dart';

void main() {
  final log = measure(buildRating(1), 360);
  printSizes(log);
}
```

```text
dayatilan: /Screen genislik=360 kisit=360..360
dayatilan: /Screen/Body genislik=328 kisit=328..328
secilen: /Screen/Body/Title genislik=120 kisit=0..328
secilen: /Screen/Body/Rating genislik=96 kisit=0..328
```

Başlık 120, derecelendirme 96 birim ister ve ikisi de aldığı 0 ile 328 arasındaki aralığa sığar. İkisinin genişliğini de kendileri seçmiştir.

## Yeni Sürüm

Şimdi aynı ağaç sürüm 2 ile kurulur. Uygulamanın kodunda hiçbir şey değişmemiştir; yalnız kilit dosyası yeni sürümü gösterir. Aşağıdaki blok iki sürümü yan yana ölçer ve yalnız derecelendirmenin satırını basar.

```dart
// main.dart
import 'sizing.dart';
import 'package_model.dart';

void main() {
  for (final version in [1, 2]) {
    print('surum=$version');
    final log = measure(buildRating(version), 360);
    printSizes(log.where((entry) => entry.path == '/Screen/Body/Rating').toList());
  }
}
```

```text
surum=1
secilen: /Screen/Body/Rating genislik=96 kisit=0..328
surum=2
secilen: /Screen/Body/Rating genislik=112 kisit=0..328
```

Yeni sürümde derecelendirme 112 birimdir ve yine seçilendir. Aldığı kısıt aynıdır: `0..328`. Değişen tek şey bileşenin kendi isteğidir. Sürüm yükseltmesi, ağacın hiçbir düğümünün kısıtını değiştirmedi.

## Bu Değişiklik Nereye Ulaşıyor

M12/K02'de bir kod değişikliğinin nereye yayıldığı sorulurdu: değişen bir parçaya kimler bağlı, etki nereye ulaşıyor. Boyutlanmada yayılım sorusu yoktur. Paketin sürümü değişince düzen kuralı bunu bilmez; kural yalnız yeni isteği görür, o isteğin hangi sürümden geldiğini görmez. Bunu sayımla da doğrulayabiliriz.

```dart
// main.dart
import 'sizing.dart';
import 'package_model.dart';

void main() {
  for (final version in [1, 2]) {
    print('surum=$version');
    countSizings(measure(buildRating(version), 360));
  }
}
```

```text
surum=1
dayatilan: 2
secilen: 2
kirpilan: 0
esnetilen: 0
ebeveyn: 2
surum=2
dayatilan: 2
secilen: 2
kirpilan: 0
esnetilen: 0
ebeveyn: 2
```

İki sürümün sayımı aynıdır. 360 birimlik ekranda sürüm yükseltmesi hiçbir düğümün sınıfını değiştirmedi.

## Bildirimi Kilitlemek

Kilit dosyası, sürüm kısıtının izin verdiği aralıktan tek bir sürüm seçip saklar. Kilit dosyası yoksa ya da sürüm denetimine eklenmediyse, aynı `^1.3.0` kısıtı farklı zamanlarda farklı sürümler getirebilir. Derecelendirme örneğinde bu, aynı kodun bir derlemede 96, ötekinde 112 birimlik bir bileşen göstermesi demektir. Yani kilit dosyası yalnız bir derleme kolaylığı değil, ekranın aynı görünmesinin de koşuludur.

Bu, sürüm kısıtı ile düzen kısıtının ayrı olduğu kuralıyla çelişmez. Kilit dosyası hangi sürümün kurulacağını sabitler; sürüm kurulduktan sonra bileşenin isteği artık bir sayıdır ve ağaçtaki yerinde ölçülür.

## Yaygın Yanılgı

**Paketi yükseltmek ekrandaki düzeni bozar ya da düzeltir.** Yükseltme düzen kuralını değiştirmez; yalnız bileşenin isteğini değiştirir. Ekranın ne olacağını sonra yine kısıt belirler. İstek aralığa sığıyorsa sonuç bir şey fark ettirmez, sığmıyorsa kırpılır. Sonraki bölümdeki dar ekran ölçümü bu ikinciyi gösterir.

## Dar Ekranda

Ekran 130 birim genişliğine iner. İç boşluk iki yandan 16'şar birim düşer; gövdeye 98 birimlik bir aralık kalır. Sürüm 1'in 96 birimlik isteği aralığa sığar, sürüm 2'nin 112 birimlik isteği sığmaz.

```dart
// main.dart
import 'sizing.dart';
import 'package_model.dart';

void main() {
  for (final version in [1, 2]) {
    print('surum=$version');
    final log = measure(buildRating(version), 130);
    printSizes(log.where((entry) => entry.path == '/Screen/Body/Rating').toList());
  }
}
```

```text
surum=1
secilen: /Screen/Body/Rating genislik=96 kisit=0..98
surum=2
kirpilan: /Screen/Body/Rating genislik=98 kisit=0..98
```

Aynı yeni sürüm, 130 birimlik ekranda kırpılan olur. Ağaç aynı, kural aynı; yalnız isteğin aralığa sığıp sığmadığı değişti. Sürüm yükseltmesinin uygulama için riski buradadır: istek büyüyünce dar bir ekranda kırpılma görülebilir.

## Sınırlayıcı Ölçüm

Son ölçüm iki sürümü yalnız sınıf adıyla karşılaştırır. Ekran 360 birimdir.

```dart
// main.dart
import 'sizing.dart';
import 'package_model.dart';

void main() {
  for (final version in [1, 2]) {
    final log = measure(buildRating(version), 360);
    final entry = log.firstWhere((item) => item.path == '/Screen/Body/Rating');
    print('surum=$version ${entry.sizing}');
  }
}
```

```text
surum=1 secilen
surum=2 secilen
```

Odak düğüm yeni sürümdeki `/Screen/Body/Rating`. İki sürümde de seçilendir: kural yalnız yeni isteği görür, hangi sürümden geldiğini görmez. Dersin boyutlanması bu yüzden seçilendir.

**KY1.** Model, bu boyutlanmanın kuralını kurar; model çerçevenin kendisi değildir. Modelde paket sürümü bir tamsayı işlevidir. Gerçek paket çözümlemesi, sürüm aralıklarının kesişimi, kilit dosyasının üretilmesi ve paket deposundan indirme modelde yoktur. Bir paketin gerçek varsayılan genişliği ise o paketin kendi belgesindedir.

## Özet

- Bu dersin boyutlanması: seçilen. Yeni sürümdeki derecelendirme, 360 birimlik ekranda 112 birim ister ve 0..328 aralığında kendi genişliğini seçer.
- Paket deposu paketleri yayımlar, bağımlılık bildirir, sürüm kısıtı aralık yazar, kilit dosyası seçilen sürümü saklar.
- Sürüm kısıtı hangi paket sürümünün kurulacağını, düzen kısıtı bir bileşenin hangi genişlik aralığında ölçüleceğini söyler; ikisi ayrıdır.
- Sürüm yükseltmesi düğümlerin kısıtını değiştirmedi; yalnız bileşenin isteğini 96'dan 112'ye çıkardı.
- Kural yalnız yeni isteği görür: 360 birimde iki sürüm de seçilen, 130 birimde yeni sürüm kırpılan çıkar.

## Sonraki Adım

Kalite, test, araç, başarım ve paketler yerine oturdu. Sıradaki ve konunun son dersi, `Derleme ve Yayın`, aynı uygulamanın iki hedefe, telefona ve tablete, birlikte yayımlandığında aynı bir görselin iki hedefte de kırpılıp kırpılmadığına bakar.
