AOY
TR EN
← Yazılar

Apple üç kez reddetti: ATT, GDPR formu ve beklemediğim bir sıra sorunu

31 Ağustos 2026· 4 dk okuma· Mağaza

Her düzeltme bir sonraki katmanı açtı. Sonuncusu kodda değil, iOS’un ATT istemini ne zaman göstermeyi kabul ettiğindeydi.

Reklam gösteren bir iOS uygulamasında iki ayrı izin var ve birbirinin yerine geçmiyorlar:

  • ATT (App Tracking Transparency) — Apple’ın cihaz izni. Reklam kimliğine erişmek için sistem diyaloğuyla soruluyor.
  • UMP / TCF formu — GDPR rızası. Avrupa Ekonomik Alanı, Birleşik Krallık ve İsviçre’de hukuken gerekli; Google’ın sertifikalı rıza platformu gösteriyor.

Apple’ın kuralı basit görünüyor: sistem istemi ilk gelmek zorunda. Uygulamayı üç kere reddettirmesi bir ay sürdü.

Birinci ret — 5.1.2(i): suçlu bizim kodumuz değildi

Ret metni, ATT yerine “özel bir istem” gösterildiğini söylüyordu. Reddedilen ekran şuydu:

Our app wants to stay free for you. Ads help support our business. Tap “Allow” on the next screen to give permission to show ads that are more relevant to you.

Apple’ın tam olarak yasakladığı kalıp: kullanıcıya “Allow’a bas” demek. Ama o metni aradım ve kodda bulamadım — ne kaynakta ne de derlenmiş binary’de tek eşleşme vardı. Metin çalışma zamanında Google’ın UMP SDK’sı tarafından AdMob konsolundan çekiliyordu.

Karar · konsol vs build

Çözüm koda değil konsola girdi: AdMob → Privacy & messaging → App Tracking Transparency altındaki “IDFA açıklayıcı” mesajı uygulamanın hedef listesinden çıkarıldı. UMP mesajı her açılışta sunucudan çekiyor, binary’de tutmuyor — yani yeni build gerekmedi, mesaj yayından kalktığı an mevcut sürüm o ekranı göstermeyi bıraktı.

⚠️ Diğer iki karta (Avrupa tüzükleri / ABD eyalet yönetmelikleri) dokunulmadı: birincisi AEA’da yasal zorunluluk, ikincisi gizlilik bildirimi. İhlal eden yalnız IDFA açıklayıcısıydı.

Düzeltme ABD bölgeli bir simülatörde doğrulandı: konum izninden doğrudan sistem ATT diyaloğuna geçiliyor, arada hiçbir ekran yok. Temiz.

İkinci ret — aynı madde, kalan suçlu sıraydı

Apple aynı maddeyi tekrar yazdı. Ama ret ekran görüntüsünde bu sefer IDFA açıklayıcısı yoktu; yerine Google’ın TCF formu vardı. Yani konsol düzeltmesi çalışmıştı, sorun taşınmıştı.

Apple’ın inceleme cihazı AEA’daydı. Kodun oradaki sırası şuydu:

_ensureConsent()        → GDPR/TCF formu   ← Apple bunu "özel istem" sayıyor
_ensureAttPermission()  → sistem ATT diyaloğu
MobileAds.initialize()
Doğrulama yanlış bölgede yapılmıştı

Birinci düzeltme ABD bölgeli simülatörde doğrulanmıştı ve orada rıza akışı hiçbir şey göstermeden hemen dönüyor — GDPR formu o turda hiç çıkmadı, dolayısıyla sıra sorunu görünmedi.

Bölgeye bağlı davranışı yanlış bölgede test etmek, test etmemekle aynı şey. Temiz çıktı tek başına kanıt değil.

Sıra çevrildi: ATT → UMP → SDK. UMP formunu tamamen kaldırmak seçenek değildi — AEA’da hukuken gerekli ve yayımlanmış gizlilik politikamız onu açıkça vaat ediyor; kaldırmak yanlış beyan olurdu. Elimizdeki tek değişken sıraydı.

Ve sıra kodda doğruydu ama çalışma zamanında tutmuyordu

AEA simülasyonlu bir koşuda ölçüldü:

