Flutter & Mobil İle Modern Uygulama İçi Satın Alma Sistemi Nasıl Yapılır?

Flutter & Mobil İle Modern Uygulama İçi Satın Alma Sistemi Nasıl Yapılır?
Flutter & Mobil İle Modern Uygulama İçi Satın Alma Sistemi Nasıl Yapılır?

Ön Hazırlık ve Gereksinimler

Uygulama içi satın alma sistemine başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. Flutter 3.x ve üzeri sürümler, yerel mağaza API'leri ile daha kararlı bir iletişim kurmaktadır. İhtiyacınız olan temel araçlar şunlardır:

  • Flutter SDK (En güncel kararlı sürüm).
  • Google Play Console ve Apple App Store Connect hesapları.
  • in_app_purchase paketi (Resmi Flutter eklentisi).
  • Test cihazları (Fiziksel Android veya iOS cihazlar).

Geliştirme aşamasında emülatörler yerine fiziksel cihazlar kullanmanız, mağaza süreçlerini test etmek için zorunludur. Ayrıca, her iki mağaza için de "Sandbox" veya "Internal Testing" hesaplarını tanımlamış olmanız gerekmektedir.

Proje Yapılandırması ve Bağımlılıklar

İlk adım olarak projenize gerekli paketi eklemeniz gerekir. pubspec.yaml dosyanıza aşağıdaki satırı ekleyerek bağımlılıkları güncelleyin. Bu paket, hem Android (Google Billing Library) hem de iOS (StoreKit) için ortak bir arayüz sağlar.

dependencies:
  flutter:
    sdk: flutter
  in_app_purchase: ^3.2.0

Terminal üzerinden flutter pub get komutunu çalıştırarak paketi projenize dahil edin. Bu paket, mağaza ile doğrudan iletişim kuran katmanı yönetir.

Ürün Tanımlama ve Mağaza Entegrasyonu

Satın alınabilir ürünleri kodunuzda değil, mağaza konsollarında tanımlamanız gerekir. Ürün kimlikleri (Product ID), her iki platformda da aynı olmalıdır. Örneğin; "premium_aylik" gibi bir ID, hem Google Play hem de App Store tarafında tanımlanmalıdır.

Aşağıdaki kod bloğu, mağazadan ürün listesini çekmek için kullanılan temel yapıyı gösterir:

final InAppPurchase _inAppPurchase = InAppPurchase.instance;

Future urunleriGetir() async {
  final bool available = await _inAppPurchase.isAvailable();
  if (!available) {
    return;
  }
  const Set _kIds = {'premium_aylik', 'premium_yillik'};
  final ProductDetailsResponse response = await _inAppPurchase.queryProductDetails(_kIds);
  if (response.notFoundIDs.isNotEmpty) {
    // Tanımlanmamış ürün hatası
  }
  List urunler = response.productDetails;
}

Bu kod, mağazanın erişilebilirliğini kontrol eder ve tanımladığınız ürünlerin detaylarını (fiyat, başlık, açıklama) çekerek uygulamanıza aktarır.

Satın Alma Akışını Başlatma

Kullanıcı bir ürünü seçtiğinde, satın alma işlemini tetikleyen bir akış oluşturmalısınız. Bu aşamada PurchaseParam nesnesi kullanılır. Satın alma işlemi asenkron bir süreçtir ve mağazadan dönen yanıtları dinlemeniz gerekir.

void satisBaslat(ProductDetails productDetails) {
  final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
  _inAppPurchase.buyNonConsumable(purchaseParam: purchaseParam);
}

Burada buyNonConsumable yöntemi, tek seferlik satın almalar (premium özellikler gibi) için kullanılır. Tüketilebilir öğeler (oyun içi para birimi gibi) için buyConsumable kullanılmalıdır.

Satın Alma İşlemlerini Dinleme ve Doğrulama

Satın alma işleminin sonucunu dinlemek için StreamSubscription yapısını kullanmalısınız. Bu, uygulamanızın herhangi bir yerinde gerçekleşen satın alma güncellemelerini yakalamanızı sağlar.

