Flutter & Mobil İle İleri Düzey Uygulama İçi Satın Alma Sistemi Nasıl Yapılır?

Flutter & Mobil İle İleri Düzey Uygulama İçi Satın Alma Sistemi Nasıl Yapılır?
Flutter & Mobil İle İleri Düzey Uygulama İçi Satın Alma Sistemi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Başarılı bir entegrasyon için öncelikle geliştirme ortamınızın güncel olduğundan emin olmalısınız. 2026 standartlarında Flutter 3.x veya üzeri bir sürüm kullanmanız, performans ve güvenlik güncellemelerinden yararlanmanız için kritiktir.

  • Flutter SDK (En güncel kararlı sürüm).
  • Google Play Console ve Apple App Store Connect geliştirici hesapları.
  • in_app_purchase resmi Flutter paketi.
  • Backend doğrulama için bir sunucu (Node.js veya Firebase Cloud Functions önerilir).

Projenizin pubspec.yaml dosyasına gerekli paketi ekleyerek işe başlayın:

dependencies:
  flutter:
    sdk: flutter
  in_app_purchase: ^3.2.0

Paketi ekledikten sonra terminalde flutter pub get komutunu çalıştırarak bağımlılıkları güncelleyin. Ayrıca, Android için AndroidManifest.xml dosyasına com.android.vending.BILLING iznini eklemeyi unutmayın.

Uygulama İçi Satın Alma Yöntemlerinin Karşılaştırılması

Satın alma süreçlerinde farklı yöntemler mevcuttur. İhtiyacınıza göre en uygun olanı seçmek için aşağıdaki tabloyu inceleyebilirsiniz.

Yöntem Avantajı Dezavantajı
Tüketilebilir (Consumable) Sürekli tekrar satın alınabilir. Veri takibi daha karmaşıktır.
Abonelik (Subscription) Düzenli gelir sağlar. Yenileme süreçlerini yönetmek zordur.
Tek Seferlik (Non-consumable) Basit entegrasyon. Tekrar satın alma yoktur.

Adım Adım Satın Alma Akışını Kurma

Satın alma akışı, ürünlerin mağazadan çekilmesi, kullanıcının satın alma işlemini başlatması ve işlemin doğrulanması olmak üzere üç ana aşamadan oluşur. İlk olarak, mağazadaki ürünleri listelemek için bir servis katmanı oluşturalım.

import 'package:in_app_purchase/in_app_purchase.dart';

class IAPService {
  final InAppPurchase _iap = InAppPurchase.instance;

  Future fetchProducts(Set productIds) async {
    final ProductDetailsResponse response = await _iap.queryProductDetails(productIds);
    if (response.notFoundIDs.isNotEmpty) {
      // Hata yönetimi
    }
    return response.productDetails;
  }
}

Bu kod bloğu, Google Play veya App Store üzerinden tanımladığınız ürün kimliklerini (ID) sorgular ve mevcut ürün detaylarını döndürür. Ürün ID'leriniz, her iki mağaza panelinde de tanımlanmış olmalıdır.

Satın Alma İşlemini Başlatma ve Dinleme

Satın alma işlemi başlatıldığında, mağaza arayüzü kullanıcıya gösterilir. Bu süreçte işlemin durumunu dinlemek (listen) hayati önem taşır. Aksi takdirde, satın alma tamamlanmış olsa bile kullanıcıya ürün teslim edilemeyebilir.

void listenToPurchaseUpdates() {
  _iap.purchaseStream.listen((List purchaseDetailsList) {
    for (var purchaseDetails in purchaseDetailsList) {
      if (purchaseDetails.status == PurchaseStatus.purchased) {
        _verifyPurchase(purchaseDetails);
      } else if (purchaseDetails.status == PurchaseStatus.error) {
        // Hata durumunu yönet
      }
    }
  });
}

purchaseStream, satın alma sürecindeki tüm güncellemeleri anlık olarak dinler. PurchaseStatus.purchased durumu, işlemin başarıyla tamamlandığını gösterir.