[ads] ATT sonucu: notDetermined      ← kullanıcı HİÇBİR ŞEY yanıtlamadan
...20 sn sonra: rıza akışı zaman aşımına uğradı

Mekanizma şuydu: iOS, ATT istemini yalnız uygulama resumed durumundayken gösteriyor. Açılışta bizim konum izni diyaloğumuz öndeyken uygulama inactive oluyor ve requestTrackingAuthorization() istemi hiç göstermeden anında notDetermined dönüyor.

Kod bunu “soruldu” sanıp devam ediyor, UMP formunu açıyordu; ATT diyaloğu sonradan formun üstüne düşüyordu. Kullanıcının ve reviewer’ın gördüğü sıra yine UMP → ATT, yani reddedilen sıra.

Beklemeyen await

await vardı ama beklenen şeyi beklemiyordu. Çağrı “sordum” değil “şu an soramam” diyordu ve ikisi aynı değeri dönüyordu.

Düzeltme: uygulama öne gelene kadar bekleyen bir yardımcı, istem gösterilmeden dönerse üç kereye kadar tekrar. 🔴 Bekleme bütçesi ile deneme sayacı ayrı tutuldu — ilk denemede birleşiklerdi ve konum diyaloğu uzun açık kalınca üç deneme de beklemede tükeniyordu.

Üçüncü ret — 5.1.1(iv): sıra doğru, ama ikinci kez sormak

Apple bu sefer başka bir madde yazdı — yani ilerleme gerçekti:

…the app shows a GDPR prompt that asks permission to track after the user has already selected “Ask App Not to Track”…

Google’ın TCF formu ilk satırında “Personalised advertising and content” rızası istiyor. Kullanıcı “takip etme” dedikten sonra o formu açmak, Apple’a göre reddedilen izni ikinci kez sormak.

Düzeltme ATT cevabına göre dallandı:

ATT cevabıUMP formuReklam isteği
AllowAEA’da gösterilirkişiselleştirilmiş
Ask App Not to Trackgösterilmezkişiselleştirilmemiş; AEA’da rıza olmadığı için hiç istenmez
Android / iOS 14 öncesieskisi gibideğişmedi

Kararsız her durum — denied, restricted, yanıtlanamamış notDetermined, istisna — “takip yok” sayıldı. Belirsizlikte kısıtlayan taraf seçildi.

Yol boyunca çıkan asıl hata

Bunu ararken çok daha ciddi bir şey bulundu: rıza durumunu tutan canRequestAds değeri okunuyor ve yalnız log’a yazılıyordu. Reklam SDK’sı ve üç ayrı reklam isteği ondan bağımsız çalışıyordu.

Yani AEA’da rızayı reddeden kullanıcıya da reklam isteniyordu — hem Google’ın entegrasyon şartına hem GDPR’a aykırı. Apple’ın “kullanıcı izin verene kadar hiçbir takip faaliyeti olmamalı” cümlesinin tam hedefi. Dört yükleme yolunun dördü de bu bayrağa bağlandı.

Karar · bilinçli fail-closed

Rıza durumu çözülemezse (ilk açılış + ağ yok, ya da akış istisna atarsa) reklam hiç gösterilmiyor. Rızasız reklam istemektense bir oturumluk gelir kaybı seçildi.

⚠️ Bunun bir izleme noktası olması şart: rıza yapılandırması bir gün “her yerde gerekli” hâline gelirse gelir sessizce sıfırlanır ve bu, kod hatasından ayırt edilemez. Teşhis tek bir log satırından okunuyor.


Çıkarılacak dersler

  • Bölgeye bağlı davranışı doğru bölgede test et. ABD’de temiz çıkan akış AEA’da reddedilen akıştı.
  • Ekranı senin kodun üretmiyor olabilir. Reddedilen metin AdMob konsolundan geliyordu; çözümü de orada, build almadan.
  • Sırayı kodda düzeltmek, kullanıcının gördüğü sırayı düzeltmez. iOS istemi yalnız uygulama önde iken gösteriyor; “soramadım” ile “sordum, cevap yok” aynı değeri dönüyor.
  • Bir bayrağı hesaplayıp kullanmamak, hesaplamamaktan kötüdür. Log’da doğru değer vardı ve kimse ona bakmıyordu.

İlgili proje

Diğer yazılar

hepsi