---
title: 'Uygulama Paketi Biçimleri'
source: 'https://academia.sh/tr/kurslar/android-uretim/uygulama-paketi-bicimleri'
course: 'Test, Başarım ve Dağıtım'
language: tr
updated: '2026-10-21T05:02:42+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Uygulama paketi, APK ve bölünmüş paket arasındaki farkı yayın ve kurulum açısından ayırır'
    - 'ABI ve ekran yoğunluğunun bir aygıta hangi dosyaların ineceğini nasıl belirlediğini açıklar'
    - 'Bir yapılandırmaya inen dosya sayısını bütçeyle karşılaştırıp aşımı içinde, azında, çoğunda ya da hepsinde diye sınıflar'
    - 'Evrensel paketin her yapılandırmaya bütün dosyaları indirdiğini, bölünmüş paketin ise yalnız eşleşenleri indirdiğini ölçer'
---

# Uygulama Paketi Biçimleri

Uygulama paketi, APK ve bölünmüş paket aygıta hangi dosyaların indiğini belirler. Ders bir yapılandırmaya inen dosya sayısını bütçeyle karşılaştırır ve evrensel paketin her yapılandırmada bütçeyi aştığını gösterir.

Önceki ders kod küçültmeyi ve karartmayı ölçtü: koruma kuralından sonra modülde kaç sınıf kaldı. O iş derlemenin içindeydi. Bu ders derlemenin çıktısına bakıyor: derleme bittiğinde ortaya çıkan paket bir aygıta ulaşırken kaç dosya taşıyor? Kursun sorusu değişmedi: **bu ölçüm bütçesini kaç örnekte aşıyor?** Ölçüm bir sayıdır, bütçe o sayının sınırıdır, örnek ise aynı ölçümün farklı bir girdide alınmış hâlidir. Sınırı kesin olarak aşan örnekler sayılır ve sayı dört yanıttan birini verir: **içinde**, **azında**, **çoğunda**, **hepsinde**.

```kotlin
// Overrun.kt — bir olcumun butcesini kac ornekte astigini siniflandirir
class Budget(val name: String, val limit: Int)

class Overrun(val label: String, val budget: Budget, samples: List<Int>) {
    val total: Int = samples.size
    val over: Int = samples.count { it > budget.limit }
    val verdict: String = when {
        over == 0 -> "icinde"
        over == total -> "hepsinde"
        over * 2 < total -> "azinda"
        else -> "cogunda"
    }

    fun line() {
        println("$label: butce=${budget.name}<=${budget.limit} | asan=$over/$total -> $verdict")
    }
}

fun countOverruns(overruns: List<Overrun>) {
    for (name in listOf("icinde", "azinda", "cogunda", "hepsinde")) {
        println("$name: ${overruns.count { it.verdict == name }}")
    }
}
```

`Overrun` bütçeyi aşan örnekleri sayar. Hiçbiri aşmıyorsa yanıt içinde, hepsi aşıyorsa hepsinde, yarıdan azı aşıyorsa azında, geri kalan her durum çoğunda olur; tam yarı çoğundadır. Kural sayıyı görür, aşımın büyüklüğünü ve nedenini görmez. Kursun açılış dersi dört ölçümü bu kuralla sınıflayıp her yanıtı bir kez gördü; bu ders o dağılıma yalnız atıf yapar.

## Üç Biçim, Bir Yayın

Android'de üç ayrı şeye paket denir ve karışmaları sık görülür. APK, aygıta kurulan dosyadır. Uygulama paketi (app bundle), uygulama mağazasına yüklenen yayın biçimidir; kendisi aygıta kurulmaz. Mağaza bu paketten her aygıt yapılandırması için bölünmüş paket (split APK) üretir: aygıtın işlemci mimarisine (ABI) uyan yerel kitaplıkları, ekran yoğunluğuna uyan kaynakları ve ortak kodu içeren küçük bir dosya kümesi. Evrensel paket (universal APK) ise bu seçimin hiç yapılmadığı biçimdir: tek dosya kümesi bütün ABI'lerin kitaplıklarını ve bütün yoğunlukların kaynaklarını taşır, her aygıta aynı küme iner.

Yapılandırmaya göre bölmenin üç ekseni vardır: dil, ekran yoğunluğu ve ABI. Bunları derleme sisteminde modül derleme betiği açar ya da kapatır. Betik parçası şöyle görünür.

```kotlin
// Platform kodu: modül derleme betiği
android {
    bundle {
        language { enableSplit = true }
        density { enableSplit = true }
        abi { enableSplit = true }
    }
}
```