late StreamSubscription _subscription;

void dinleyiciyiBaslat() {
  final Stream purchaseUpdated = _inAppPurchase.purchaseStream;
  _subscription = purchaseUpdated.listen((purchaseDetailsList) {
    for (var purchaseDetails in purchaseDetailsList) {
      if (purchaseDetails.status == PurchaseStatus.purchased) {
        // Satın alma başarılı, sunucu tarafında doğrula
        veritabaniGuncelle(purchaseDetails);
      }
    }
  });
}

Bu dinleyici, uygulama açık olduğu sürece arka planda çalışır. İşlem başarılı olduğunda, kullanıcıya içeriği açan mantığı burada tetiklemelisiniz.

Uygulama İçi Satın Alma Yöntemleri Karşılaştırması

Yöntem Kullanım Alanı Avantajı
Non-Consumable Premium üyelik, Reklam kaldırma Kullanıcı bir kez alır, her cihazda erişir.
Consumable Oyun parası, İpucu Tekrar tekrar satın alınabilir.
Subscription Haftalık/Aylık içerik erişimi Düzenli gelir sağlar.
Kritik Güvenlik Uyarısı: Satın alma işlemlerini asla sadece cihaz üzerinde doğrulamayın. Başarılı bir satın alma işleminden sonra, mağazadan dönen "receipt" verisini kendi backend sunucunuza göndererek Google veya Apple API'leri üzerinden sunucu taraflı doğrulama (Server-side verification) yapın. Aksi takdirde, uygulama manipüle edilerek sahte satın almalar gerçekleştirilebilir.

Sıkça Sorulan Sorular

Satın alma işlemi neden test cihazında hata veriyor?

Genellikle mağaza konsolunda ürünlerin "Active" durumunda olmaması veya test kullanıcısının doğru yapılandırılmamasından kaynaklanır. Ayrıca, uygulamanızın "Release" imzası ile imzalanmış olması gerekebilir.

Kullanıcı uygulamayı sildiğinde satın aldığı ürünler kaybolur mu?

Hayır. Satın alma bilgileri mağaza hesabına bağlıdır. Uygulama tekrar yüklendiğinde, restorePurchases() metodu ile geçmiş satın almalar geri yüklenebilir.

Sunucu taraflı doğrulama neden zorunludur?

İstemci tarafındaki kodlar, kötü niyetli kullanıcılar tarafından değiştirilebilir. Sunucu taraflı doğrulama, işlemin gerçekliğini mağazanın kendi API'leri ile teyit ederek güvenliği sağlar.

Abonelik iptalleri nasıl yönetilir?

Abonelik iptalleri mağaza üzerinden yapılır. Uygulamanızda, kullanıcının abonelik durumunu her açılışta sunucunuzdan kontrol ederek güncel tutmalısınız.

Hangi durumlarda "Consumable" kullanılmalıdır?

Kullanıcı bir öğeyi tükettiğinde tekrar ihtiyaç duyuyorsa (örneğin oyun içi altın veya ek haklar) mutlaka "Consumable" olarak tanımlanmalıdır.

İleri Seviye Hata Ayıklama ve Loglama Stratejileri

Uygulama içi satın alma süreçlerinde karşılaşılan hataların çoğu, mağaza tarafındaki konfigürasyon eksikliklerinden veya ağ kesintilerinden kaynaklanır. Kullanıcı deneyimini korumak için, satın alma akışının her aşamasını detaylı bir şekilde loglamanız kritik öneme sahiptir.

Satın Alma Hata Kodlarını Yönetme

in_app_purchase paketi, hata durumunda IAPError nesnesi döndürür. Bu nesneyi yakalayarak kullanıcıya anlamlı geri bildirimler sunmalı ve hatayı analiz edebilmek için bir loglama servisine (Firebase Crashlytics gibi) göndermelisiniz.

