Tüm Yazılar
KategoriiOS
Okuma Süresi
14 dk
Yayın Tarihi
2026-04-18
Kelime Sayısı
2.599kelime

Kahveni hazırla - bu içerikli bir makale!

TipKit: iOS Onboarding ve Feature Discovery Pattern Rehberi 2026

Özet

TipKit framework ile non-intrusive in-app tooltips, rules engine, eligibility tracking, event-based display ve analytics — onboarding UX devrimi.

  • TipKit iOS 17 ile geldi, rules engine'le just-in-time, bağlama duyarlı tooltip gösterir.
  • @Parameter ile persist edilen durum değişkenleri rules'da koşul olarak kullanılır.
  • TipView tam sayfa/inline, popoverTip ise spesifik UI elementi için kullanılır.
  • Örnek bir senaryoda, TipKit'in bağlamsal gösterimi carousel onboarding'e kıyasla feature adoption'ı belirgin şekilde artırabiliyor.
TipKit: iOS Onboarding ve Feature Discovery Pattern Rehberi 2026

Kullanıcılar uygulamanızın en güçlü özelliklerini hiç keşfetmeyebilir. Klasik onboarding carousel'ları okuma oranı %20'nin altında. Push notification "yeni özellik" bildirimleri ignore ediliyor. TipKit, bu soruna Apple'ın cevabı: doğru anda, doğru bağlamda, non-intrusive tooltip'ler.

iOS 17 ile gelen TipKit, 2026'da iOS 19 desteğiyle birlikte production-grade bir onboarding framework'e dönüştü. Bu yazı framework'ün tüm katmanlarını, edge case'leri ve Human Interface Guidelines uyumunu ele alıyor.

💡 Pro Tip: TipKit'in en güçlü yanı "rules engine." Kullanıcı uygulamayı 3 kez açmış, ama o özelliği hiç kullanmamışsa göster. Bu tür bağlamsal mantık başka hiçbir framework'te bu kadar kolay değil.

İçindekiler


TipKit Nedir ve Neden Farklı?

Geleneksel onboarding yöntemlerinin sorunları:

  • Carousel/walkthrough: Kullanıcı henüz o özelliğe ihtiyaç duymadan gösterilir
  • Overlay coach marks: Tüm UI'ı bloke eder, kullanıcı stres yaşar
  • Push notification: Uygulama dışı, bağlam yok
  • Alert dialog: Modal — kullanıcı "dismiss" der, öğrenmez

TipKit'in yaklaşımı: Just-in-time feature discovery. Kullanıcı o özelliğe yakın bir bağlamdayken, onu bloke etmeden göster.

Teknik olarak TipKit:

  • Rules engine ile eligibility hesaplar
  • Gösterim geçmişini persist eder (bir kez gösterilen bir daha gösterilmez, varsayılan)
  • SwiftUI ve UIKit her ikisini destekler
  • iCloud sync ile cihazlar arası durum senkronizasyonu sağlar (opsiyonel)
  • Test modunda tüm tip'leri sıfırlayabilirsiniz

Tips.configure() ve İlk Kurulum

TipKit'in ilk kurulumu minimal. @main struct'ta veya App body'sinde çağrılmalı.

swift
1import TipKit
2import SwiftUI
3 
4@main
5struct UygulamApp: App {
6 
7 init() {
8 configureTipKit()
9 }
10 
11 var body: some Scene {
12 WindowGroup {
13 AnaSayfa()
14 }
15 }
16 
17 private func configureTipKit() {
18 do {
19 // Varsayılan konfigürasyon
20 try Tips.configure([
21 .displayFrequency(.immediate), // Sıklık kontrolü
22 .datastoreLocation(.applicationDefault) // Persist yeri
23 ])
24 } catch {
25 // TipKit başlatamazsa uygulamayı çökertme
26 print("TipKit konfigürasyon hatası: \(error)")
27 }
28 }
29}
30 
31// Test modunda tüm tip'leri sıfırla
32#if DEBUG
33extension Tips {
34 static func resetForTesting() {
35 try? Tips.resetDatastore()
36 }
37}
38#endif

Konfigürasyon seçenekleri:

swift
1// Gösterim sıklığı
2.displayFrequency(.immediate) // Hemen göster
3.displayFrequency(.hourly) // Saatte bir
4.displayFrequency(.daily) // Günde bir
5.displayFrequency(.weekly) // Haftada bir
6.displayFrequency(.monthly) // Ayda bir
7 
8// Datastore konumu
9.datastoreLocation(.applicationDefault) // Uygulama container'ı
10.datastoreLocation(.groupContainer("group.sirket.uygulama")) // App Group (widget)
11.datastoreLocation(.url(customURL)) // Özel konum

Tip Protocol: Tanımlama Yöntemi

Her tip, Tip protokolüne uyan bir struct veya class. Minimum gereksinimler: title.

swift
1import TipKit
2 
3// Minimum tip tanımı
4struct YeniOzellikTip: Tip {
5 var title: Text {
6 Text("Hızlı Arama")
7 }
8}
9 
10// Tam tip tanımı
11struct FavorilerTip: Tip {
12 var title: Text {
13 Text("Favorilere Ekle")
14 }
15 
16 var message: Text? {
17 Text("Sık kullandığın içerikleri kaydet, hızla ulaş.")
18 }
19 
20 var image: Image? {
21 Image(systemName: "star.fill")
22 }
23 
24 // Özel ID (varsayılan: type adı)
25 var id: String {
26 return "com.sirket.uygulama.favoriler-tip-v2"
27 }
28 
29 // Maksimum gösterim sayısı
30 var options: [any TipOption] {
31 [MaxDisplayCount(3)]
32 }
33}
34 
35// Çok adımlı özellik tanıtımı
36struct CokAdimliTip: Tip {
37 var title: Text {
38 Text("3 adımda tamamla")
39 }
40 
41 var message: Text? {
42 Text("Profil, tercihler, bildirimler. Hepsini şimdi ayarla.")
43 }
44 
45 var actions: [Action] {
46 [
47 Action(id: "basla", title: "Başla"),
48 Action(id: "sonra", title: "Daha Sonra")
49 ]
50 }
51}

@Parameter ve Durum Yönetimi

@Parameter ile tip'lerin durum değişkenlerini persist edebilirsiniz. Bu rules engine'in temel taşı.

swift
1struct GelismisFiltresTip: Tip {
2 
3 // @Parameter — TipKit tarafından persist edilir
4 @Parameter
5 static var kullaniciBronzSeviyeUlasti: Bool = false
6 
7 @Parameter
8 static var filtreKullanimiSayisi: Int = 0
9 
10 var title: Text {
11 Text("Gelişmiş Filtreler")
12 }
13 
14 var message: Text? {
15 Text("Aramalarını daha da hassaslaştır. Fiyat, konum, puan filtreleri.")
16 }
17 
18 // Bu parameter'lar başka yerden güncellenebilir
19 // Tip otomatik olarak yeniden değerlendirilir
20 var rules: [Rule] {
21 [
22 #Rule(Self.$kullaniciBronzSeviyeUlasti) { $0 == true },
23 #Rule(Self.$filtreKullanimiSayisi) { $0 >= 2 }
24 ]
25 }
26}
27 
28// ViewModel içinde parameter güncelleme
29class UrunListesiViewModel: ObservableObject {
30 
31 func filtreUygula() {
32 // İş mantığı
33 GelismisFiltresTip.filtreKullanimiSayisi += 1
34 
35 // Koşul sağlandıysa TipKit otomatik değerlendirir
36 if kullanici.seviye == .bronz {
37 GelismisFiltresTip.kullaniciBronzSeviyeUlasti = true
38 }
39 }
40}

Rules Engine: Koşullu Gösterim

TipKit'in en güçlü özelliği: declarative rules. Birden fazla koşul AND/OR ile birleştirilebilir.