Bu parça platform kodudur; burada çıktı, süre ya da boyut iddia etmiyoruz. Model, bu ölçümün kuralını kurar; model aracın kendisi değildir. Modelde paket bir dosya listesidir, aygıt yapılandırması bir ABI ve bir yoğunluk çiftidir.

Betikteki üç satırın her biri ayrı bir soruya karşılık gelir. `abi` ekseni açıkken yerel kitaplıklar işlemci mimarisine göre ayrı dosyalara bölünür; aygıt kendi mimarisine uyan kitaplığı alır, ötekileri almaz. `density` ekseni açıkken ekran yoğunluğuna bağlı kaynaklar aynı şekilde ayrılır. `language` ekseni açıkken dil kaynakları ayrılır ve aygıt yalnız kendi dillerini ister. Eksenlerden biri kapalıysa o eksenin dosyaları ayrılmadan ortak parçada kalır ve her aygıta iner. Ders bu betiği çalıştırmaz; betiğin ifade ettiği ayrımı modelde bir `wants` ilkesine çevirir ve ilkenin sonucunu sayar.

## Dosya Listesi ve Yapılandırma

Aşağıdaki yardımcı dosya paketi kurar. Her `PackageFile` ya bir ABI'ye ya da bir yoğunluğa bağlıdır ya da hiçbirine bağlı değildir. `filesForConfig` bir yapılandırmaya kaç dosyanın ineceğini sayar; hangi dosyanın ineceğine `wants` ilkesi karar verir.

```kotlin
// PackageModel.kt — paket dosyalarini ve bir yapilandirmaya inen dosyalari modeller
class PackageFile(val name: String, val abi: String? = null, val density: String? = null)

class DeviceConfig(val label: String, val abi: String, val density: String)

fun buildPackage(abis: List<String>, densities: List<String>): List<PackageFile> =
    listOf(PackageFile("kod.dex"), PackageFile("yapi.xml")) +
        abis.map { PackageFile("kitaplik-$it.so", abi = it) } +
        densities.map { PackageFile("kaynak-$it.bin", density = it) }

fun samplePackage(): List<PackageFile> =
    buildPackage(listOf("arm64", "arm32", "x86"), listOf("mdpi", "hdpi", "xhdpi", "xxhdpi"))

fun sampleConfigs(): List<DeviceConfig> = listOf(
    DeviceConfig("dar-telefon", "arm32", "mdpi"),
    DeviceConfig("orta-telefon", "arm64", "hdpi"),
    DeviceConfig("genis-telefon", "arm64", "xhdpi"),
    DeviceConfig("tablet", "arm64", "xxhdpi"),
    DeviceConfig("eski-aygit", "arm32", "hdpi"),
    DeviceConfig("emulator", "x86", "xhdpi"),
)

fun filesForConfig(
    files: List<PackageFile>,
    config: DeviceConfig,
    wants: (PackageFile, DeviceConfig) -> Boolean,
): Int = files.count { wants(it, config) }

val everything: (PackageFile, DeviceConfig) -> Boolean = { _, _ -> true }

val matching: (PackageFile, DeviceConfig) -> Boolean = { file, config ->
    (file.abi == null || file.abi == config.abi) && (file.density == null || file.density == config.density)
}
```

Paket dokuz dosyadır: iki ortak dosya, üç ABI kitaplığı, dört yoğunluk kaynağı. Yapılandırma listesi altı örnek verir. `everything` ilkesi yapılandırmaya bakmaz; evrensel paketin tanımı budur. `matching` ilkesi ise yalnız yapılandırmanın ABI'sine ve yoğunluğuna uyan dosyaları ister.

## Evrensel Paket

Bütçeyi beş dosya olarak koyalım. Bu sayı modelin girdisidir: bir platform eşiği ya da mağaza kuralı değildir, dersin soruyu sormak için seçtiği sınırdır. Evrensel paketin altı yapılandırmaya kaç dosya indirdiğini ölçelim.

```kotlin
// Main.kt — evrensel paket her yapilandirmaya butun dosyalari indirir
fun main() {
    val files = samplePackage()
    val samples = sampleConfigs().map { filesForConfig(files, it, everything) }
    println("paket dosyasi: ${files.size}")
    println("inen dosyalar: $samples")
    Overrun("evrensel-paket", Budget("dosya", 5), samples).line()
}
```

```text
paket dosyasi: 9
inen dosyalar: [9, 9, 9, 9, 9, 9]
evrensel-paket: butce=dosya<=5 | asan=6/6 -> hepsinde
```

