---
title: "iOS SDK'da Flow Builder ile satın almaları etkinleştirin"
description: "Adapty Flow Builder ile uygulama içi satın almaları etkinleştirmeye yönelik hızlı başlangıç kılavuzu."
---

Uygulama içi satın almaları etkinleştirmek için üç temel kavramı anlamanız gerekir:
- [**Ürünler**](product) – kullanıcıların satın alabileceği her şey (abonelikler, consumable'lar, süresiz erişim)
- [**Flow'lar**](adapty-flow-builder) – ürünleri kullanıcılara sunan, no-code Flow Builder ile oluşturulan ekran dizileri. SDK bunları `getFlow` ile alır. Kullanıcı arayüzünü kendi kodunuzla oluşturmayı tercih ederseniz, bunun yerine paywall kullanın — bkz. [Paywallları manuel olarak uygulama](ios-quickstart-manual).
- [**Placement'lar**](placements) – uygulamanızda flow'ları nerede ve ne zaman göstereceğiniz (`main`, `onboarding`, `settings` gibi). Flow'ları kontrol panelinde placement'lara bağlar, ardından kodunuzda placement ID'si ile talep edersiniz. Bu sayede A/B testleri çalıştırmak ve farklı kullanıcılara farklı flow'lar göstermek çok kolay olur.
Adapty, uygulamanızda satın alımları etkinleştirmeniz için üç yol sunar. Uygulama gereksinimlerinize göre birini seçin:

| Uygulama | Karmaşıklık | Ne zaman kullanılır |
|---|---|---|
| Adapty Flow Builder | ✅ Kolay | [No-code builder'da eksiksiz, satın almaya hazır bir flow oluşturursunuz](quickstart-paywalls). Adapty bunu otomatik olarak render eder ve tüm karmaşık satın alma akışını, makbuz doğrulamasını ve abonelik yönetimini arka planda halleder. |
| Elle oluşturulan paywalllar | 🟡 Orta | Paywall arayüzünüzü uygulama kodunuzda kendiniz uygularsınız; ancak ürün tekliflerinde esnekliği korumak için flow nesnesini yine Adapty'den alırsınız. [Rehbere](ios-quickstart-manual) göz atın. |
| Observer modu | 🔴 Zor | Kendi satın alma altyapınız zaten mevcuttur ve bunu kullanmaya devam etmek istersiniz. Observer modunun Adapty'de bazı kısıtlamaları olduğunu unutmayın. [Makaleye](observer-vs-full-mode) bakın. |
:::important
**Aşağıdaki adımlar, Adapty Flow Builder'da oluşturulan bir flow'un nasıl uygulanacağını göstermektedir.**

Paywall arayüzünü kendiniz oluşturmayı tercih ediyorsanız, bkz. [Paywall'ları manuel olarak uygulama](ios-quickstart-manual).
:::

Adapty Flow Builder'da oluşturulan bir flow'u görüntülemek için uygulama kodunuzda yalnızca şunları yapmanız gerekir:

1. **Flow'u alın**: Adapty'den alın.
2. **Görüntüleyin, satın almaları Adapty sizin için yönetecektir**: Görünümü uygulamanızda gösterin.
3. **Buton eylemlerini yönetin**: Kullanıcı etkileşimlerini uygulamanızın bu etkileşimlere verdiği yanıtlarla ilişkilendirin. Örneğin, kullanıcılar butona tıkladığında bağlantılar açın veya flow'u kapatın.
## Başlamadan önce \{#before-you-start\}

Başlamadan önce şu adımları tamamlayın:

1. Adapty Kontrol Paneli'nde [uygulamanızı App Store'a bağlayın](initial_ios).
2. Adapty'de [ürünlerinizi oluşturun](create-product).
3. [Bir flow oluşturun ve ürünleri ekleyin](create-paywall).
4. [Bir placement oluşturun ve flow'u ekleyin](create-placement).
5. Uygulama kodunuzda [Adapty SDK'yı yükleyip etkinleştirin](sdk-installation-ios). Bu kılavuz Adapty iOS SDK v4 API'lerini kullanmaktadır.

## 1. Flow'u edinin \{#1-get-the-flow\}

Flow'larınız, kontrol panelinde yapılandırılmış placement'larla ilişkilendirilir. Placement'lar, farklı kitleler için farklı flow'lar çalıştırmanıza veya [A/B testi](ab-tests) yapmanıza olanak tanır.

Adapty Flow Builder'da oluşturulan bir flow'u edinmek için şunları yapmanız gerekir:

1. `getFlow` metodunu kullanarak [placement](placements) ID'sine göre `flow` nesnesini alın ve bir görünüm yapılandırması içerip içermediğini kontrol edin.
2. `getFlowConfiguration` metodunu kullanarak görünüm yapılandırmasını edinin. Bu yapılandırma, flow'u görüntülemek için gereken UI öğelerini ve stil bilgilerini içerir.
```swift

func loadFlow() async {
    let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")

    guard flow.hasViewConfiguration else {
        print("Flow'un bir görünüm yapılandırması yok")
        return
    }

    flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow)
}
```
## 2. Flow'u göster \{#display-the-flow\}

Artık flow konfigürasyonuna sahipsiniz; flow'u göstermek için birkaç satır kod eklemeniz yeterli.

<Tabs groupId="current-os" queryString>

<TabItem value="swiftui" label="SwiftUI" default>

SwiftUI'da flow'u gösterirken aynı zamanda olayları da ele almanız gerekir. `didFinishPurchase`, `didFailPurchase`, `didFinishRestore`, `didFailRestore` ve `didReceiveError` zorunludur. Test sırasında bu olayları kaydetmek için aşağıdaki kod parçacığını doğrudan kopyalayabilirsiniz.
:::tip
Flow, başarılı bir satın alma işleminin ardından otomatik olarak kapanmaz. `didFinishPurchase` içinde, flow'u kapatmak için sunum bağlantınızı `false` olarak ayarlayın ya da flow'un sonraki ekranlarına devam etmesi için hiçbir şey yapmayın.
:::
```swift
.flow(
    isPresented: $flowPresented,
    flowConfiguration: flowConfiguration,
    didFinishPurchase: { product, purchaseResult in
        print("Purchase finished successfully")
        flowPresented = false // or do nothing to let the flow continue
    },
    didFailPurchase: { product, error in
        print("Purchase failed: \(error)")
    },
    didFinishRestore: { profile in
        print("Restore finished successfully")
    },
    didFailRestore: { error in
        print("Restore failed: \(error)")
    },
    didReceiveError: { error in
        flowPresented = false
        print("Flow error: \(error)")
    }
)
```
</TabItem>
<TabItem value="uikit" label="UIKit" default>

```swift

func presentFlow(with config: AdaptyUI.FlowConfiguration) {
    let flowController = try AdaptyUI.flowController(
        with: config,
        delegate: self
    )
    present(flowController, animated: true)
}
```
`AdaptyFlowControllerDelegate`'i olayları ele almak için uygulayın. En azından varsayılan uygulaması olmayan dört metodu implemente edin. Dikkat: controller başarılı bir satın almanın ardından kendini kapatmaz — `didFinishPurchase` içinde kapatın ya da flow'un sonraki ekranlarına devam etmesine izin vermek için hiçbir şey yapmayın:
```swift
extension YourViewController: AdaptyFlowControllerDelegate {
    func flowController(_ controller: AdaptyFlowController,
                        didFinishPurchase product: AdaptyPaywallProduct,
                        purchaseResult: AdaptyPurchaseResult) {
        if !purchaseResult.isPurchaseCancelled {
            controller.dismiss(animated: true) // or do nothing to let the flow continue
        }
    }

    func flowController(_ controller: AdaptyFlowController,
                        didFailPurchase product: AdaptyPaywallProduct,
                        error: AdaptyError) {
        print("Purchase failed: \(error)")
    }

    func flowController(_ controller: AdaptyFlowController,
                        didFinishRestoreWith profile: AdaptyProfile) {
        print("Restore finished successfully")
    }

    func flowController(_ controller: AdaptyFlowController,
                        didFailRestoreWith error: AdaptyError) {
        print("Restore failed: \(error)")
    }
}
```
</TabItem>
</Tabs>
:::info
Bir flow'un nasıl görüntüleneceğine dair daha fazla ayrıntı için [rehberimize](ios-present-paywalls) bakın.
:::
## 3. Buton eylemlerini yönetin \{#handle-button-actions\}

Kullanıcılar butona tıkladığında, iOS SDK satın alma işlemlerini, geri yüklemeleri, flow'u kapatmayı ve bağlantı açmayı otomatik olarak yönetir.

Ancak bazı butonların özel veya önceden tanımlanmış kimlikleri vardır ve kodunuzda eylemlerin yönetilmesini gerektirir. Ya da varsayılan davranışlarını geçersiz kılmak isteyebilirsiniz.

Örneğin, kapat butonunu şu şekilde yönetebilirsiniz. UIKit'te, `.close` tetiklendiğinde SDK controller'ı otomatik olarak kapatır — yalnızca özel bir davranış istiyorsanız geçersiz kılın. SwiftUI'da ise `isPresented` binding'inizi kendiniz `false` olarak ayarlamanız gerekir.
:::tip
Buton [aksiyonlarını](handle-paywall-actions) ve [olayları](ios-handling-events) nasıl yöneteceğinize dair kılavuzlarımızı okuyun.
:::

<Tabs groupId="current-os" queryString>

<TabItem value="swiftui" label="SwiftUI" default>
```swift
.flow(
    isPresented: $flowPresented,
    flowConfiguration: flowConfiguration,
    didPerformAction: { action in
        switch action {
            case .close:
                flowPresented = false // dismiss the flow when the user taps close
            default:
                break
        }
    },
    didFinishPurchase: { product, purchaseResult in flowPresented = false },
    didFailPurchase: { product, error in /* handle the error */ },
    didFinishRestore: { profile in /* check access level and dismiss */ },
    didFailRestore: { error in /* handle the error */ },
    didReceiveError: { error in flowPresented = false }
)
```
</TabItem>
<TabItem value="uikit" label="UIKit" default>

```swift
extension YourViewController: AdaptyFlowControllerDelegate {
    func flowController(_ controller: AdaptyFlowController,
                        didPerform action: AdaptyUI.Action) {
        switch action {
            case .close:
                controller.dismiss(animated: true) // varsayılan davranış — yalnızca gerektiğinde geçersiz kılın
            default:
                break
        }
    }
}
```
</TabItem>
</Tabs>
## Sonraki adımlar \{#next-steps\}

:::tip
Sorularınız mı var ya da sorunlarla mı karşılaşıyorsunuz? Sık sorulan soruların yanıtlarını bulabileceğiniz veya kendi sorularınızı sorabileceğiniz [destek forumumuza](https://adapty.featurebase.app/) göz atın. Ekibimiz ve topluluğumuz yardımcı olmak için burada!
:::

Flow'unuz uygulamada görüntülenmeye hazır. Bir test satın alma işlemini tamamlayabildiğinizden emin olmak için [satın almalarınızı sandbox modunda test edin](test-purchases-in-sandbox).

Şimdi, flow'u veya ücretli özelliklere erişimi doğru kullanıcılara sunduğunuzdan emin olmak için [kullanıcıların access level'ını kontrol etmeniz](ios-check-subscription-status) gerekiyor.
## Tam örnek \{#full-example\}

Bu rehberdeki tüm adımların uygulamanıza birlikte nasıl entegre edileceği aşağıda gösterilmektedir.

<Tabs groupId="current-os" queryString>

<TabItem value="swiftui" label="SwiftUI" default>

```swift

struct ContentView: View {
    @State private var flowPresented = false
    @State private var flowConfiguration: AdaptyUI.FlowConfiguration?
    @State private var isLoading = false
    @State private var hasInitialized = false

    var body: some View {
        VStack {
            if isLoading {
                ProgressView("Loading...")
            } else {
                Text("Your App Content")
            }
        }
        .task {
            guard !hasInitialized else { return }
            await initializeFlow()
            hasInitialized = true
        }
        .flow(
            isPresented: $flowPresented,
            flowConfiguration: flowConfiguration,
            didPerformAction: { action in
                switch action {
                case .close:
                    flowPresented = false
                default:
                    break
                }
            },
            didFinishPurchase: { product, purchaseResult in
                print("Purchase finished successfully")
                flowPresented = false // or do nothing to let the flow continue
            },
            didFailPurchase: { product, error in
                print("Purchase failed: \(error)")
            },
            didFinishRestore: { profile in
                print("Restore finished successfully")
            },
            didFailRestore: { error in
                print("Restore failed: \(error)")
            },
            didReceiveError: { error in
                print("Flow error: \(error)")
                flowPresented = false
            }
        )
    }

    private func initializeFlow() async {
        isLoading = true
        defer { isLoading = false }

        await loadFlow()
        flowPresented = true
    }

    private func loadFlow() async {
        do {
            let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")
            guard flow.hasViewConfiguration else {
                print("Flow doesn't have a view configuration")
                return
            }
            flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow)
        } catch {
            print("Failed to load: \(error)")
        }
    }
}
```
</TabItem>

<TabItem value="uikit" label="UIKit" default>

```swift

class ViewController: UIViewController {
    private var flowConfiguration: AdaptyUI.FlowConfiguration?

    override func viewDidLoad() {
        super.viewDidLoad()

        Task {
            await initializeFlow()
        }
    }

    private func initializeFlow() async {
        do {
            flowConfiguration = try await loadFlow()

            if let flowConfiguration {
                await MainActor.run {
                    presentFlow(with: flowConfiguration)
                }
            }
        } catch {
            print("Error initializing: \(error)")
        }
    }

    private func loadFlow() async throws -> AdaptyUI.FlowConfiguration? {
        let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")

        guard flow.hasViewConfiguration else {
            print("Flow doesn't have a view configuration")
            return nil
        }

        return try await AdaptyUI.getFlowConfiguration(forFlow: flow)
    }

    private func presentFlow(with config: AdaptyUI.FlowConfiguration) {
        guard let flowController = try? AdaptyUI.flowController(
            with: config,
            delegate: self
        ) else { return }

        present(flowController, animated: true)
    }
}

extension ViewController: AdaptyFlowControllerDelegate {
    func flowController(_ controller: AdaptyFlowController,
                        didFinishPurchase product: AdaptyPaywallProduct,
                        purchaseResult: AdaptyPurchaseResult) {
        if !purchaseResult.isPurchaseCancelled {
            controller.dismiss(animated: true) // or do nothing to let the flow continue
        }
    }

    func flowController(_ controller: AdaptyFlowController,
                        didFailPurchase product: AdaptyPaywallProduct,
                        error: AdaptyError) {
        print("Purchase failed for \(product.vendorProductId): \(error)")

        guard error.adaptyErrorCode != .paymentCancelled else { return }

        let message = switch error.adaptyErrorCode {
        case .paymentNotAllowed:
            "Purchases are not allowed on this device."
        default:
            "Purchase failed. Please try again."
        }

        let alert = UIAlertController(title: "Purchase Error", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default))
        present(alert, animated: true)
    }

    func flowController(_ controller: AdaptyFlowController,
                        didFinishRestoreWith profile: AdaptyProfile) {
        print("Restore finished successfully")
        controller.dismiss(animated: true)
    }

    func flowController(_ controller: AdaptyFlowController,
                        didFailRestoreWith error: AdaptyError) {
        print("Restore failed: \(error)")
    }

    func flowController(_ controller: AdaptyFlowController,
                        didReceiveError error: AdaptyUIError) {
        print("Flow error: \(error)")
        controller.dismiss(animated: true)
    }
}
```
</TabItem>
</Tabs>