Ö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_purchasepaketi (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.

Yorumlar (0)
Yorum Yaz