---
title: 'Uygulama İçi Satın Alma ve Reklam'
source: 'https://academia.sh/tr/kurslar/android-servisler/uygulama-ici-satin-alma-ve-reklam'
course: 'Platform Servisleri ve Tümleştirmeler'
language: tr
updated: '2026-10-21T05:02:41+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Satın alma güncellemesinin onaylanana kadar yeniden teslim edildiğini ölçer'
    - 'Onaylanan satın almanın bir kez ulaştığını gösterir'
    - 'Geri ödenen satın almanın kayıp olduğunu ölçer'
    - 'Kurs boyunca ölçülen 14 dersin teslimini karşılaştırır'
---

# Uygulama İçi Satın Alma ve Reklam

Uygulama içi satın almada onaylanmayan satın alma, platform satın almaları her sorguladığında yeniden teslim edilir. Ders onaylanmayan satın almanın yinelenen, onaylananın birebir ulaşmasını ve geri ödenen satın almanın kayıp olmasını ölçer; ardından 14 dersin teslimini tek tabloda toplar.

Önceki derste son değer kazandı ve eski değer ezildi. Satın alma tersini yapar: platform bir satın almayı uygulamaya bildirir ve uygulama onu onaylayana kadar aynı güncellemeyi yeniden verir. Soru kursun sorusudur: **gönderilen bu olay alıcıya kaç kopya olarak ulaştı?** Burada olay bir satın alma güncellemesidir, alıcı uygulamanın satın almayı işleyen kodudur.

```kotlin
// Arrival.kt — gonderilen bir olayin aliciya kac kopya olarak ulastigini siniflandirir
class Signal(val key: String, val seq: Int)

class Arrival(val label: String, val sent: Signal, received: List<Signal>) {
    val copies: Int = received.count { it.seq == sent.seq }
    val verdict: String = when {
        copies > 1 -> "yinelenen"
        copies == 1 -> "birebir"
        received.any { it.key == sent.key && it.seq > sent.seq } -> "ezilen"
        else -> "kayip"
    }

    fun line() {
        println("$label: anahtar=${sent.key} | kopya=$copies -> $verdict")
    }
}

fun countArrivals(arrivals: List<Arrival>) {
    for (name in listOf("birebir", "yinelenen", "ezilen", "kayip")) {
        println("$name: ${arrivals.count { it.verdict == name }}")
    }
}
```

## Satın Alma ve Onaylama

Uygulama içi satın alma (in-app purchase), kullanıcının uygulama içinde uygulama mağazası üzerinden ödeme yapmasıdır. Ödeme sonucu uygulamaya bir güncelleme olarak gelir. **Onaylama** (acknowledgement), uygulamanın "bu satın almayı işledim, yeni bir ürün verdim" demesidir. Onaylanmayan satın alma işlenmemiş sayılır ve uygulama satın almaları her sorguladığında platform onu yeniden döndürür.

Platformda onay, faturalama kitaplığının istemci sınıfına yapılan bir çağrıdır.

```kotlin
// Platform kodu: BillingClient
val params = AcknowledgePurchaseParams.newBuilder()
    .setPurchaseToken(purchase.purchaseToken)
    .build()
grantItem(purchase)
billingClient.acknowledgePurchase(params) { result ->
    if (result.responseCode != BillingClient.BillingResponseCode.OK) retryAcknowledge(purchase)
}
```

Bu parça platform kodudur ve burada çıktı, süre ya da sayı iddia etmiyoruz. Model, platformun bu kuralını kurar; model platformun kendisi değildir. Modelde onay, bir sıra numarasının kümesine girmesidir; yeniden teslim, onaylanmamış satın almaları listeye yeniden eklemektir; platformun satın almaları sorgulaması modelde bir açılışla temsil edilir.

```kotlin
// Billing.kt — onaylanmayan satin alma her acilista yeniden teslim edilir
fun redeliver(purchases: List<Signal>, acknowledged: Set<Int>, opens: Int): List<Signal> =
    (1..opens).flatMap { open ->
        if (open == 1) purchases else purchases.filter { it.seq !in acknowledged }
    }

fun expire(received: List<Signal>, refunded: Set<Int>): List<Signal> =
    received.filter { it.seq !in refunded }
```