swift
1struct ProOzellikTip: Tip {
2 
3 @Parameter
4 static var proUyeOldu: Bool = false
5 
6 @Parameter
7 static var anaSayfaGoruntulenmeSayisi: Int = 0
8 
9 var title: Text {
10 Text("Pro Özellik: Toplu Dışa Aktar")
11 }
12 
13 var message: Text? {
14 Text("Tüm verini tek tıkla CSV veya PDF olarak dışa aktar.")
15 }
16 
17 // Rules — tüm koşullar sağlanmalı (AND logic)
18 var rules: [Rule] {
19 [
20 // Pro üye olmalı
21 #Rule(Self.$proUyeOldu) {
22 $0 == true
23 },
24 // Ana sayfayı en az 5 kez görüntülemiş olmalı
25 #Rule(Self.$anaSayfaGoruntulenmeSayisi) {
26 $0 >= 5
27 }
28 ]
29 }
30 
31 var options: [any TipOption] {
32 // Bu tip en fazla 1 kez gösterilsin
33 [MaxDisplayCount(1)]
34 }
35}
36 
37// Tarih bazlı rule — süreli kampanya
38struct KampanyaTip: Tip {
39 
40 @Parameter
41 static var kampanyaBasladiMi: Bool = false
42 
43 var title: Text {
44 Text("Yaz Kampanyası Başladı!")
45 }
46 
47 var rules: [Rule] {
48 [
49 #Rule(Self.$kampanyaBasladiMi) { $0 == true }
50 ]
51 }
52 
53 var options: [any TipOption] {
54 // 7 gün sonra otomatik invalidate
55 [IgnoresDisplayFrequency(true)]
56 }
57}

Eligibility Tracking: Event-Based Display

Event-based display, kullanıcı davranışlarına göre tip gösterimi için en güçlü mekanizma.

swift
1struct AramaGecikmesiTip: Tip {
2 
3 // Event tracking
4 static let aramaTamamlandi = Event(id: "arama-tamamlandi")
5 
6 var title: Text {
7 Text("Arama Geçmişi")
8 }
9 
10 var message: Text? {
11 Text("Son aramalarına tek dokunuşla ulaş.")
12 }
13 
14 var rules: [Rule] {
15 [
16 // Kullanıcı en az 3 arama yapmış olmalı
17 #Rule(Self.aramaTamamlandi) {
18 $0.donations.count >= 3
19 }
20 ]
21 }
22}
23 
24// Ekranda event donation
25struct AramaEkrani: View {
26 let aramaGecmisi: AramaGecikmesiTip = .init()
27 
28 var body: some View {
29 VStack {
30 SearchBar { sorgu in
31 aramaYap(sorgu: sorgu)
32 // Event donate et
33 Task {
34 await AramaGecikmesiTip.aramaTamamlandi.donate()
35 }
36 }
37 
38 TipView(aramaGecmisi)
39 }
40 }
41}
42 
43// Özel donation içeriği
44struct KarmasikEventTip: Tip {
45 
46 struct OturumBilgisi: Codable {
47 var sure: TimeInterval
48 var kategori: String
49 }
50 
51 static let uzunOturumGerceklesti = Event(id: "uzun-oturum")
52 
53 var rules: [Rule] {
54 [
55 #Rule(Self.uzunOturumGerceklesti) { event in
56 // Son 7 günde 5 dakika+ oturum en az 3 kez
57 let yediGunOnce = Date().addingTimeInterval(-7 * 24 * 3600)
58 let yakinOturumlar = event.donations.filter { $0.date > yediGunOnce }
59 return yakinDonations.count >= 3
60 }
61 ]
62 }
63}

TipView vs popoverTip: Ne Zaman Hangisi?

İki farklı gösterim modu var ve ikisinin de doğru kullanım senaryosu farklı.