Altı örneğin altısı da bütçeyi aştı: yanıt **hepsinde**. Bu sonucu kuralın cömert davranmasından değil, ilkenin yapılandırmaya bakmamasından alıyoruz. Dar ekranlı eski bir telefon da geniş bir tablet de dokuz dosya indirdi; `samples` listesi bu yüzden dokuzdan başka bir sayı içermiyor. Yoğunluk kaynaklarının çoğu o aygıt için hiç kullanılmayacak.

**DA1.** Model dosyayı bir iş birimi sayar ve her dosyayı eşit ağırlıkta görür. Gerçekte bir yoğunluk kaynağı dosyası bir ortak kod dosyasından çok farklı bir büyüklükte olabilir; model boyut, sıkıştırma ve indirme koşullarını kurmaz. Dosya sayısı boyutun yerine konmuş bir iş birimidir ve bir bayt ölçümü değildir.

## Bütçe Modelin Girdisidir

Aynı işlevin iki bütçede iki farklı aşım vermesi bir çelişki değildir; ölçünün kendisidir. Bütçeyi dokuza çıkaralım: evrensel paket en fazla dokuz dosya indiriyor, hiçbir örnek bu sınırı kesin olarak aşmaz. Bölünmüş paket için bütçeyi üçe indirelim: dört dosya inen her yapılandırma bu sefer sınırı aşar.

```kotlin
// Main.kt — ayni olcum iki butceyle iki asim verir
fun main() {
    val files = samplePackage()
    val configs = sampleConfigs()
    val loose = Overrun("evrensel-paket", Budget("dosya", 9), configs.map { filesForConfig(files, it, everything) })
    val strict = Overrun("bolunmus-paket", Budget("dosya", 3), configs.map { filesForConfig(files, it, matching) })
    loose.line()
    strict.line()
    countOverruns(listOf(loose, strict))
}
```

```text
evrensel-paket: butce=dosya<=9 | asan=0/6 -> icinde
bolunmus-paket: butce=dosya<=3 | asan=6/6 -> hepsinde
icinde: 1
azinda: 0
cogunda: 0
hepsinde: 1
```

Sınır sınıra eşit olan örneği aşım saymaz: dokuz dosya indiren evrensel paket dokuz bütçesinde içinde kaldı. Bölünmüş paket dört dosya indirdi ve üç bütçesinde hepsinde çıktı. Bu iki sonuç paketin iyi ya da kötü olduğunu söylemez; yalnız bütçeyle sayının karşılaştırıldığını gösterir. Bu yüzden bütçeyi dersin başında koyuyoruz ve gerekçesini söylüyoruz: dosya sayısı bir paket biçimini değil, bir yapılandırmanın indirme işini temsil ediyor.

## Yarım Bölme

Üç ekseni birlikte bölmek zorunlu değildir. Yalnız ABI'ye göre bölen bir paket, yoğunluk kaynaklarının hepsini her aygıta yine de indirir. Modelde bu, ABI'ye uyan ama yoğunluğa bakmayan bir ilkedir.

```kotlin
// Main.kt — yalniz ABI'ye gore bolunen paket yogunluk dosyalarini yine indirir
fun main() {
    val files = samplePackage()
    val abiOnly: (PackageFile, DeviceConfig) -> Boolean = { file, config -> file.abi == null || file.abi == config.abi }
    val samples = sampleConfigs().map { filesForConfig(files, it, abiOnly) }
    println("inen dosyalar: $samples")
    Overrun("yalniz-abi", Budget("dosya", 5), samples).line()
}
```

```text
inen dosyalar: [7, 7, 7, 7, 7, 7]
yalniz-abi: butce=dosya<=5 | asan=6/6 -> hepsinde
```

Her yapılandırma yedi dosya indirdi: iki ortak dosya, tek ABI kitaplığı ve dört yoğunluk kaynağı. Kısmi bölme dokuzu yediye düşürdü ama aşım değişmedi. Kural dokuzun yediden kötü olduğunu görmez; yalnız ikisinin de beşten büyük olduğunu görür.

## Dil Ekseni

Üçüncü eksen dildir ve DA2'de belirteceğimiz gibi ana modelde yoktur. Onu ayrı bir blokta, dosya adıyla taklit edelim: pakete üç dil dosyası ekleyelim ve her aygıta bir ya da iki dil verelim. Dil ekseni açıkken aygıt yalnız kendi dillerinin dosyalarını indirir; ABI ve yoğunluk kuralı `matching` ilkesinde aynı kalır.