```kotlin
// Probe.kt — gonderilen satin almalar icin uygulamanin isledigi listeyi alici sayar
fun probe(sent: List<Signal>, received: List<Signal>): List<Arrival> =
    sent.mapIndexed { i, s -> Arrival("olay-${i + 1}", s, received) }
```

**GD1.** Model, ilk açılışta her satın almanın bir kez teslim edildiğini varsayar. Platformda teslim, uygulama çalışırken de gelebilir ve açılış sayısı gerçek kullanımda değişir.

## Onaylanmayan Satın Alma

Üç satın alma yapılır ve uygulama hiçbirini onaylamaz. Uygulama iki kez açılır.

```kotlin
// Main.kt — onaylanmayan satin alma her acilista yeniden teslim edilir
fun main() {
    val coins = Signal("satin.jeton", 1)
    val premium = Signal("satin.premium", 2)
    val adFree = Signal("satin.reklamsiz", 3)
    val sent = listOf(coins, premium, adFree)
    val arrivals = probe(sent, redeliver(sent, emptySet(), 2))
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
```

```text
olay-1: anahtar=satin.jeton | kopya=2 -> yinelenen
olay-2: anahtar=satin.premium | kopya=2 -> yinelenen
olay-3: anahtar=satin.reklamsiz | kopya=2 -> yinelenen
birebir: 0
yinelenen: 3
ezilen: 0
kayip: 0
```

Bu dersin teslimi: yinelenen. Üç satın almanın üçü de iki kopya olarak ulaştı. Önceki derslerde yinelenen, kaybolan bir yanıttan ya da bir döndürmeden doğuyordu; burada yineleme platformun kuralıdır: platform onaylanmamış satın almayı her sorguladığında yeniden döndürür ve bu onay gelene kadar sürer. M30/K05'ten ayrım: orada yinelenen isteği etkisiz kılmak ve sonucu tek yapmak ölçülüyordu; bu kurs sonucu değil kopya sayısını ölçer. Satın almayı tekilleştiren ya da etkisiz işleyen bir alıcı da yinelenen olay almıştır.

## Onaylama Zinciri Keser

Aynı üç satın alma yapılır, ama uygulama ilk ikisini onaylar.

```kotlin
// Main.kt — onaylanan satin alma bir kez, onaylanmayan her acilista ulasir
fun main() {
    val coins = Signal("satin.jeton", 1)
    val premium = Signal("satin.premium", 2)
    val adFree = Signal("satin.reklamsiz", 3)
    val sent = listOf(coins, premium, adFree)
    val arrivals = probe(sent, redeliver(sent, setOf(1, 2), 2))
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
```

```text
olay-1: anahtar=satin.jeton | kopya=1 -> birebir
olay-2: anahtar=satin.premium | kopya=1 -> birebir
olay-3: anahtar=satin.reklamsiz | kopya=2 -> yinelenen
birebir: 2
yinelenen: 1
ezilen: 0
kayip: 0
```

Onaylanan iki satın alma ilk açılıştan sonra gelmedi ve birebir sayıldı. Onaylanmayan üçüncü satın alma ikinci açılışta yine geldi. Kural nedeni görmez: üçüncünün işlenmediğini mi yoksa onayın kaybolduğunu mu ayırt etmez, yalnızca iki kopyanın ulaştığını görür.

Bu davranış korumadır. Onaylanmayan satın alma, kullanıcının parasını almış ama ürünü verilmemiş bir durumdur; yeniden teslim, uygulamanın ürünü vermesi için ikinci şanstır. Bedeli kopyadır: ürünü veren kod, aynı satın almayı iki kez görmeye hazır olmalıdır.

## Abonelik Yenilemesi

Abonelik, aynı ürünün dönem dönem yenilenmesidir. Her yenileme yeni bir satın alma güncellemesidir ve kendi sıra numarasını taşır. Yenileme eskinin yerini almaz; çünkü onaylanmamış eski dönem hâlâ yeniden teslim edilir.

```kotlin
// Main.kt — onaylanmayan abonelik donemleri eskiyi ezmez
fun main() {
    val first = Signal("abonelik.pro", 1)
    val second = Signal("abonelik.pro", 2)
    val third = Signal("abonelik.pro", 3)
    val sent = listOf(first, second, third)
    val arrivals = probe(sent, redeliver(sent, setOf(1), 2))
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
```

