Android'de Takılan Geçiş Reklamını Olay Kayıtlarıyla Yakalamak
Nesim Razon, bağımsız Android geliştiricisi · 2026-11-12
Bir oyuncu, geçiş reklamından sonra oyunun dokunuşlara cevap vermediğini yazdı. Crashlytics'te çökme yoktu, ANR yoktu ve kendi telefonlarımızda tekrar üretemiyorduk. Bu yazı AdMob tam ekran reklamlarının etrafına nasıl küçük bir yaşam döngüsü kaydı eklediğimizi, verinin neye benzediğini ve onunla ne yaptığımızı anlatıyor. Bu bir hata ayıklama hikâyesi; her uygulamaya uyan bir tarif değil.
Yığın izi olmayan şikâyet
Şikâyet, HyperOS'lu ve Android 13 çalıştıran bir Redmi telefondaki tek bir kullanıcıdan geldi. Bölüm sonunda tam ekran bir reklam çıkmış. Reklam bitince oyun normal görünüyormuş ama oyuncuyu dinlemiyormuş. Dokunuşlar sanki başka yere düşüyordu: Play Store paneli kendiliğinden açılıyor, sonraki bölüm düğmesi hiçbir şey yapmıyordu. Oyuncu, aynı türden reklamla bir kez daha yaşadığını söyledi.
Dışarıdan bakınca bu bir donmaya benziyor, ama uygulama donmamıştı. Ana iş parçacığı sağlamdı ve hiçbir şey istisna fırlatmıyordu. Olağan araçların sessiz kalmasının nedeni tam olarak bu.
Çökme raporlama bunu neden göremez
Crashlytics ölümcül istisnaları, istersen ölümcül olmayanları da kaydeder. Takılan bir reklam ikisi de değildir. Reklam SDK'sı kendi aktivitesini ve bir web görünümünü çalıştırır; içerik yanlış davranırsa pencere oyunun üstünde şeffaf bir katman olarak kalabilir. Senin kodun hiç hata vermez. Kullanıcı sadece ona ulaşamaz.
ANR raporları da yardım etmez, çünkü uygulama girdi olaylarına cevap vermeyi sürdürür. Bir şeyin ters gittiğini bilen tek taraf reklam SDK'sıdır ve bize söylemedi. Bu yüzden ilk iş, görünmeyen kısmı görünür kılmaktı: gerçek cihazlarda reklamın ne yaptığını sırayla yazmak.
Burada küçük ama işe yarar bir ayrım var: çökme, uygulamanın durması demektir; takılma ise uygulamanın çalışıp kullanıcının ona erişememesidir. İkincisi için kendi tarafında hiçbir sinyal yoktur. Bir şeyin gözlemlenebilir olması için birinin onu yazması gerekir, yoksa o olay hiç yaşanmamış gibi görünür ve reklam SDK'sı bu kapanış anını bize yazmıyordu.
Fikir: reklamın her aşamasını kaydet
AdMob yükleme ve tam ekran içerik için geri çağrılar verir. Hem geçiş hem ödüllü biçimde her birine küçük bir kaydedici bağladık. Her çağrı, şu parametrelerle ad_event adlı bir Firebase Analytics olayı üretir: format (interstitial ya da rewarded), stage, adapter, code ve ms.
Kodumuzdaki aşamalar loaded, load_failed, shown, impression, clicked, dismissed, show_failed ve bizim icat ettiğimiz bir tane daha: resumed_no_dismiss. Adapter, reklamı sunan aracılık bağdaştırıcısının sınıf adıdır (hangi reklam ağının ya da aracılık katmanının devrede olduğunu gösterir); son 60 karaktere kısaltılır, böylece tek olay hangi reklam kaynağının devrede olduğunu gösterir. Code alanı hatalarda SDK hata kodunu, ms ise reklamın gösterilmesinden bu yana geçen süreyi taşır. Aynı satır Crashlytics'e iz olarak da yazılır; sonradan bir çökme olursa raporu hangi reklam aşamasının önce geldiğini gösterir.
SDK'nın vermediği tek aşama
Her normal reklam bir dismissed geri çağrısıyla biter. Takılan reklam, o çağrının hiç gelmediği durumdur; yani bir geri çağrıdan kaydedemezsin. Yokluğu fark etmen gerekir.
Bunu uygulama yaşam döngüsüyle yaptık. Reklam gösterilince sarmalayıcı biçimini, adaptörünü ve başlangıç zamanını saklar. Sonra genel bir aktivite yaşam döngüsü dinleyicisi onActivityResumed'u izler. Sarmalayıcı hâlâ ekranda reklam olduğunu sanırken kendi aktivitelerimizden biri öne dönerse, reklam kapanmış olmalıydı ama bize haber vermedi. Reklam SDK'sının kendi aktivitelerini yok sayıyoruz, yarış durumlarından kaçınmak için gösterimden en az 1,5 saniye geçmesini istiyoruz ve reklam başına yalnızca bir kez bildiriyoruz. Sonuç, geçen süreyle birlikte bir resumed_no_dismiss olayıdır. Dinleyici yalnızca kaydeder. Oyuna asla dokunmaz, bu yüzden hiçbir şeyi kötüleştiremez.
Bu yaklaşımın bir bedeli var: sinyal dolaylıdır. Reklamın gerçekten ekranda kaldığını görmüyoruz; yalnızca reklam kapandı haberi gelmeden kendi ekranımızın tekrar öne geçtiğini görüyoruz. Yine de pratikte bu, kullanıcı şikâyetinin tarif ettiği durumla örtüşüyor ve ayrıca kimseye bir şey göstermeden, tamamen arka planda ölçülebiliyor.
Olayları tabloya çevirmek
Ham olaylar bir teşhis değildir. Sayıları GA4 Data API ile haftalık bir rapora çekiyoruz. Bunun çalışması için format ve stage, GA4'te olay kapsamlı özel boyut olarak tanımlı olmalı; yoksa sorgu hata döner. Rapor, biçim ve aşamaya göre gruplar ve her hücrede iki sayı gösterir: kaç olay ve kaç kullanıcı.
Bir sütunu aşağı okuyunca reklamın yaşamını görürsün: loaded, shown, impression, dismissed. Sağlıklı şekil, dismissed sayısının shown sayısına yakın olmasıdır. Rapor bir satır daha ekler: takılma olaylarının gösterim olaylarına oranı, yüzde olarak. resumed_no_dismiss sayısı sıfırın üstündeyse pano uyarır ve AdMob'un reklam inceleme araçlarına yönlendirir. Aranan çift, dismissed olmadan shown'dur; resumed_no_dismiss olayı bunu açık hâle getirir.
Ne bulduk, neyi değiştirdik
Kullanıcının anlatımı, ekranda ara sıra şeffaf bir katman bırakan belirli bir üçüncü taraf oyun reklamını gösteriyordu. Reklam normal AdMob yolundan geldiği için çözüm bizim kodumuzda değil, talep tarafındaydı: o reklamverenin alan adını AdMob'un engelleme denetimlerinden engelledik. Aynı sürümde oyunun reklam gösterme biçimini bilerek değiştirmedik. Önce ölçtük; böylece sonraki bir düzeltme bir başlangıç değeriyle karşılaştırılabilirdi.
Kanıt konusunda dürüst olalım. İlk sinyal tek bir kullanıcı şikâyeti ve aynı içeriğin daha önce de sorun çıkardığı bilgisiydi. Kayıt, sorunun ne sıklıkla olduğunu ve hangi adaptörün arkasında olduğunu öğrenmek için eklendi; engel ise kullanıcının anlattığı içeriğe yönelik hedefli bir yanıttı. Kontrollü bir önce-sonra deneyimiz yok ve oyuncu tabanı küçük olduğundan sayılar da küçük. Rakamlarımızı güven aralıklı bir ölçüm olarak değil, bir duman alarmı olarak düşün.
Engelin bir yan maliyeti de var. Bir reklamverenin alan adını engellemek, o reklamverenin diğer reklamlarını da kaldırır ve talebi biraz daraltabilir. Bu yüzden engeli tek bir somut sorunla gerekçelendirdik ve ölçüm tablosunu açık bıraktık; takılma olayları sıfıra yakın kalırsa karar doğru görünür, yeniden çıkarsa başka bir reklamverene bakmamız gerekir.
Sınırlar ve gizlilik
Sezgisel yöntem yanlış alarm üretebilir. Sarmalayıcı hâlâ reklam açık sanarken aktivitemiz başka bir nedenle öne dönerse sayılabilir; eşik ve reklam başına bir kez kuralı bu yüzden var. Kullanıcı uygulamayı zorla kapatırsa takılan bir reklamı kaçırabilir de. Ayrıca Analytics olayları SDK tarafından örneklenir ve toplu gönderilir, bu yüzden sayılar bir iki gün geriden gelir.
Gizlilik açısından: olay yalnızca biçimi, aşamayı, kısaltılmış adaptör sınıf adını, bir hata kodunu ve bir süreyi taşır. Parametrelerimizde kullanıcı kimliği yok ve koddaki açıklama reklam kimliğinin toplanmadığını belirtir. Analytics yalnızca yayın sürümünde açıktır, böylece testler sayıları kirletmez. Reklamlar için de Google'ın Kullanıcı Mesajlaşma Platformu üzerinden olağan onay akışını kullanıyoruz. Uygulaman onay kuralları olan bölgelerde analitik topluyorsa, Firebase Analytics'in kendi kurulumunda nasıl sınırlandığını kontrol et; biz burada belirli bir onay modu yapılandırmasını doğrulamadık.
Buradan ne çıkar
Reklam gösteriyorsan, gösterim ile kapanış arasında muhtemelen bir kör noktan var. Birkaç düzine satır bunu kapatabilir: her geri çağrıyı kaydet, eksik olanı etkinlik yaşam döngüsünden türet ve biçimi aşamaya göre çiz. Kaydediciyi pasif tut. Neyi düzelttiğini bilmeden ekranı otomatik düzeltmeye çalışma, yalnızca olanı bildir.
Takılan bir reklam sana iki şekilde mal olur. Oyuncu kötü yorum bırakır ve oturumu kaybedersin. İkisini de veri olmadan bir nedene bağlamak zordur. Bir yaşam döngüsü tablosu varsa, kullanıcıdan gelen sonraki rapor artık doğrulayamadığın bir hikâye değil, bakabileceğin bir satırdır.
Son bir not: yaşam döngüsü kaydı yalnızca takılmalar için değildir. loaded ile shown arasındaki fark, reklamın hazır olduğu hâlde ne kadar gösterildiğini; load_failed ve show_failed kodları ise reklam doldurma sorunlarını gösterir. Aynı tablo, reklam tarafındaki birçok başka sürprizi de ilk bakışta ortaya çıkarır.
Sık sorulan sorular
Crashlytics takılan geçiş reklamını neden göstermez?
Hiçbir şey çökmez. Reklam penceresi uygulamanın üstünde kalırken uygulamanın kendisi çalışmayı sürdürür; kaydedilecek istisna ya da ANR yoktur.
Hiç kapanmayan bir reklam nasıl tespit edilir?
Reklamın gösterildiği zamanı sakla, sonra aktivite yaşam döngüsünü izle. Reklam hâlâ gösteriliyor diye işaretliyken kendi aktivitelerinden biri öne dönerse resumed_no_dismiss gibi bir olay bildir.
Her reklam olayıyla hangi parametreler kaydediliyor?
Reklam biçimi, aşama, kısaltılmış adaptör sınıf adı, hatalarda bir hata kodu ve reklamın gösterilmesinden bu yana geçen milisaniye.
Parametreleri GA4'te tanımlamam gerekir mi?
Evet. format ve stage değerlerini GA4 Data API ile sorgulamak için olay kapsamlı özel boyut olarak tanımla.
Takılan reklam nasıl düzeltildi?
Reklamverenin alan adı AdMob'da engellenerek. Kayıt davranışı değiştirmedi; sorunun ne sıklıkla olduğunu ölçmek için var.
Diğer yazılar
- Sunucu Olmadan Herkese Aynı Günlük Bulmaca Nasıl Verilir?
- Yüzlerce Bulmaca Bölümü Nasıl Üretilir ve Doğrulanır?
- Tek Geliştirici, Yaklaşık İki Düzine Android Uygulaması
Mahjong Solitaire Tahtası Çözülebilir mi? Nasıl Garanti Ederiz
Mahjong Solitaire'in Tarihi ve Klasik Mahjong'dan Farkı- XOX Tarihi ve Çeşitleri: Çözülmüş Bir Oyunun Hikâyesi