```kotlin
// Main.kt — dil ekseni acikken birden fazla dili olan aygit bir dosya daha indirir
fun main() {
    val languages = listOf("tr", "en", "de")
    val files = samplePackage() + languages.map { PackageFile("dil-$it.bin") }
    val deviceLanguages = listOf(
        listOf("tr"), listOf("tr", "en"), listOf("en"),
        listOf("de", "en"), listOf("tr"), listOf("en"),
    )
    val samples = sampleConfigs().mapIndexed { index, config ->
        files.count { file ->
            if (file.name.startsWith("dil-")) file.name.removePrefix("dil-").removeSuffix(".bin") in deviceLanguages[index]
            else matching(file, config)
        }
    }
    println("inen dosyalar: $samples")
    Overrun("dil-ekseni", Budget("dosya", 5), samples).line()
}
```

```text
inen dosyalar: [5, 6, 5, 6, 5, 5]
dil-ekseni: butce=dosya<=5 | asan=2/6 -> azinda
```

Dört dosya ortak parça, ABI kitaplığı ve yoğunluk kaynağından geliyor; bir dil bir dosya, iki dil iki dosya ekliyor. Tek dilli dört aygıt beş dosyada kaldı ve bütçeyi aşmadı. İki dilli iki aygıt altıya çıktı ve aştı. Altı örneğin ikisi aştığı için yanıt **azında**: sayı yarının altında kaldı. Bu sonuç ilginç bir şeyi gösteriyor. Paketi tam bölmek, dosya sayısını aygıttan bağımsız tek bir sayıya indirmiyor; aygıtın kendi özellikleri, burada kaç dil kullandığı, sayıyı oynatıyor. Sınır beşe konduğu için tek bir ek dil bile yanıtı değiştirir.

**DA3.** Dil dosyaları adlarından ayrıştırılıyor (`dil-tr.bin` gibi) ve her dil tek dosyadır. Gerçekte bir dilin kaynakları birden fazla dosyaya yayılabilir; modelde bir dil bir dosyadır.

## Evrensel Paket Neden Var

Evrensel paket yanlış bir seçim değildir; farklı bir bedelle gelen kolaylıktır. Tek dosya olduğu için bir ekip arkadaşına, bir test aygıtına ya da mağaza dışındaki bir dağıtım kanalına olduğu gibi verilebilir ve hangi yapılandırmanın kurulacağı sorusu hiç çıkmaz. Mağazanın bölünmüş paket üretmesi ise mağazanın bu yapılandırma bilgisine sahip olmasına bağlıdır. Bu yüzden iki biçim aynı yayın içinde birlikte yaşar: biri kolay elden ele aktarım, öteki aygıta özgü indirme içindir.

Seçimi pratikte belirleyen soru şudur: paketi kim, hangi yapılandırmaya göre seçecek? Cevap "mağaza, aygıt başına" ise bölünmüş paket doğal olandır. Cevap "kimse, olduğu gibi kurulacak" ise evrensel paket tek yoldur. Ölçüm bu iki durumun bedelini aynı birimle, dosya sayısıyla yan yana koyar.

## Yaygın Yanılgılar

**"Uygulama paketi aygıta kurulur."** Kurulan şey APK'dır. Uygulama paketi mağazaya yüklenir ve mağaza onu yapılandırmaya göre bölünmüş paketlere çevirir. İkisi aynı dosya değildir ve aynı adımda üretilmez.

**"Bölünmüş paket her zaman daha az dosya indirir."** Bölme eksenlerinin hangisinin açık olduğuna bağlıdır. Yarım bölme örneğinde yedi dosya indi, tam bölmede dört. Yalnız ABI ekseni açık bırakılırsa yoğunluk kaynaklarının hepsi yine iner.

**"Bölünmüş paket her aygıta aynı sayıda dosya indirir."** Tam bölünmüş pakette ABI ve yoğunluk kaynakları için bu doğrudur, çünkü her aygıtın bir ABI'si ve bir yoğunluğu vardır. Dil ekseni açılınca doğru olmaktan çıkar: iki dilli aygıt altı, tek dilli aygıt beş dosya indirdi. Aygıtın sahip olduğu değer sayısı arttıkça indirilen dosya sayısı da artar.

**"Evrensel paket yalnızca yanlış bir tercihtir."** Evrensel paket mağaza dışı dağıtımda hâlâ gereklidir; yukarıdaki bölüm bunu gerekçesiyle anlattı. Yanlış olan, bütçesi olan bir mağaza yayınında hangi aygıta hangi dosyanın ineceğini hiç tartmadan evrensel paketi tek yol saymaktır.