```text
olay-1: anahtar=abonelik.pro | kopya=1 -> birebir
olay-2: anahtar=abonelik.pro | kopya=2 -> yinelenen
olay-3: anahtar=abonelik.pro | kopya=2 -> yinelenen
birebir: 1
yinelenen: 2
ezilen: 0
kayip: 0
```

İlk dönem onaylandığı için birebir, sonraki iki dönem yinelenen. Aynı anahtarın daha büyük sırası ulaştı ama ezilen oluşmadı, çünkü ezilen için küçük sıranın hiç ulaşmaması gerekir. Önceki derste yapılandırma böyle davranıyordu; abonelikte eski dönem de ulaşmaya devam eder.

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

Yeniden teslim sonsuz sürmez. Onaylanmayan satın alma bir süre sonra geri ödenir ve ürün verilmeden satın alma iptal olur. Süreyi platform belirler; modelde ve bu derste bir sayı yazmıyoruz. Geri ödenen satın almanın güncellemesi artık gelmez.

```kotlin
// Main.kt — geri odenen satin almanin teslimi gelmez
fun main() {
    val coins = Signal("satin.jeton", 1)
    val premium = Signal("satin.premium", 2)
    val adFree = Signal("satin.reklamsiz", 3)
    val theme = Signal("satin.tema", 4)
    val sent = listOf(coins, premium, adFree, theme)
    val received = expire(redeliver(sent, setOf(1), 2), setOf(2, 3))
    val arrivals = probe(sent, received)
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
```

```text
olay-1: anahtar=satin.jeton | kopya=1 -> birebir
olay-2: anahtar=satin.premium | kopya=0 -> kayip
olay-3: anahtar=satin.reklamsiz | kopya=0 -> kayip
olay-4: anahtar=satin.tema | kopya=2 -> yinelenen
birebir: 1
yinelenen: 1
ezilen: 0
kayip: 2
```

İkinci ve üçüncü satın alma geri ödendi ve uygulamaya hiç ulaşmadı; yerlerini alan aynı anahtarlı bir kopya olmadığı için ezilen değil, kayıp yazıldı. Onaylanan birebir, süresi dolmamış onaysız dördüncü yinelenen kaldı. Kayıp burada kullanıcı için kayıp değildir: parası iade edilmiştir. Kural bunu ayırt etmez, yalnız kopyanın ulaşmadığını görür.

**GD2.** Model, geri ödemeyi ilk teslimden önce olmuş sayar. Platformda geri ödeme teslimden sonra da gelebilir; o durumda kopya zaten ulaşmıştır ve ürünün geri alınması ayrı bir iştir.

## Reklam Yerleşimi

Reklam, satın almadan farklı bir gelir yoludur. Uygulama bir yer ayırır ve reklam kitaplığı oraya içeriği yükler. Yükleme sunucudan gelir, başarısız olabilir ve ne zaman biteceği uygulamanın elinde değildir.

```kotlin
// Platform kodu: reklam yerlesimi
val slot = findViewById<FrameLayout>(R.id.reklam_alani)
bannerView.loadAd(request)
slot.addView(bannerView)
```

Bu parça da platform kodudur ve çıktı ya da sayı iddia etmiyoruz. Reklam gösterimini bu derste ölçmüyoruz: gösterimin sayılması reklam ağının tanımına bağlıdır ve modelde karşılığı yoktur. Ölçtüğümüz şey satın alma güncellemesinin kopya sayısıdır.

## Uygulamanın Yapacakları

- **Satın almayı işledikten sonra onaylamak.** Ürün önce verilir, onay sonra gönderilir. Onayı öne almak, süreç ürünü vermeden ölürse kullanıcıyı parası alınmış ama ürünsüz bırakır; ürünü verip hiç onaylamamak ise kopyanın sürmesine yol açar.
- **Satın alma kimliğini kaydetmek.** Aynı satın almanın ikinci kopyası geldiğinde ürün tekrar verilmemelidir. Kimliği kaydeden uygulama kopyayı etkisiz kılar; ölçüm yine de iki kopya sayar.
- **Abonelik dönemlerini ayrı işlemek.** Yeni dönem eskinin yerini almaz; ikisi de ulaşır.
- **Reklam yüklemesinin başarısızlığına hazırlanmak.** Reklam gelmezse ekran boş kalmamalıdır.

## Yaygın Yanılgılar

**Onay çağrısı satın almayı bir kez teslim eder.** Eder, ama yalnız çağrı başarılı olursa. Onay kaybolursa satın alma yine yinelenir.