Kritik Güvenlik Uyarısı: Satın alma işlemlerini asla sadece cihaz üzerinde (client-side) doğrulamayın. Kullanıcının satın alma token'ını kendi backend sunucunuza göndererek Google veya Apple API'leri üzerinden sunucu taraflı doğrulama (server-side verification) yapmanız zorunludur. Bu, "hacker" müdahalelerini ve sahte satın alımları engellemek için tek yoldur.

Sunucu Taraflı Doğrulama (Server-Side Verification)

Güvenli bir sistem için satın alma token'ını bir API'ye göndermelisiniz. İşte temel bir doğrulama mantığı:

Future _verifyPurchase(PurchaseDetails purchaseDetails) async {
  final String token = purchaseDetails.verificationData.serverVerificationData;
  // Backend'e token gönderimi
  final response = await http.post(Uri.parse('https://api.uygulamaniz.com/verify'),
    body: {'token': token});
    
  if (response.statusCode == 200) {
    // Ürünü kullanıcıya teslim et
    _iap.completePurchase(purchaseDetails);
  }
}

completePurchase metodunu çağırmak, mağazaya işlemin başarıyla sonuçlandığını ve ürünün teslim edildiğini bildirir. Bunu yapmazsanız, mağaza işlemi "tamamlanmamış" olarak görür ve kullanıcıya geri ödeme yapabilir.

Hata Yönetimi ve Debug İpuçları

Uygulama içi satın alma süreçlerinde en sık karşılaşılan sorunlar, mağaza bağlantı hataları ve doğrulama başarısızlıklarıdır. Geliştirme aşamasında "Sandbox" veya "Test Track" ortamlarını kullanmanız şarttır.

// Hata yakalama örneği
try {
  await _iap.buyNonConsumable(purchaseParam: purchaseParam);
} catch (e) {
  print("Satın alma hatası: $e");
}

Hataları kullanıcıya anlamlı mesajlarla iletmek, kullanıcı deneyimini (UX) doğrudan etkiler. Örneğin, "İnternet bağlantınızı kontrol edin" veya "Mağaza şu an yanıt vermiyor" gibi bilgilendirici uyarılar kullanın.

Sıkça Sorulan Sorular

Uygulama içi satın alma testlerini nasıl yaparım?

Android için Google Play Console'da "Internal App Sharing" veya "Closed Testing" kanallarını kullanmalısınız. iOS için ise "Sandbox" kullanıcıları oluşturarak test gerçekleştirebilirsiniz.

Satın alma token'ı neden backend'e gönderilmeli?

Cihaz üzerinde yapılan doğrulamalar, manipülasyona açıktır. Sunucu taraflı doğrulama, mağazaların kendi API'leri ile doğrudan iletişim kurarak işlemin gerçekliğini teyit eder.

Abonelik iptallerini nasıl takip ederim?

Abonelikler için mağazaların "Real-time Developer Notifications" (RTDN) servislerini kullanmalısınız. Bu servis, abonelik durumu değiştiğinde sunucunuza bir webhook gönderir.

Neden ürünlerim mağazada "bulunamadı" hatası veriyor?

Ürün ID'lerinin mağaza panelinde "Active" durumunda olduğundan ve paket adınızın (package name/bundle ID) mağaza ile birebir eşleştiğinden emin olun.

Satın alma işlemi tamamlandıktan sonra ürün teslim edilmezse ne olur?

completePurchase metodunu çağırmadığınız sürece, mağaza işlemi açık tutar ve birkaç gün içinde kullanıcıya otomatik para iadesi yapabilir. Bu yüzden her başarılı işlem mutlaka tamamlanmalıdır.

Sorumluluk Reddi: Bu rehberde paylaşılan kodlar eğitim amaçlıdır. Ödeme sistemleri, finansal veriler ve kullanıcı güvenliği ile ilgili süreçlerde her zaman en güncel resmi API dokümantasyonlarını takip etmeli ve güvenlik standartlarına uygun hareket etmelisiniz.

Uygulama İçi Satın Alma Süreçlerinde Performans Optimizasyonu

Satın alma süreçlerinin kullanıcı deneyimini bozmaması için performans kritik bir rol oynar. Özellikle uygulama ilk açıldığında ürün listesinin (SKU) yüklenmesi, ağ gecikmelerinden dolayı kullanıcıyı bekletebilir. Bu durumu yönetmek için "Lazy Loading" ve "Caching" stratejilerini uygulamalısınız.