**"Dosya sayısı küçüldüyse paket küçüldü."** Bu iki ifade aynı şey değildir. Sayı yapılandırma seçiminin etkisini gösterir; büyüklük için ayrı bir ölçüm gerekir ve bu derste yapılmadı.

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

Bu ölçümün adı sınırlayıcıdır, çünkü dersin sorusuna verilebilecek en iyi yanıtı arar: bütçe aynı, paket aynı, örnekler aynı ve yalnız hangi dosyaların ineceğine karar veren ilke değişiyor. Evrensel paketin hepsinde çıkması paketin bir kusuru olarak okunmasın; ilke yapılandırmaya bakmadığında başka bir sonuç mümkün değildir. Sınırlayıcıyı ayrıca koymamızın nedeni, hepsinde yanıtını gören okurun "bu bütçe hiç tutulamaz" sonucuna varmasını önlemektir. Tutulabildiğini aynı bütçede göstermek, bütçenin gerçekçi olduğunu da kanıtlar.

Yapılandırmaya göre tam bölünmüş paket, her yapılandırmaya yalnız eşleşen dosyaları indirir. Bütçe yine beş dosyadır.

```kotlin
// Main.kt — bolunmus paket her yapilandirmaya yalniz eslesen dosyalari indirir
fun main() {
    val files = samplePackage()
    val samples = sampleConfigs().map { filesForConfig(files, it, matching) }
    println("inen dosyalar: $samples")
    Overrun("bolunmus-paket", Budget("dosya", 5), samples).line()
}
```

```text
inen dosyalar: [4, 4, 4, 4, 4, 4]
bolunmus-paket: butce=dosya<=5 | asan=0/6 -> icinde
```

Aynı paket, aynı altı yapılandırma, aynı bütçe: tek fark ilkedir ve yanıt hepsinde iken içinde oldu. Evrensel paket bu dersin hepsinde örneğiydi; bölünmüş paket onun içinde karşılığı. Sonucu tek başına paketin biçimi belirlemedi: aynı uygulama paketi hangi dosyaların ineceğine karar veren ilkeye göre iki yanıt verdi.

Kuralın bu sonuçta göremediği bir şey var: dosyaların büyüklüğü. Dört küçük dosya ile dört büyük dosya aynı sayılır, dokuz küçük dosya ise dört büyük dosyadan daha az indirme işi olabilir. Model dosya sayısını sayar ve dosya büyüklüğünü kurmaz. Dosya sayısı yalnız yapılandırmaya bağlı seçimin etkisini görünür kılar.

**DA2.** Model yapılandırmayı bir ABI ve bir yoğunluk çifti olarak kurar. Gerçekte dil de bir bölme eksenidir ve bir aygıtın birden fazla dili olabilir; ana modelde dil ekseni yoktur ve yukarıdaki `Dil Ekseni` bölümü onu yalnız bir blokta ayrıca kurar.

## Özet

- Bu dersin aşımı: hepsinde. Evrensel paket altı yapılandırmanın altısında bütçeyi aştı, çünkü ilke yapılandırmaya bakmayıp dokuz dosyanın dokuzunu da indirdi.
- Uygulama paketi mağazaya yüklenen yayın biçimidir; APK aygıta kurulan dosyadır; bölünmüş paket ise bir yapılandırmaya uyan dosya kümesidir.
- Aynı ölçüm bütçeye göre değişti: dokuz bütçesinde evrensel paket içinde, üç bütçesinde bölünmüş paket hepsinde çıktı. Bütçe modelin girdisidir.
- Yalnız ABI'ye göre bölünen paket her yapılandırmaya yedi dosya indirdi ve hepsinde kaldı.
- Dil ekseni açılınca tek dilli aygıtlar beş, iki dilli aygıtlar altı dosya indirdi ve yanıt azında oldu; aygıtın özelliği sayıyı oynatır.
- Yapılandırmaya göre bölünmüş paket her yapılandırmaya dört dosya indirdi ve beş bütçesinde içinde kaldı; kural dosya sayısını görür, büyüklüğünü görmez.

## Sonraki Adım

Bu derste bir derleme aygıta hangi dosyaları indirdi diye saydık. Ama aygıtların hepsi son derlemeyi kullanmıyor: kimi yeni sürümü indirdi, kimi eski sürümde kaldı. Sıradaki ders, `Sürüm Yönetimi`, sekiz aygıtın kurulu sürüm kodunun son sürümden kaç sürüm geride kaldığını ölçer.