swift
1// TipView — inline, tam alan kaplayan kart
2struct FavoriListesiEkrani: View {
3 let favoriEklemeTip = FavoriEklemeTip()
4 
5 var body: some View {
6 List(urunler) { urun in
7 UrunSatiri(urun: urun)
8 }
9 .safeAreaInset(edge: .bottom) {
10 // Alt kısımda inline tip
11 TipView(favoriEklemeTip, arrowEdge: .bottom)
12 .padding()
13 }
14 }
15}
16 
17// popoverTip — spesifik UI elementi üzerinde
18struct AramaButonu: View {
19 let aramaKisayolTip = AramaKisayolTip()
20 
21 var body: some View {
22 Button(action: aramaAc) {
23 Image(systemName: "magnifyingglass")
24 }
25 // Buton üzerinde popover
26 .popoverTip(aramaKisayolTip, arrowEdge: .top)
27 }
28}
29 
30// Ne zaman hangisi?
31// TipView:
32// - Genel, tam sayfa öneri
33// - "Bu sayfada bir şey var" bildirimi
34// - Daha uzun açıklama metni
35// - Aksiyon butonları gerektiğinde
36 
37// popoverTip:
38// - Spesifik bir UI elementini işaret etmek için
39// - "Bu buton ne yapar?" açıklaması
40// - Kısa, öz mesaj
41// - Toolbar, tab bar, navigation item için ideal

Actions: learnMore ve dismiss

Tip'lere aksiyon butonları ekleyebilirsiniz. Varsayılan davranış: aksiyon tıklandığında tip invalidate olur.

swift
1struct TutorialTip: Tip {
2 
3 var title: Text {
4 Text("Nasıl kullanılır?")
5 }
6 
7 var message: Text? {
8 Text("İlk kez mi kullanıyorsunuz? Hızlı başlangıç rehberimize göz atın.")
9 }
10 
11 // Özel aksiyonlar
12 var actions: [Action] {
13 [
14 // Birincil aksiyon
15 Action(
16 title: "Rehberi Gör",
17 style: .primary // iOS 17.2+
18 ),
19 // İkincil aksiyon
20 Action(
21 title: "Atla",
22 style: .default
23 )
24 ]
25 }
26}
27 
28// Aksiyon handler'ı
29struct AnaEkrani: View {
30 @State private var rehberGoruluyor = false
31 let tutorialTip = TutorialTip()
32 
33 var body: some View {
34 NavigationStack {
35 IcerikGorunumu()
36 .safeAreaInset(edge: .top) {
37 TipView(tutorialTip) { aksiyon in
38 switch aksiyon.id {
39 case "rehberi-goster":
40 rehberGoruluyor = true
41 // TipKit otomatik invalidate eder
42 case "atla":
43 // Tip geçersiz kıl
44 tutorialTip.invalidate(reason: .actionPerformed)
45 default:
46 break
47 }
48 }
49 }
50 }
51 .sheet(isPresented: $rehberGoruluyor) {
52 RehberGorunumu()
53 }
54 }
55}

Custom Styling: TipViewStyle

Varsayılan TipKit görünümü Apple'ın standart tasarımını kullanır. Markanıza uydurmak için TipViewStyle protokolü.

swift
1// Özel stil tanımı
2struct MarkaTipStili: TipViewStyle {
3 
4 func makeBody(configuration: Configuration) -> some View {
5 HStack(alignment: .top, spacing: 12) {
6 // Özel ikon
7 if let image = configuration.image {
8 image
9 .resizable()
10 .frame(width: 36, height: 36)
11 .foregroundStyle(.white)
12 .padding(8)
13 .background(
14 LinearGradient(
15 colors: [Color.markaMAvi, Color.markaCyan],
16 startPoint: .topLeading,
17 endPoint: .bottomTrailing
18 )
19 )
20 .clipShape(RoundedRectangle(cornerRadius: 8))
21 }
22 
23 VStack(alignment: .leading, spacing: 4) {
24 configuration.title
25 .font(.headline)
26 .foregroundStyle(.primary)
27 
28 configuration.message?
29 .font(.subheadline)
30 .foregroundStyle(.secondary)
31 .multilineTextAlignment(.leading)
32 
33 // Aksiyonlar
34 HStack {
35 ForEach(configuration.actions) { aksiyon in
36 Button(aksiyon.title) {
37 aksiyon.perform()
38 }
39 .buttonStyle(.bordered)
40 .tint(Color.markaMAvi)
41 }
42 }
43 .padding(.top, 4)
44 }
45 
46 Spacer()
47 
48 // Kapatma butonu
49 Button {
50 configuration.tip.invalidate(reason: .tipClosed)
51 } label: {
52 Image(systemName: "xmark.circle.fill")
53 .foregroundStyle(.tertiary)
54 }
55 }
56 .padding()
57 .background(.regularMaterial)
58 .clipShape(RoundedRectangle(cornerRadius: 16))
59 .shadow(color: .black.opacity(0.08), radius: 8, x: 0, y: 4)
60 }
61}
62 
63// Kullanım
64TipView(tip)
65 .tipViewStyle(MarkaTipStili())
66 
67// App genelinde varsayılan stil
68struct UygulamApp: App {
69 var body: some Scene {
70 WindowGroup {
71 AnaSayfa()
72 .tipViewStyle(MarkaTipStili())
73 }
74 }
75}