Ürün Listesini Yerel Bellekte Önbelleğe Alma

Ürün fiyatlarını ve bilgilerini her seferinde Google Play veya App Store API'sinden çekmek yerine, ilk başarılı çekimden sonra yerel bir veritabanında (örneğin shared_preferences veya hive) saklayabilirsiniz. Böylece kullanıcı internet bağlantısı yavaş olsa bile arayüzü görebilir.


Future cacheProductDetails(List products) async {
  final prefs = await SharedPreferences.getInstance();
  final productJson = products.map((p) => p.id).toList();
  await prefs.setStringList('cached_products', productJson);
}

Future getCachedProducts() async {
  final prefs = await SharedPreferences.getInstance();
  return prefs.getStringList('cached_products');
}

İleri Düzey Güvenlik: Satın Alma İmzalarını Doğrulama

Sunucu taraflı doğrulamanın ötesinde, uygulama içerisinde de satın alma işleminin bütünlüğünü kontrol etmek, "man-in-the-middle" saldırılarına karşı ek bir savunma katmanı sağlar. Özellikle Android tarafında, Purchase nesnesi içindeki signature ve originalJson alanlarını kendi sunucunuzdaki genel anahtar (public key) ile doğrulamak, işlemin mağazadan geldiğini kesinleştirir.

Güvenlik Kontrol Listesi

  • İmza Doğrulama: Satın alma verisinin manipüle edilmediğinden emin olun.
  • Nonce Kullanımı: İsteklerin tekrar oynatılmasını (replay attack) engellemek için her satın alma isteğinde benzersiz bir token (nonce) oluşturun.
  • Obfuscation: Kodunuzu yayınlarken mutlaka --obfuscate ve --split-debug-info parametrelerini kullanarak tersine mühendisliği zorlaştırın.

// Örnek: Satın alma imzasının uygulama tarafında basit kontrolü
bool verifyPurchaseSignature(Purchase purchase, String publicKey) {
  // Burada RSA veya ilgili kriptografik kütüphaneler ile 
  // purchase.signature ve purchase.originalJson doğrulanmalıdır.
  // Bu işlem, sunucu doğrulamasının bir ön adımı olarak kullanılabilir.
  return true; // Doğrulama başarılı ise
}

Dağıtım Öncesi Son Kontroller

Uygulamanızı mağazaya göndermeden önce şu senaryoları mutlaka test edin:

  1. İnternet Kesintisi: Satın alma işlemi sırasında internet kesilirse, uygulama tekrar açıldığında restorePurchases metodunun tetiklendiğinden emin olun.
  2. Kullanıcı İptali: Kullanıcı ödeme ekranını kapatırsa, uygulamanın "kullanıcı vazgeçti" durumunu doğru yönettiğini ve bir hata mesajı göstermediğini doğrulayın.
  3. Farklı Cihazlar: Aynı Google/Apple hesabı ile farklı cihazlarda satın alma geçmişinin senkronize olup olmadığını kontrol edin.

Sonuç

Flutter ile ileri düzey bir uygulama içi satın alma sistemi kurmak, dikkatli bir planlama ve güvenli bir altyapı gerektirir. Bu rehberde; ürünleri çekme, satın alma akışını yönetme, sunucu taraflı doğrulama yapma ve hata yönetimi konularını adım adım ele aldık. Bir sonraki adım olarak, abonelik yönetimi için sunucu tarafında bir webhook alıcısı yazmayı ve kullanıcıların satın alma geçmişlerini veritabanınızda tutmayı hedefleyebilirsiniz. Uygulamanızın gelir modellerini güçlendirmek için bu temelleri sağlamlaştırmak en önemli önceliğiniz olmalıdır.

Bu yazıya tepkinizi paylaşın:
Selin Korkmaz

Kendin yap (DIY) projeleri ve sürdürülebilir yaşam ipuçları üzerine odaklanıyorum. Okuyucularıma bütçe dostu ve yaratıcı çözüm önerileri sunmaktan keyif alıyorum.

Yorumlar (0)

Yorum Yaz