Flow ve paywall olaylarını işleme - Kotlin Multiplatform
Bu kılavuz; satın alma, geri yükleme, ürün seçimi ve flow görüntüleme için olay işlemeyi kapsar. Ayrıca düğme işlemeyi de (flow’u kapatma, bağlantı açma vb.) uygulamanız gerekir. Ayrıntılar için flow aksiyonlarını işleme kılavuzumuza bakın.
Flow Builder veya Paywall Builder ile yapılandırılan flow’lar ve paywaller, satın alma yapmak ve geri yüklemek için ekstra kod gerektirmez. Ancak uygulamanızın yanıt verebileceği bazı olaylar üretirler. Bu olaylar; düğme tıklamalarını (kapat düğmeleri, URL’ler, ürün seçimleri vb.) ve satın alma işlemleriyle ilgili bildirimleri kapsar. Bu olaylara nasıl yanıt vereceğinizi aşağıda öğrenebilirsiniz.
Mobil uygulamanızdaki flow ekranında gerçekleşen süreçleri kontrol etmek veya izlemek için AdaptyUIFlowsEventsObserver arayüzü yöntemlerini uygulayın ve gözlemcinizi AdaptyUI.setFlowsEventsObserver() ile kaydedin. Bazı yöntemlerin yaygın senaryoları otomatik olarak ele alan varsayılan uygulamaları bulunur; bu nedenle yalnızca değiştirmek istediğiniz yöntemleri geçersiz kılın:
AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver {
// override only the methods you want to change
})Bu metodlar, flow olaylarına yanıt vermek için özel mantığınızı eklediğiniz yerlerdir. Flow’u kapatmak için view.dismiss() kullanabilir ya da ihtiyaç duyduğunuz başka özel davranışları uygulayabilirsiniz. dismiss() fonksiyonunun bir suspend fonksiyonu olduğunu unutmayın — bir callback içinde, observer’ın mainUiScope’unu kullanarak çağırın: mainUiScope.launch { view.dismiss() }.
Kullanıcı tarafından tetiklenen olaylar
Flow’un görünmesi ve kaybolması
Bir flow göründüğünde veya kaybolduğunda şu metodlar çağrılır:
override fun flowViewDidAppear(view: AdaptyUIFlowView) {
// Handle flow appearance
// You can track analytics or update UI here
}
override fun flowViewDidDisappear(view: AdaptyUIFlowView) {
// Handle flow disappearance
// You can track analytics or update UI here
}- iOS’ta,
flowViewDidAppearaynı zamanda kullanıcı bir flow içindeki web paywall butonuna dokunduğunda ve bir web paywall uygulama içi tarayıcıda açıldığında da tetiklenir. - iOS’ta,
flowViewDidDisappearaynı zamanda bir flow’dan uygulama içi tarayıcıda açılan web paywall ekrandan kaybolduğunda da tetiklenir.
Olay örnekleri (Genişletmek için tıklayın)
// Flow appeared
{
// No additional data
}
// Flow disappeared
{
// No additional data
}Ürün seçimi
Bir kullanıcı satın alma için ürün seçerse bu metot çağrılır:
override fun flowViewDidSelectProduct(view: AdaptyUIFlowView, productId: String) {
// Handle product selection
// You can update UI or track analytics here
}Olay örneği (Genişletmek için tıklayın)
{
"productId": "premium_monthly"
}Satın alma başlatıldı
Bir kullanıcı satın alma sürecini başlatırsa bu metot çağrılır:
override fun flowViewDidStartPurchase(view: AdaptyUIFlowView, product: AdaptyPaywallProduct) {
// Handle purchase start
// You can show loading indicators or track analytics here
}Observer modunda, bir flow’dan başlatılan satın almalar AdaptyUIObserverModeResolver’ınıza iletilir.
Etkinlik örneği (Genişletmek için tıklayın)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}Başarılı, iptal edilmiş veya bekleyen satın alma
Bir satın alma tamamlandığında bu metot çağrılır. Varsayılan olarak hiçbir şey yapmaz — satın alma sonrasında siz kapatana kadar flow açık kalır; bu nedenle kullanıcı erişim kazandığında view.dismiss() metodunu kendiniz çağırmanız gerekir:
override fun flowViewDidFinishPurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
// Check if user has access to premium features
if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) {
mainUiScope.launch { view.dismiss() }
}
}
AdaptyPurchaseResult.Pending -> {
// Handle pending purchase (e.g., user will pay offline with cash)
}
AdaptyPurchaseResult.UserCanceled -> {
// Handle user cancellation
}
}
}Etkinlik örnekleri (Genişletmek için tıklayın)
// Successful purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
}
}
// Pending purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Pending"
}
}
// User canceled purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "UserCanceled"
}
}Başarılı satın alım durumunda flow ekranını kapatmanızı öneririz.
Başarısız satın alım
Bir satın alım hata nedeniyle başarısız olursa bu metot çağrılır. Bu durum; StoreKit/Google Play Billing hatalarını (ödeme kısıtlamaları, geçersiz ürünler, ağ hataları), işlem doğrulama hatalarını ve sistem hatalarını kapsar. Kullanıcı iptalleri bu metodu değil, iptal sonucuyla birlikte flowViewDidFinishPurchase’ı tetikler; bekleyen ödemeler ise bu metodu tetiklemez.
override fun flowViewDidFailPurchase(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct,
error: AdaptyError
) {
// Add your purchase failure handling logic here
// For example: show error message, retry option, or custom error handling
}Olay örneği (Genişletmek için tıklayın)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
}Geri yükleme başlatıldı
Bir kullanıcı geri yükleme işlemini başlatırsa bu metot çağrılır:
override fun flowViewDidStartRestore(view: AdaptyUIFlowView) {
// Handle restore start
// You can show loading indicators or track analytics here
}Başarılı geri yükleme
Bir satın alma işlemi başarıyla geri yüklenirse bu metot çağrılır. Varsayılan olarak hiçbir şey yapmaz — siz kapatana kadar geri yükleme sonrasında flow açık kalır:
override fun flowViewDidFinishRestore(view: AdaptyUIFlowView, profile: AdaptyProfile) {
// Add your successful restore handling logic here
// For example: show success message, update UI, or dismiss the flow
// Check if user has access to premium features
if (profile.accessLevels["premium"]?.isActive == true) {
mainUiScope.launch { view.dismiss() }
}
}Olay örneği (Genişletmek için tıklayın)
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}Kullanıcı gerekli accessLevel’a sahipse ekranı kapatmanızı öneririz. Bunu nasıl kontrol edeceğinizi öğrenmek için Abonelik durumu konusuna bakın.
Başarısız geri yükleme
Adapty.restorePurchases() başarısız olursa bu metot çağrılır:
override fun flowViewDidFailRestore(view: AdaptyUIFlowView, error: AdaptyError) {
// Add your restore failure handling logic here
// For example: show error message, retry option, or custom error handling
}Olay örneği (Genişletmek için tıklayın)
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}Web ödeme navigasyonu tamamlama
Bir kullanıcı web paywall aracılığıyla satın alma işlemini başlatırsa bu metot çağrılır:
override fun flowViewDidFinishWebPaymentNavigation(
view: AdaptyUIFlowView,
product: AdaptyPaywallProduct?,
error: AdaptyError?
) {
if (error != null) {
// Handle web payment navigation error
} else {
// Handle successful web payment navigation
}
}Etkinlik örnekleri (Genişletmek için tıklayın)
// Başarılı web ödeme navigasyonu
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Başarısız web ödeme navigasyonu
{
"product": null,
"error": {
"code": "web_payment_failed",
"message": "Web payment navigation failed",
"details": {
"underlyingError": "Network connection error"
}
}
}Veri Alma ve Render Etme
Ürün yükleme hataları
Başlatma sırasında ürünleri iletmezseniz, AdaptyUI gerekli nesneleri sunucudan kendisi alır. Bu işlem başarısız olursa, AdaptyUI hatayı şu metodu çağırarak bildirir:
override fun flowViewDidFailLoadingProducts(view: AdaptyUIFlowView, error: AdaptyError) {
// Add your product loading failure handling logic here
// For example: show error message, retry option, or custom error handling
}Olay örneği (Genişletmek için tıklayın)
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}Render ve çalışma zamanı hataları
Arayüz render edilirken bir hata oluşursa ya da satın alma dışında başka bir çalışma zamanı hatası meydana gelirse, bu metot aracılığıyla bildirilir. Varsayılan olarak hata durumunda flow kapatılır — flow’u açık tutmak veya kendi işleme mantığınızı eklemek için bu metodu geçersiz kılın:
override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {
// Handle the error
// The default implementation dismisses the flow;
// once you override this method, dismissal is up to you
}Olay örneği (Genişletmek için tıklayın)
{
"error": {
"code": "rendering_failed",
"message": "Failed to render flow interface",
"details": {
"underlyingError": "Invalid flow configuration"
}
}
}Normal koşullarda bu tür hatalar oluşmamalıdır; eğer biriyle karşılaşırsanız lütfen bize bildirin.
Analytics olayları
flowViewDidReceiveAnalyticEvent callback’i, bir flow’dan gelen özel analitik olaylar için ayrılmıştır. Flow’lar henüz bu olayları kodunuza iletmediğinden, bunu uygulamanıza gerek yoktur:
override fun flowViewDidReceiveAnalyticEvent(
view: AdaptyUIFlowView,
name: String,
paramsJsonString: String
) {
// Reserved for custom analytic events from a flow
}Navigasyon
Android sistem geri butonu
Varsayılan olarak, bir flow Android sistem geri butonu veya geri hareketiyle kapatılamaz — varsayılan flowViewDidPerformAction implementasyonu flow’u yalnızca CloseAction ile kapatır ve AndroidSystemBackAction’ı yok sayar; bu nedenle kullanıcı, flow’dan sizin belirlediğiniz bir yol üzerinden çıkar: örneğin bir Close butonu veya builder’daki bir on_device_back aksiyonu. Sistem geri butonu ile flow’u kapatmak istiyorsanız aksiyonu kendiniz ele alın:
override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) {
when (action) {
is AdaptyUIAction.CloseAction ->
mainUiScope.launch { view.dismiss() } // default behavior
is AdaptyUIAction.AndroidSystemBackAction ->
mainUiScope.launch { view.dismiss() } // not handled by default
is AdaptyUIAction.OpenUrlAction ->
AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior
else -> Unit
}
}Flow aksiyonlarını yönetme kılavuzuna tüm aksiyonların listesi için bakın.
Paywall Builder ile yapılandırılmış paywalllar, satın alma yapmak veya geri yüklemek için ekstra kod gerektirmez. Ancak uygulamanızın yanıt verebileceği bazı olaylar üretirler. Bu olaylar; düğme basışlarını (kapat düğmeleri, URL’ler, ürün seçimleri vb.) ve paywall üzerinde gerçekleştirilen satın alma ile ilgili aksiyonlara dair bildirimleri kapsar. Bu olaylara nasıl yanıt vereceğinizi aşağıda öğrenebilirsiniz.
Bu kılavuz yalnızca yeni Paywall Builder paywallları içindir.
Mobil uygulamanızdaki paywall ekranında gerçekleşen süreçleri kontrol etmek veya izlemek için AdaptyUIPaywallsEventsObserver arayüz metotlarını uygulayın. Bazı metotların, yaygın senaryoları otomatik olarak işleyen varsayılan uygulamaları mevcuttur.
Bu metotlar, paywall olaylarına özel mantığınızı eklediğiniz yerlerdir. Paywallı kapatmak için view.dismiss() kullanabilir ya da ihtiyacınıza göre herhangi bir özel davranış uygulayabilirsiniz.
Kullanıcı kaynaklı olaylar
Paywallın görünmesi ve kaybolması
Bir paywall belirdiğinde veya kaybolduğunda bu metodlar çağrılır:
override fun paywallViewDidAppear(view: AdaptyUIPaywallView) {
// Handle paywall appearance
// You can track analytics or update UI here
}
override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) {
// Handle paywall disappearance
// You can track analytics or update UI here
}- iOS’ta, kullanıcı bir paywall içindeki web paywall butonuna tıkladığında ve uygulama içi tarayıcıda bir web paywall açıldığında
paywallViewDidAppearda çağrılır. - iOS’ta, bir paywalldan açılan web paywall uygulama içi tarayıcıdan ekranda kaybolduğunda
paywallViewDidDisappearda çağrılır.
Olay örnekleri (Genişletmek için tıklayın)
// Paywall appeared
{
// No additional data
}
// Paywall disappeared
{
// No additional data
}Ürün seçimi
Kullanıcı satın almak üzere bir ürün seçtiğinde bu metod çağrılır:
override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) {
// Handle product selection
// You can update UI or track analytics here
}Olay örneği (Genişletmek için tıklayın)
{
"productId": "premium_monthly"
}Satın alma başlatıldı
Kullanıcı satın alma sürecini başlattığında bu metod çağrılır:
override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) {
// Handle purchase start
// You can show loading indicators or track analytics here
}Olay örneği (Genişletmek için tıklayın)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
}
}Başarılı, iptal edilmiş veya bekleyen satın alma
Satın alma başarılı olduğunda bu metod çağrılır. Varsayılan olarak, kullanıcı tarafından iptal edilmedikçe paywallı otomatik olarak kapatır:
override fun paywallViewDidFinishPurchase(
view: AdaptyUIPaywallView,
product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
when (purchaseResult) {
is AdaptyPurchaseResult.Success -> {
// Check if user has access to premium features
if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) {
view.dismiss()
}
}
AdaptyPurchaseResult.Pending -> {
// Handle pending purchase (e.g., user will pay offline with cash)
}
AdaptyPurchaseResult.UserCanceled -> {
// Handle user cancellation
}
}
}Olay örnekleri (Genişletmek için tıklayın)
// Successful purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Success",
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
}
}
}
}
// Pending purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "Pending"
}
}
// User canceled purchase
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"purchaseResult": {
"type": "UserCanceled"
}
}Başarılı satın alma durumunda paywall ekranını kapatmanızı öneririz.
Başarısız satın alma
Bir hata nedeniyle satın alma başarısız olduğunda bu metod çağrılır. Bu durum; StoreKit/Google Play Billing hatalarını (ödeme kısıtlamaları, geçersiz ürünler, ağ hataları), işlem doğrulama hatalarını ve sistem hatalarını kapsar. Kullanıcının iptal etmesi durumunda ise bu metod değil, iptal sonucuyla birlikte paywallViewDidFinishPurchase tetiklenir; bekleyen ödemeler bu metodu tetiklemez.
override fun paywallViewDidFailPurchase(
view: AdaptyUIPaywallView,
product: AdaptyPaywallProduct,
error: AdaptyError
) {
// Add your purchase failure handling logic here
// For example: show error message, retry option, or custom error handling
}Olay örneği (Genişletmek için tıklayın)
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": {
"code": "purchase_failed",
"message": "Purchase failed due to insufficient funds",
"details": {
"underlyingError": "Insufficient funds in account"
}
}
}Geri yükleme başlatıldı
Kullanıcı geri yükleme sürecini başlattığında bu metod çağrılır:
override fun paywallViewDidStartRestore(view: AdaptyUIPaywallView) {
// Handle restore start
// You can show loading indicators or track analytics here
}Başarılı geri yükleme
Satın alma geri yükleme başarılı olduğunda bu metod çağrılır:
override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) {
// Add your successful restore handling logic here
// For example: show success message, update UI, or dismiss paywall
// Check if user has access to premium features
if (profile.accessLevels["premium"]?.isActive == true) {
view.dismiss()
}
}Olay örneği (Genişletmek için tıklayın)
{
"profile": {
"accessLevels": {
"premium": {
"id": "premium",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
},
"subscriptions": [
{
"vendorProductId": "premium_monthly",
"isActive": true,
"expiresAt": "2024-02-15T10:30:00Z"
}
]
}
}Kullanıcının gerekli accessLevel’a sahip olması durumunda ekranı kapatmanızı öneririz. Bunu nasıl kontrol edeceğinizi öğrenmek için Abonelik durumu konusuna bakın.
Başarısız geri yükleme
Adapty.restorePurchases() başarısız olduğunda bu metod çağrılır:
override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) {
// Add your restore failure handling logic here
// For example: show error message, retry option, or custom error handling
}Olay örneği (Genişletmek için tıklayın)
{
"error": {
"code": "restore_failed",
"message": "Purchase restoration failed",
"details": {
"underlyingError": "No previous purchases found"
}
}
}Web ödeme navigasyonu tamamlandı
Kullanıcı web paywall üzerinden satın alma sürecini başlattığında bu metod çağrılır:
override fun paywallViewDidFinishWebPaymentNavigation(
view: AdaptyUIPaywallView,
product: AdaptyPaywallProduct?,
error: AdaptyError?
) {
if (error != null) {
// Handle web payment navigation error
} else {
// Handle successful web payment navigation
}
}Olay örnekleri (Genişletmek için tıklayın)
// Successful web payment navigation
{
"product": {
"vendorProductId": "premium_monthly",
"localizedTitle": "Premium Monthly",
"localizedDescription": "Premium subscription for 1 month",
"localizedPrice": "$9.99",
"price": 9.99,
"currencyCode": "USD"
},
"error": null
}
// Failed web payment navigation
{
"product": null,
"error": {
"code": "web_payment_failed",
"message": "Web payment navigation failed",
"details": {
"underlyingError": "Network connection error"
}
}
}Veri çekme ve render etme
Ürün yükleme hataları
Başlatma sırasında ürünleri siz geçmezseniz AdaptyUI gerekli nesneleri sunucudan kendi alır. Bu işlem başarısız olursa AdaptyUI hatayı bu metodu çağırarak bildirir:
override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) {
// Add your product loading failure handling logic here
// For example: show error message, retry option, or custom error handling
}Olay örneği (Genişletmek için tıklayın)
{
"error": {
"code": "products_loading_failed",
"message": "Failed to load products from the server",
"details": {
"underlyingError": "Network timeout"
}
}
}Render hataları
Arayüz render edilirken bir hata oluşursa bu metod aracılığıyla bildirilir:
override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {
// Handle rendering error
// In a normal situation, such errors should not occur
// If you come across one, please let us know
}Olay örneği (Genişletmek için tıklayın)
{
"error": {
"code": "rendering_failed",
"message": "Failed to render paywall interface",
"details": {
"underlyingError": "Invalid paywall configuration"
}
}
}Normal şartlarda bu tür hatalar oluşmamalıdır; eğer böyle bir hatayla karşılaşırsanız lütfen bize bildirin.