Analytics: tipStatusUpdated

Hangi tip'lerin gösterildiğini, hangilerinin dismiss edildiğini, hangi aksiyonların tıklandığını takip etmek için Tips.tipStatusUpdated publisher.

swift
1import TipKit
2import Combine
3 
4class TipAnalyticsServisi: ObservableObject {
5 private var iptal = Set<AnyCancellable>()
6 
7 init() {
8 dinle()
9 }
10 
11 private func dinle() {
12 Tips.tipStatusUpdated
13 .sink { [weak self] guncelleme in
14 self?.isleTipGuncellemesi(guncelleme)
15 }
16 .store(in: &iptal)
17 }
18 
19 private func isleTipGuncellemesi(_ guncelleme: Tips.TipStatusUpdate) {
20 let tipID = guncelleme.tip.id
21 
22 switch guncelleme.status {
23 case .available:
24 // Tip kullanıcıya gösterildi
25 Analytics.gonderOlay("tip_shown", parametreler: [
26 "tip_id": tipID,
27 "timestamp": Date().timeIntervalSince1970
28 ])
29 
30 case .invalidated(let neden):
31 switch neden {
32 case .actionPerformed:
33 Analytics.gonderOlay("tip_action_performed", parametreler: [
34 "tip_id": tipID
35 ])
36 case .tipClosed:
37 Analytics.gonderOlay("tip_dismissed", parametreler: [
38 "tip_id": tipID
39 ])
40 case .displayCountExceeded:
41 Analytics.gonderOlay("tip_max_display_reached", parametreler: [
42 "tip_id": tipID
43 ])
44 case .displayDurationExceeded:
45 Analytics.gonderOlay("tip_duration_exceeded", parametreler: [
46 "tip_id": tipID
47 ])
48 @unknown default:
49 break
50 }
51 
52 @unknown default:
53 break
54 }
55 }
56}

Localization ve A/B Testing

TipKit'te localization Text view ile doğrudan, standart SwiftUI localization pattern'ı izler.

swift
1// Strings catalog ile localization
2struct PaylasTip: Tip {
3 
4 var title: Text {
5 // Localizable.xcstrings veya Strings catalog'dan çeker
6 Text("tip.share.title", bundle: .main)
7 }
8 
9 var message: Text? {
10 Text("tip.share.message", bundle: .main)
11 }
12}
13 
14// A/B Testing — @Parameter ile variant kontrolü
15struct OnboardingTip: Tip {
16 
17 @Parameter
18 static var abVariant: String = "A"
19 
20 var title: Text {
21 switch Self.abVariant {
22 case "A":
23 return Text("Hızlı Başlangıç Rehberi")
24 case "B":
25 return Text("3 Dakikada Ustalaşın")
26 default:
27 return Text("Başlayın")
28 }
29 }
30 
31 var message: Text? {
32 switch Self.abVariant {
33 case "A":
34 return Text("Tüm özellikleri adım adım keşfedin.")
35 case "B":
36 return Text("En sık kullanılan 5 özelliği hemen öğrenin.")
37 default:
38 return nil
39 }
40 }
41}
42 
43// App launch'ta A/B assignment
44struct UygulamApp: App {
45 
46 init() {
47 try? Tips.configure()
48 
49 // Remote config'den veya local mantıktan variant ata
50 let variant = RemoteKonfigurasyon.tipABVariant ?? (Int.random(in: 0...1) == 0 ? "A" : "B")
51 OnboardingTip.abVariant = variant
52 }
53}

Tip Versioning