**Geri ödenen satın alma uygulamada bir iz bırakır.** Bırakmaz. Ölçümde iki satın alma hiç ulaşmadı ve kayıp yazıldı.

**Abonelik yenilemesi eski dönemi ezer.** Ezmez. Onaylanmayan iki dönem yinelenen olarak ulaştı.

**Kayıp her zaman bir hatadır.** Değildir. Geri ödenen satın alma kayıptır ve doğru sonuçtur.

## Özet

- Bu dersin teslimi: yinelenen. Onaylanmayan üç satın alma, platform onları yeniden sorguladığında (modelde ikinci açılış) yeniden teslim edildi: yinelenen 3.
- Onaylanan satın alma bir kez ulaşır. İki onaylı, bir onaysız satın almada birebir 2, yinelenen 1 çıktı.
- Abonelik yenilemesi eski dönemi ezmez. Birebir 1, yinelenen 2.
- Geri ödenen satın alma kayıp olur: birebir 1, yinelenen 1, kayıp 2.
- Satın almayı tekilleştiren alıcı da yinelenen olay alır; kurs sonucu değil kopya sayısını ölçer.
- Reklam yerleşimi platform kodudur ve bu derste ölçülmez.

## Kurs Kapanışı

Kurs 14 derste aynı soruyu sordu: gönderilen bu olay alıcıya kaç kopya olarak ulaştı? Her dersin teslimi o dersin `## Özet` bölümündeki ilk maddedir; sınırlayıcı ölçüm sütunundaki sayılar kaynak dersin çıktısında görünür.

| Ders | Ölçülen olay | Teslim | Sınırlayıcı ölçüm |
|---|---|---|---|
| Bildirimler | kullanıcı bildirimi | kayıp | aynı kimlikli ikinci kullanıcı bildirimi birincinin yerini alır: ezilen 1 |
| Bulut Mesajlaşma | sunucudan gelen ileti | ezilen | daraltma anahtarı taşımayan iletiler: birebir 4, ezilen 1 |
| Konum ve Haritalar | konum güncellemesi | ezilen | izin geri alınınca sonrakiler gelmez: kayıp 3 |
| Kamera ve Medya | yakalanan fotoğraf | birebir | iki dokunuş iki ayrı sıra: birebir 3 |
| Sensörler | sensör okuması | ezilen | dinleyici kaldırılınca okumalar kesilir: kayıp 2 |
| Derin Bağlantılar ve Kısayollar | derin bağlantı | yinelenen | işaret bellekte kalırsa yinelenen 2 |
| Pencere Öğeleri | pencere öğesi güncellemesi | ezilen | kaldırılan öğeye güncelleme gelmez: kayıp 2 |
| Şifreli Depolama ve Anahtar Deposu | saklanan sır | kayıp | yeniden yazılan sır eskiyi ezer: ezilen 1, kayıp 1 |
| Ağ Güvenliği Yapılandırması | giden ağ isteği | kayıp | yeniden gönderilen istek ilkini ezer: ezilen 1, kayıp 1 |
| Kimlik Doğrulama Akışları | belirteç yenilemesi | yinelenen | tek uçuş ikinci yenilemeyi düşürür: kayıp 1 |
| Uygulama İmzalama | uygulama sürümü | birebir | farklı anahtarlı sürümler: birebir 1, kayıp 3 |
| Analitik ve Çökme Raporlama | analitik olayı | yinelenen | kuyruk dolunca eski olaylar düşer: kayıp 2 |
| Uzaktan Yapılandırma | yapılandırma değeri | ezilen | etkinleşmeyen değer: birebir 1, kayıp 2 |
| Uygulama İçi Satın Alma ve Reklam | satın alma güncellemesi | yinelenen | geri ödenen satın alma: kayıp 2 |

14 dersin 2'si birebir, 4'ü yinelenen, 5'i ezilen, 3'ü kayıp teslimle kapanır. Açılış dersindeki çekirdeğin dağılımı başkadır: sekiz olay 3 birebir, 1 yinelenen, 2 ezilen, 2 kayıp çıktı. İki dağılım aynı şeyi saymaz; çekirdek sekiz olayı, tablo on dört dersi sayar.

Sıradaki kurs M31/K06, Test, Başarım ve Dağıtım konu alanına geçer.