void handlePurchaseError(IAPError error) {
  // Hata koduna göre kullanıcıya özel mesaj göster
  switch (error.code) {
    case 'purchase_cancelled':
      print("Kullanıcı işlemi iptal etti.");
      break;
    case 'purchase_error':
      print("Satın alma sırasında bir hata oluştu: ${error.message}");
      break;
    default:
      print("Bilinmeyen hata: ${error.code}");
  }
  // Hata detaylarını analiz için logla
  FirebaseCrashlytics.instance.recordError(error.message, StackTrace.current);
}

Performans Optimizasyonu ve Satın Alma Deneyimi

Satın alma ekranlarının hızlı açılması, dönüşüm oranlarını doğrudan etkiler. Mağaza verilerini her seferinde API çağrısı ile çekmek yerine, yerel bir önbellekleme mekanizması kurmalısınız.

Veri Senkronizasyonu ve Önbellekleme

Uygulama başladığında queryProductDetails metodunu çağırıp sonuçları bir StateManagement çözümünde (Provider, Bloc veya Riverpod) tutun. Böylece kullanıcı "Satın Al" butonuna bastığında, ürün bilgileri zaten bellekte hazır olacaktır.

Strateji Avantajı Uygulama
Lazy Loading Daha hızlı ilk açılış Satın alma ekranı açıldığında veriyi çek
Local Caching Çevrimdışı erişim Ürün detaylarını SharedPreferences ile sakla
Retry Logic Daha yüksek başarı oranı Bağlantı hatalarında 3 kez otomatik tekrar dene

Satın Alma İşlemlerinde "Retry" Mekanizması

Ağ hataları nedeniyle satın alma işlemi tamamlanamazsa, kullanıcıyı döngüde bırakmak yerine akıllı bir tekrar deneme mekanizması kurun:

Future buyProductWithRetry(ProductDetails product, int attempt) async {
  try {
    final PurchaseParam purchaseParam = PurchaseParam(productDetails: product);
    await _inAppPurchase.buyNonConsumable(purchaseParam: purchaseParam);
  } catch (e) {
    if (attempt < 3) {
      await Future.delayed(Duration(seconds: 2 * attempt));
      return buyProductWithRetry(product, attempt + 1);
    } else {
      rethrow;
    }
  }
}

Bu yöntem, özellikle internet bağlantısının kararsız olduğu mobil ağlarda kullanıcı memnuniyetini ciddi oranda artıracaktır. Unutmayın, satın alma süreci "atomik" olmalıdır; yani ya tamamen gerçekleşmeli ya da hiçbir şey olmamış gibi sistem eski haline dönmelidir.

Sonuç

Flutter ile uygulama içi satın alma sistemi kurmak, başlangıçta karmaşık görünse de doğru yapılandırıldığında oldukça güvenli ve ölçeklenebilir bir süreçtir. Bu rehberde öğrendiğiniz adımları takip ederek, ürünlerinizi tanımlayabilir, satın alma akışlarını yönetebilir ve kullanıcılarınız için profesyonel bir ödeme deneyimi sunabilirsiniz. Bir sonraki adım olarak, sunucu taraflı doğrulama için Node.js veya Firebase Cloud Functions kullanarak kendi doğrulama servisinizi oluşturmanızı öneririm.

Sorumluluk Reddi: Bu makalede paylaşılan kodlar eğitim amaçlıdır. Uygulamanızın finansal verileri ve ödeme süreçleri ile ilgili güvenlik sorumluluğu tamamen geliştiriciye aittir. Üretim ortamına geçmeden önce tüm süreçleri kapsamlı bir şekilde test etmeniz ve güncel mağaza politikalarını (Google Play ve App Store) takip etmeniz tavsiye edilir.
Bu yazıya tepkinizi paylaşın:
Burak Yılmaz

Mutfak teknikleri ve pratik gastronomi ipuçları üzerine beş yıllık deneyime sahibim. Okuyucuların mutfak süreçlerini hızlandıracak ve kolaylaştıracak rehberler hazırlıyorum.

Yorumlar (0)

Yorum Yaz