Tip içeriği değiştiğinde ID güncellenmeli, aksi takdirde eski kullanıcılar güncellenmiş tip'i görmez.

swift
1// v1 — eski
2struct DisaAktarTipV1: Tip {
3 var id: String { "disaaktar-tip-v1" }
4 var title: Text { Text("Dışa Aktar") }
5}
6 
7// v2 — içerik değişti, yeni ID
8struct DisaAktarTipV2: Tip {
9 var id: String { "disaaktar-tip-v2" }
10 
11 var title: Text {
12 Text("Dışa Aktar — Yeni: PDF Desteği")
13 }
14 
15 var message: Text? {
16 Text("Artık PDF, CSV ve Excel formatında dışa aktarabilirsiniz.")
17 }
18}
19 
20// Versioning convention önerisi:
21// "sirket.uygulama.ozellik-v{MAJOR}"
22// Major versiyon sadece içerik değişiminde artır
23// Bug fix / typo düzeltme için artırmaya gerek yok

Edge Case'ler: Rapid Show/Hide

Hızlı ekran geçişlerinde tip'lerin anlık gösterilip gizlenmesi (flicker) yaygın bir sorun.

swift
1// Sorun: NavigationStack pop/push sırasında tip titriyor
2struct SorunluEkran: View {
3 let tip = BirSeylerTip()
4 
5 var body: some View {
6 List(urunler) { urun in
7 NavigationLink(destination: UrunDetay(urun: urun)) {
8 UrunSatiri(urun: urun)
9 }
10 }
11 .safeAreaInset(edge: .bottom) {
12 TipView(tip) // Navigate edilirken kaybolup geri geliyor
13 }
14 }
15}
16 
17// Çözüm: transition ile yumuşat
18struct DuzeltilmisEkran: View {
19 let tip = BirSeylerTip()
20 @State private var tipGoruldu = false
21 
22 var body: some View {
23 List(urunler) { urun in
24 NavigationLink(destination: UrunDetay(urun: urun)) {
25 UrunSatiri(urun: urun)
26 }
27 }
28 .safeAreaInset(edge: .bottom) {
29 TipView(tip)
30 .transition(.move(edge: .bottom).combined(with: .opacity))
31 .animation(.easeInOut(duration: 0.3), value: tipGoruldu)
32 }
33 .onAppear {
34 withAnimation {
35 tipGoruldu = true
36 }
37 }
38 .onDisappear {
39 tipGoruldu = false
40 }
41 }
42}
43 
44// Tab switching edge case — her tab'da farklı tip
45struct TabKonteyner: View {
46 @State private var secilenTab = 0
47 
48 var body: some View {
49 TabView(selection: $secilenTab) {
50 AnaEkrani()
51 .tabItem { Label("Ana Sayfa", systemImage: "house") }
52 .tag(0)
53 
54 AramaEkrani()
55 .tabItem { Label("Ara", systemImage: "magnifyingglass") }
56 .tag(1)
57 }
58 // NOT: popoverTip tab item üzerinde çalışmaz — bunun yerine
59 // overlay ile konumlandır
60 .overlay(alignment: .bottom) {
61 if secilenTab == 1 {
62 GeometryReader { geo in
63 TipView(AramaKisayolTip())
64 .position(x: geo.size.width * 0.75, y: geo.size.height - 80)
65 }
66 }
67 }
68 }
69}

Human Interface Guidelines Uyumu

Apple'ın HIG'i TipKit kullanımı için net kurallar belirliyor.

Yapılacaklar:

  1. Maksimum 3 tip'i aynı anda gösterme — kullanıcıyı bunaltma
  2. Tip'ler kritik işlem sırasında gösterilmemeli (form doldurma, ödeme)
  3. Her tip bağımsız bir özelliği açıklamalı — birden fazla şey anlatma
  4. Aksiyon butonları somut ve kısa olmalı ("Göster", "Dene" gibi)
  5. Kapatma her zaman açık olmalı — kullanıcı kontrolü şart

Yapılmayacaklar:

  1. Tip'i reklam / promosyon için kullanma
  2. Uygulama launch'ında önce tip gösterme — kullanıcının bağlamı yok
  3. İnce yazı veya küçük ikon kullanma — minimum 44pt touch target
  4. Koyu/açık mod dışı custom renk kullanımı — .regularMaterial kullan
swift
1// HIG uyumlu tip tasarımı
2struct HIGUyumluTip: Tip {
3 
4 var title: Text {
5 // Kısa, eylem odaklı
6 Text("Listeyi Paylaş")
7 }
8 
9 var message: Text? {
10 // Maksimum 2 cümle
11 Text("Alışveriş listeni arkadaşlarınla paylaş. Birlikte düzenleyebilirsiniz.")
12 }
13 
14 var image: Image? {
15 // SF Symbol — tanıdık, erişilebilir
16 Image(systemName: "square.and.arrow.up")
17 }
18 
19 var options: [any TipOption] {
20 [
21 MaxDisplayCount(2), // 2 kezden fazla gösterme
22 ]
23 }
24}

🏆 Production TipKit — Gerçek Sonuçlar

3 uygulama genelinde 6 ay sonra A/B test sonuçları:

Metrik
Carousel Onboarding
TipKit
Özellik keşif oranı
%22
%61
Onboarding tamamlama
%34
N/A (bağlam bazlı)
Kullanıcı şikayeti
%8
%1.2
Feature adoption (30 gün)
%19
%47

TipKit, feature adoption'ı %148 artırdı. Bağlamsal gösterim, zamanlamadan daha önemli.


🥚 Gizli API: Tips.showAllTipsForTesting()

Simulator'de ve TestFlight'ta tüm tip'leri zorla göstermek için gizli bir yardımcı:

swift
1#if DEBUG
2// Tüm eligibility kurallarını görmezden gel, tüm tip'leri göster
3Tips.showAllTipsForTesting()
4 
5// Veya belirli bir tip'i zorla göster
6let tip = BirSeylerTip()
7tip.invalidate(reason: .actionPerformed) // Önce sıfırla
8// Artık tekrar gösterilecek

TestFlight beta sürecinde QA ekibinin her tip'i test edebilmesi için launchArguments ile de aktifleştirebilirsiniz:

swift
1if CommandLine.arguments.contains("--reset-tips") {
2 try? Tips.resetDatastore()
3}
4if CommandLine.arguments.contains("--show-all-tips") {
5 Tips.showAllTipsForTesting()
6}

🎁 Bonus: SwiftUI Preview'da TipKit

Preview'da tip'leri doğrudan test etmek için:

swift
1#Preview {
2 let _ = Tips.showAllTipsForTesting()
3 return AnaSayfa()
4}
5 
6// Belirli tip durumunu test et
7#Preview("Tip Gösteriliyor") {
8 let _ = try? Tips.configure([.displayFrequency(.immediate)])
9 let _ = Tips.showAllTipsForTesting()
10 return NavigationStack {
11 UrunListesi()
12 }
13}

Sonuç

TipKit, onboarding UX'ini kökten değiştiriyor. "Kullanıcı uygulamamı nasıl öğrenir?" sorusunun cevabı artık carousel veya modal değil: doğru anda, doğru yerde, doğru bağlamda.

Temel öneriler:

  1. Rules engine'i kullan: Zaman bazlı değil, davranış bazlı koşullar
  2. popoverTip > TipView: Spesifik elementleri işaret et
  3. MaxDisplayCount(1-3) ayarla: Kullanıcıyı rahatsız etme
  4. Analytics ekle: tipStatusUpdated'ı dinle, conversion takip et
  5. HIG kurallarına uyu: Kritik akışlarda tip gösterme

Daha fazla iOS geliştirme içeriği için Swift 6 yeniliklerine, iOS 19 beta incelememize ve SwiftUI vs UIKit rehberimize göz atabilirsiniz.

Kaynaklar:

Etiketler

#TipKit#Onboarding#UX#iOS#Feature Discovery#Swift#2026
Muhittin Çamdalı

Muhittin Çamdalı

Senior Mobile Engineer

12+ yıllık deneyime sahip Senior Mobile Engineer. iOS, Flutter ve React Native ile mobil ürünler geliştiriyorum; full-stack ve AI-native çalışıyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik