Mobil Araçlar Rehberi (Mobile Tools Guide)
Mobil uygulama geliştirmede kullanılan temel araçlar, servisler ve kütüphaneler. Firebase, bildirim sistemleri, BaaS platformları, UI kütüphaneleri, veritabanları, CI/CD, test araçları ve paket yönetimi konularını kapsar.
1. Firebase
Firebase Nedir? (What is Firebase?)
Firebase, Google tarafından sunulan kapsamlı bir mobil ve web uygulama geliştirme platformudur (comprehensive app development platform). Backend altyapısı kurmadan (without setting up backend infrastructure) kimlik doğrulama, veritabanı, dosya depolama, bildirim ve analitik gibi servisleri hazır olarak sunar.
Resmi Site (Official Site): https://firebase.google.com
Firebase Servisleri Tablosu (Firebase Services Table)
| Servis (Service) | Kategori (Category) | Açıklama (Description) | Ücretsiz Katman (Free Tier) |
|---|---|---|---|
| Authentication | Kimlik Doğrulama | Email, Google, Apple, Phone, Anonymous | Sınırsız (Unlimited) |
| Cloud Firestore | Veritabanı (Database) | NoSQL belge tabanlı DB (document-based) | 1 GiB depolama, 50K okuma/gün |
| Realtime Database | Veritabanı (Database) | Gerçek zamanlı JSON veritabanı | 1 GB depolama, 10 GB/ay transfer |
| Cloud Storage | Dosya Depolama (File Storage) | Dosya yükleme/indirme (upload/download) | 5 GB depolama |
| Cloud Messaging (FCM) | Bildirimler (Notifications) | Push bildirim gönderimi | Sınırsız (Unlimited) |
| Crashlytics | Hata İzleme (Crash Reporting) | Gerçek zamanlı çökme raporları | Sınırsız (Unlimited) |
| Analytics | Analitik (Analytics) | Kullanıcı davranış analizi | Sınırsız (Unlimited) |
| Remote Config | Yapılandırma (Configuration) | Uzaktan uygulama ayarları | Sınırsız (Unlimited) |
| Dynamic Links | Derin Bağlantılar (Deep Links) | Platformlar arası akıllı linkler | Sınırsız (Unlimited) |
| App Distribution | Dağıtım (Distribution) | Beta test dağıtımı | Sınırsız (Unlimited) |
| Cloud Functions | Sunucusuz (Serverless) | Backend fonksiyonları | 125K çağrı/ay |
| Hosting | Barındırma (Hosting) | Statik site barındırma | 10 GB depolama, 360 MB/gün |
| Performance Monitoring | Performans (Performance) | Uygulama performans takibi | Sınırsız (Unlimited) |
| Test Lab | Test (Testing) | Gerçek cihazlarda test | 15 test/gün (sanal), 5 test/gün (fiziksel) |
Firebase Kurulumu (Firebase Setup)
React Native Kurulumu (React Native Setup)
# 1. React Native Firebase paketini yükle (Install RN Firebase)
npm install @react-native-firebase/app
# 2. İhtiyacınıza göre modül ekleyin (Add modules as needed)
npm install @react-native-firebase/auth
npm install @react-native-firebase/firestore
npm install @react-native-firebase/storage
npm install @react-native-firebase/messaging
npm install @react-native-firebase/crashlytics
npm install @react-native-firebase/analytics
# 3. iOS bağımlılıklarını yükleyin (Install iOS dependencies)
cd ios && pod install && cd ..React Native yapılandırma adımları (Configuration Steps):
- Firebase Console'dan yeni proje oluşturun (Create new project from Firebase Console)
- iOS uygulaması ekleyin →
GoogleService-Info.plistdosyasınıios/klasörüne koyun - Android uygulaması ekleyin →
google-services.jsondosyasınıandroid/app/klasörüne koyun android/build.gradledosyasına Google Services plugin ekleyin:
// android/build.gradle
buildscript {
dependencies {
// ... mevcut bağımlılıklar (existing dependencies)
classpath 'com.google.gms:google-services:4.4.2'
}
}// android/app/build.gradle
apply plugin: 'com.google.gms.google-services'- iOS için
AppDelegate.mmdosyasını güncelleyin:
#import <Firebase.h>
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[FIRApp configure]; // Firebase başlat (Initialize Firebase)
// ... diğer kodlar (other code)
}Flutter Kurulumu (Flutter Setup)
# 1. Firebase CLI ve FlutterFire CLI yükleyin (Install Firebase CLI & FlutterFire CLI)
npm install -g firebase-tools
dart pub global activate flutterfire_cli
# 2. Firebase'e giriş yapın (Login to Firebase)
firebase login
# 3. FlutterFire yapılandırması (FlutterFire configuration)
flutterfire configure
# 4. Gerekli paketleri ekleyin (Add required packages)
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore
flutter pub add firebase_storage
flutter pub add firebase_messaging
flutter pub add firebase_crashlytics
flutter pub add firebase_analyticsFlutter yapılandırma (Flutter Configuration):
// lib/main.dart
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart'; // FlutterFire CLI tarafından oluşturulur (generated by FlutterFire CLI)
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}Authentication (Kimlik Doğrulama)
Firebase Authentication birden fazla kimlik doğrulama yöntemi destekler (supports multiple auth methods).
Email/Password Authentication
React Native:
import auth from '@react-native-firebase/auth';
// Kayıt (Register)
async function register(email, password) {
try {
const userCredential = await auth().createUserWithEmailAndPassword(email, password);
console.log('Kullanıcı oluşturuldu (User created):', userCredential.user.uid);
return userCredential.user;
} catch (error) {
if (error.code === 'auth/email-already-in-use') {
console.log('Bu email zaten kullanımda (Email already in use)');
}
if (error.code === 'auth/invalid-email') {
console.log('Geçersiz email adresi (Invalid email)');
}
throw error;
}
}
// Giriş (Login)
async function login(email, password) {
try {
const userCredential = await auth().signInWithEmailAndPassword(email, password);
console.log('Giriş başarılı (Login successful):', userCredential.user.uid);
return userCredential.user;
} catch (error) {
if (error.code === 'auth/user-not-found') {
console.log('Kullanıcı bulunamadı (User not found)');
}
if (error.code === 'auth/wrong-password') {
console.log('Yanlış şifre (Wrong password)');
}
throw error;
}
}
// Çıkış (Logout)
async function logout() {
await auth().signOut();
console.log('Çıkış yapıldı (Signed out)');
}
// Oturum durumu dinleyici (Auth state listener)
auth().onAuthStateChanged((user) => {
if (user) {
console.log('Kullanıcı giriş yapmış (User signed in):', user.uid);
} else {
console.log('Kullanıcı çıkış yapmış (User signed out)');
}
});Flutter:
import 'package:firebase_auth/firebase_auth.dart';
final FirebaseAuth _auth = FirebaseAuth.instance;
// Kayıt (Register)
Future<User?> register(String email, String password) async {
try {
final credential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
print('Kullanıcı oluşturuldu: ${credential.user?.uid}');
return credential.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'email-already-in-use') {
print('Bu email zaten kullanımda');
}
rethrow;
}
}
// Giriş (Login)
Future<User?> login(String email, String password) async {
try {
final credential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
return credential.user;
} on FirebaseAuthException catch (e) {
print('Giriş hatası: ${e.message}');
rethrow;
}
}
// Oturum durumu dinleyici (Auth state listener)
_auth.authStateChanges().listen((User? user) {
if (user != null) {
print('Kullanıcı giriş yapmış: ${user.uid}');
} else {
print('Kullanıcı çıkış yapmış');
}
});Google Sign-In
React Native:
import { GoogleSignin } from '@react-native-google-signin/google-signin';
import auth from '@react-native-firebase/auth';
// Yapılandırma (Configuration)
GoogleSignin.configure({
webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
});
async function googleSignIn() {
// Google giriş ekranını aç (Open Google sign-in screen)
const { idToken } = await GoogleSignin.signIn();
// Firebase credential oluştur (Create Firebase credential)
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Firebase ile giriş yap (Sign in with Firebase)
return auth().signInWithCredential(googleCredential);
}Flutter:
import 'package:google_sign_in/google_sign_in.dart';
Future<UserCredential> googleSignIn() async {
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
final GoogleSignInAuthentication? googleAuth = await googleUser?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
return await FirebaseAuth.instance.signInWithCredential(credential);
}Apple Sign-In
React Native:
import { appleAuth } from '@invertase/react-native-apple-authentication';
import auth from '@react-native-firebase/auth';
async function appleSignIn() {
// Apple giriş isteği (Apple sign-in request)
const appleAuthResponse = await appleAuth.performRequest({
requestedOperation: appleAuth.Operation.LOGIN,
requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
});
const { identityToken, nonce } = appleAuthResponse;
const appleCredential = auth.AppleAuthProvider.credential(identityToken, nonce);
return auth().signInWithCredential(appleCredential);
}Phone Authentication (Telefon ile Doğrulama)
React Native:
import auth from '@react-native-firebase/auth';
// SMS kodu gönder (Send SMS code)
async function sendVerificationCode(phoneNumber) {
const confirmation = await auth().signInWithPhoneNumber(phoneNumber);
return confirmation; // Doğrulama nesnesini sakla (Store confirmation object)
}
// SMS kodunu doğrula (Verify SMS code)
async function verifyCode(confirmation, code) {
try {
await confirmation.confirm(code);
console.log('Telefon doğrulaması başarılı (Phone verification successful)');
} catch (error) {
console.log('Geçersiz kod (Invalid code)');
}
}Firestore (Bulut Veritabanı / Cloud Database)
Cloud Firestore, Firebase'in NoSQL belge tabanlı bulut veritabanıdır (NoSQL document-based cloud database). Gerçek zamanlı senkronizasyon (real-time sync) ve çevrimdışı destek (offline support) sunar.
CRUD İşlemleri (CRUD Operations)
React Native:
import firestore from '@react-native-firebase/firestore';
// ---------- CREATE (Oluşturma) ----------
// Otomatik ID ile belge ekle (Add document with auto ID)
async function addUser(userData) {
const docRef = await firestore().collection('users').add({
name: userData.name,
email: userData.email,
age: userData.age,
createdAt: firestore.FieldValue.serverTimestamp(),
});
console.log('Belge eklendi, ID (Document added, ID):', docRef.id);
return docRef.id;
}
// Belirli ID ile belge oluştur (Create document with specific ID)
async function setUser(userId, userData) {
await firestore().collection('users').doc(userId).set({
name: userData.name,
email: userData.email,
age: userData.age,
updatedAt: firestore.FieldValue.serverTimestamp(),
});
}
// ---------- READ (Okuma) ----------
// Tek belge oku (Read single document)
async function getUser(userId) {
const doc = await firestore().collection('users').doc(userId).get();
if (doc.exists) {
console.log('Kullanıcı verisi (User data):', doc.data());
return { id: doc.id, ...doc.data() };
} else {
console.log('Belge bulunamadı (Document not found)');
return null;
}
}
// Tüm belgeleri oku (Read all documents)
async function getAllUsers() {
const snapshot = await firestore().collection('users').get();
const users = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data(),
}));
return users;
}
// ---------- UPDATE (Güncelleme) ----------
// Belge güncelle (Update document)
async function updateUser(userId, updates) {
await firestore().collection('users').doc(userId).update({
...updates,
updatedAt: firestore.FieldValue.serverTimestamp(),
});
}
// Belirli alanı artır (Increment specific field)
async function incrementLoginCount(userId) {
await firestore().collection('users').doc(userId).update({
loginCount: firestore.FieldValue.increment(1),
});
}
// Diziye eleman ekle (Add element to array)
async function addFavorite(userId, itemId) {
await firestore().collection('users').doc(userId).update({
favorites: firestore.FieldValue.arrayUnion(itemId),
});
}
// ---------- DELETE (Silme) ----------
// Belge sil (Delete document)
async function deleteUser(userId) {
await firestore().collection('users').doc(userId).delete();
}
// Belirli alanı sil (Delete specific field)
async function removeField(userId, fieldName) {
await firestore().collection('users').doc(userId).update({
[fieldName]: firestore.FieldValue.delete(),
});
}Sorgu ve Filtreleme (Query & Filtering)
const usersRef = firestore().collection('users');
// Basit sorgu (Simple query)
const activeUsers = await usersRef
.where('isActive', '==', true)
.get();
// Birden fazla koşul (Multiple conditions)
const filteredUsers = await usersRef
.where('age', '>=', 18)
.where('age', '<=', 30)
.where('city', '==', 'Istanbul')
.get();
// Sıralama ve limit (Ordering and limit)
const recentUsers = await usersRef
.orderBy('createdAt', 'desc')
.limit(10)
.get();
// Sayfalama (Pagination)
const firstPage = await usersRef
.orderBy('name')
.limit(20)
.get();
const lastDoc = firstPage.docs[firstPage.docs.length - 1];
const secondPage = await usersRef
.orderBy('name')
.startAfter(lastDoc)
.limit(20)
.get();
// Dizi içinde arama (Array contains)
const jsDevelopers = await usersRef
.where('skills', 'array-contains', 'JavaScript')
.get();
// Birden fazla değer arama (Where in)
const specificCities = await usersRef
.where('city', 'in', ['Istanbul', 'Ankara', 'Izmir'])
.get();Gerçek Zamanlı Dinleyici (Real-time Listener)
// Tek belge dinleyici (Single document listener)
const unsubscribeUser = firestore()
.collection('users')
.doc('user123')
.onSnapshot(
(doc) => {
if (doc.exists) {
console.log('Güncel veri (Current data):', doc.data());
}
},
(error) => {
console.error('Dinleyici hatası (Listener error):', error);
}
);
// Koleksiyon dinleyici (Collection listener)
const unsubscribeCollection = firestore()
.collection('messages')
.where('chatId', '==', 'chat123')
.orderBy('timestamp', 'desc')
.limit(50)
.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') {
console.log('Yeni mesaj (New message):', change.doc.data());
}
if (change.type === 'modified') {
console.log('Değişen mesaj (Modified message):', change.doc.data());
}
if (change.type === 'removed') {
console.log('Silinen mesaj (Removed message):', change.doc.data());
}
});
});
// Dinleyiciyi kaldır (Unsubscribe listener) - Component unmount'ta çağırın
unsubscribeUser();
unsubscribeCollection();Realtime Database vs Firestore Karşılaştırma (Comparison)
| Özellik (Feature) | Realtime Database | Cloud Firestore |
|---|---|---|
| Veri Modeli (Data Model) | Büyük JSON ağacı (Large JSON tree) | Koleksiyon ve belge (Collection & document) |
| Sorgu (Queries) | Sınırlı, tek boyutlu (Limited, single dimension) | Gelişmiş, bileşik sorgular (Advanced, composite) |
| Ölçeklenme (Scaling) | Tek bölge (Single region) | Çoklu bölge, otomatik ölçek (Multi-region, auto-scale) |
| Çevrimdışı (Offline) | Mobilde destekler | Mobil + Web destekler |
| Fiyatlandırma (Pricing) | Bant genişliği + depolama | Okuma/yazma işlem sayısı |
| Gerçek Zamanlı (Real-time) | Çok hızlı (~ms) | Hızlı (~1-2s) |
| Yapı (Structure) | Derin iç içe geçme (Deep nesting) | Düz koleksiyonlar (Flat collections) |
| İdeal Kullanım (Best For) | Sohbet, canlı durum | Karmaşık sorgular, büyük veri |
| Önerilen (Recommended) | Eski projeler, basit yapı | Yeni projeler için önerilen |
Öneri (Recommendation): Yeni projelerde Cloud Firestore kullanın. Daha güçlü sorgu yetenekleri, daha iyi ölçeklenme ve aktif geliştirme desteği sunar.
Cloud Storage (Bulut Depolama)
Dosya yükleme, indirme ve yönetme servisidir (file upload, download and management service).
import storage from '@react-native-firebase/storage';
// Dosya yükleme (Upload file)
async function uploadFile(localPath, remotePath) {
const reference = storage().ref(remotePath);
const task = reference.putFile(localPath);
// İlerleme takibi (Progress tracking)
task.on('state_changed', (snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(`Yükleniyor (Uploading): ${progress.toFixed(1)}%`);
});
await task;
const downloadURL = await reference.getDownloadURL();
console.log('İndirme URL (Download URL):', downloadURL);
return downloadURL;
}
// Profil fotoğrafı yükleme (Upload profile photo)
async function uploadProfilePhoto(userId, photoUri) {
const filename = `profile_photos/${userId}_${Date.now()}.jpg`;
const reference = storage().ref(filename);
await reference.putFile(photoUri);
const url = await reference.getDownloadURL();
// Firestore'da profil URL'sini güncelle (Update profile URL in Firestore)
await firestore().collection('users').doc(userId).update({
photoURL: url,
});
return url;
}
// Dosya silme (Delete file)
async function deleteFile(remotePath) {
await storage().ref(remotePath).delete();
console.log('Dosya silindi (File deleted)');
}
// Dosya listele (List files)
async function listFiles(folderPath) {
const result = await storage().ref(folderPath).listAll();
const urls = await Promise.all(
result.items.map(item => item.getDownloadURL())
);
return urls;
}Cloud Messaging / FCM (Push Bildirimler)
Firebase Cloud Messaging, platformlar arası push bildirim gönderme servisidir (cross-platform push notification service).
import messaging from '@react-native-firebase/messaging';
// Bildirim izni iste (Request notification permission)
async function requestPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Bildirim izni verildi (Notification permission granted)');
const token = await messaging().getToken();
console.log('FCM Token:', token);
// Token'ı sunucuya kaydet (Save token to server)
await saveTokenToServer(token);
}
return enabled;
}
// Token yenilenme dinleyici (Token refresh listener)
messaging().onTokenRefresh(async (token) => {
console.log('Yeni FCM Token:', token);
await saveTokenToServer(token);
});
// Ön planda bildirim dinle (Listen for foreground notifications)
messaging().onMessage(async (remoteMessage) => {
console.log('Ön plan bildirimi (Foreground notification):', remoteMessage);
// Yerel bildirim göster (Show local notification)
showLocalNotification(remoteMessage);
});
// Arka planda bildirim dinle (Listen for background notifications)
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Arka plan bildirimi (Background notification):', remoteMessage);
});
// Bildirime tıklanınca (When notification is tapped)
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log('Bildirime tıklandı (Notification tapped):', remoteMessage.data);
// İlgili ekrana yönlendir (Navigate to relevant screen)
navigateToScreen(remoteMessage.data);
});
// Uygulama kapalıyken bildirime tıklanmış mı kontrol et (Check if app opened from notification)
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
console.log('Uygulama bildirimden açıldı (App opened from notification)');
navigateToScreen(remoteMessage.data);
}
});
// Konuya abone ol (Subscribe to topic)
await messaging().subscribeToTopic('news');
await messaging().subscribeToTopic('promotions');Crashlytics (Çökme Raporlama / Crash Reporting)
import crashlytics from '@react-native-firebase/crashlytics';
// Kullanıcı bilgisi ekle (Set user info)
crashlytics().setUserId('user123');
crashlytics().setAttribute('role', 'premium');
crashlytics().setAttributes({
email: 'user@example.com',
plan: 'premium',
});
// Özel log mesajı (Custom log message)
crashlytics().log('Kullanıcı sepete ürün ekledi (User added item to cart)');
// Hata yakala ve raporla (Catch and report error)
try {
await riskyOperation();
} catch (error) {
crashlytics().recordError(error);
crashlytics().log(`Hata detayı (Error detail): ${error.message}`);
}
// Manuel çökme testi (Manual crash test) - sadece test için
// crashlytics().crash();Analytics (Analitik)
import analytics from '@react-native-firebase/analytics';
// Ekran görüntüleme (Screen view)
await analytics().logScreenView({
screen_name: 'ProductDetail',
screen_class: 'ProductDetailScreen',
});
// Özel olay (Custom event)
await analytics().logEvent('add_to_cart', {
item_id: 'SKU123',
item_name: 'Laptop',
price: 2999.99,
currency: 'TRY',
});
// Satın alma olayı (Purchase event)
await analytics().logPurchase({
value: 2999.99,
currency: 'TRY',
items: [{ item_id: 'SKU123', item_name: 'Laptop', quantity: 1 }],
});
// Kullanıcı özelliği (User property)
await analytics().setUserProperty('preferred_language', 'tr');Remote Config (Uzaktan Yapılandırma)
import remoteConfig from '@react-native-firebase/remote-config';
// Varsayılan değerler ayarla (Set default values)
await remoteConfig().setDefaults({
welcome_message: 'Hoşgeldiniz!',
feature_new_ui: false,
min_app_version: '1.0.0',
maintenance_mode: false,
});
// Yapılandırma ayarları (Configuration settings)
await remoteConfig().setConfigSettings({
minimumFetchIntervalMillis: 300000, // 5 dakika (5 minutes)
});
// Sunucudan al ve etkinleştir (Fetch from server and activate)
await remoteConfig().fetchAndActivate();
// Değerleri oku (Read values)
const welcomeMsg = remoteConfig().getValue('welcome_message').asString();
const isNewUi = remoteConfig().getValue('feature_new_ui').asBoolean();
const minVersion = remoteConfig().getValue('min_app_version').asString();
console.log('Karşılama mesajı (Welcome message):', welcomeMsg);
// Feature flag kontrolü (Feature flag check)
if (isNewUi) {
// Yeni UI göster (Show new UI)
} else {
// Eski UI göster (Show old UI)
}Dynamic Links & App Distribution
Dynamic Links (Dinamik Bağlantılar)
Not (Note): Firebase Dynamic Links kullanımdan kaldırılmıştır (deprecated). Yeni projeler için alternatif olarak Branch.io veya Adjust kullanın.
import dynamicLinks from '@react-native-firebase/dynamic-links';
// Dinamik link oluştur (Create dynamic link)
const link = await dynamicLinks().buildShortLink({
link: 'https://myapp.com/product/123',
domainUriPrefix: 'https://myapp.page.link',
android: {
packageName: 'com.myapp.android',
},
ios: {
bundleId: 'com.myapp.ios',
appStoreId: '123456789',
},
});
// Gelen dinamik linki dinle (Listen for incoming dynamic link)
dynamicLinks().onLink((link) => {
console.log('Dinamik link alındı (Dynamic link received):', link.url);
handleDeepLink(link.url);
});App Distribution (Uygulama Dağıtımı)
Firebase App Distribution, beta test dağıtımı için kullanılır (used for beta test distribution).
# Firebase CLI ile dağıtım (Distribution via Firebase CLI)
# Android APK dağıt (Distribute Android APK)
firebase appdistribution:distribute app-release.apk \
--app YOUR_APP_ID \
--groups "beta-testers" \
--release-notes "Yeni özellikler eklendi (New features added)"
# iOS IPA dağıt (Distribute iOS IPA)
firebase appdistribution:distribute App.ipa \
--app YOUR_IOS_APP_ID \
--groups "ios-testers" \
--release-notes "Bug düzeltmeleri (Bug fixes)"Firebase Fiyatlandırma (Firebase Pricing)
| Özellik (Feature) | Spark (Ücretsiz / Free) | Blaze (Kullandıkça Öde / Pay as you go) |
|---|---|---|
| Fiyat (Price) | $0 | Kullanıma göre (Usage-based) |
| Authentication | Sınırsız (Unlimited) | Sınırsız (Unlimited) |
| Firestore Depolama | 1 GiB | $0.18/GiB |
| Firestore Okuma | 50K/gün | $0.06/100K |
| Firestore Yazma | 20K/gün | $0.18/100K |
| Firestore Silme | 20K/gün | $0.02/100K |
| Cloud Storage | 5 GB | $0.026/GB |
| Cloud Functions | Yok (None) | 2M çağrı/ay ücretsiz, sonra $0.40/M |
| Hosting | 10 GB depolama | $0.026/GB |
| Realtime DB | 1 GB depolama, 10 GB/ay | $5/GB depolama, $1/GB transfer |
| FCM | Sınırsız (Unlimited) | Sınırsız (Unlimited) |
| Crashlytics | Sınırsız (Unlimited) | Sınırsız (Unlimited) |
| Analytics | Sınırsız (Unlimited) | Sınırsız (Unlimited) |
| Remote Config | Sınırsız (Unlimited) | Sınırsız (Unlimited) |
| Test Lab | 15 sanal/gün, 5 fiziksel/gün | Kullanıma göre (Usage-based) |
İpucu (Tip): Çoğu küçük/orta ölçekli uygulama (small/medium apps) Spark planıyla başlayabilir. Cloud Functions kullanmak istiyorsanız Blaze planına geçmeniz gerekir, ancak ücretsiz kotalar hâlâ geçerlidir.
2. Bildirim Sistemleri (Notification Systems)
Bildirim Türleri (Notification Types)
| Tür (Type) | Açıklama (Description) | Kullanım Alanı (Use Case) |
|---|---|---|
| Remote (Uzak) | Sunucudan gönderilen bildirimler | Mesaj, kampanya, haber |
| Local (Yerel) | Cihaz üzerinde tetiklenen bildirimler | Hatırlatıcı, zamanlayıcı, alarm |
| Silent (Sessiz) | Kullanıcıya gösterilmeyen bildirimler | Arka plan veri senkronizasyonu |
| Rich (Zengin) | Medya içeren bildirimler | Resim, video, eylem düğmeleri |
Platform Bildirim Servisleri (Platform Notification Services)
| Servis (Service) | Platform | Açıklama (Description) |
|---|---|---|
| FCM (Firebase Cloud Messaging) | Android + iOS + Web | Google'ın çapraz platform bildirim servisi |
| APNs (Apple Push Notification service) | iOS | Apple'ın yerel bildirim servisi |
| OneSignal | Android + iOS + Web | Ücretsiz çapraz platform bildirim hizmeti |
| Expo Notifications | Expo (React Native) | Expo'nun yerleşik bildirim API'si |
FCM Kullanımı (FCM Usage)
FCM yapılandırması için yukarıdaki Firebase bölümüne bakın. Sunucu tarafından bildirim gönderme örneği (server-side notification example):
// Node.js sunucu tarafı (Server-side)
const admin = require('firebase-admin');
admin.initializeApp();
// Tek cihaza bildirim gönder (Send to single device)
async function sendToDevice(token, title, body, data = {}) {
const message = {
notification: { title, body },
data,
token,
android: {
priority: 'high',
notification: {
channelId: 'default',
sound: 'default',
},
},
apns: {
payload: {
aps: {
sound: 'default',
badge: 1,
},
},
},
};
const response = await admin.messaging().send(message);
console.log('Bildirim gönderildi (Notification sent):', response);
}
// Konuya bildirim gönder (Send to topic)
async function sendToTopic(topic, title, body) {
await admin.messaging().send({
notification: { title, body },
topic,
});
}
// Toplu bildirim gönder (Send batch notifications)
async function sendMulticast(tokens, title, body) {
const message = {
notification: { title, body },
tokens, // Maksimum 500 token
};
const response = await admin.messaging().sendEachForMulticast(message);
console.log(`${response.successCount} başarılı, ${response.failureCount} başarısız`);
}OneSignal Entegrasyonu (OneSignal Integration)
// React Native OneSignal kurulumu (Setup)
// npm install react-native-onesignal
import { OneSignal } from 'react-native-onesignal';
// Başlatma (Initialize)
OneSignal.initialize('YOUR_ONESIGNAL_APP_ID');
// Bildirim izni iste (Request permission)
OneSignal.Notifications.requestPermission(true);
// Bildirim dinleyici (Notification listener)
OneSignal.Notifications.addEventListener('foregroundWillDisplay', (event) => {
console.log('Bildirim alındı (Notification received):', event);
event.getNotification().display(); // Bildirimi göster
});
// Bildirime tıklama dinleyici (Click listener)
OneSignal.Notifications.addEventListener('click', (event) => {
console.log('Bildirime tıklandı (Notification clicked):', event);
const data = event.notification.additionalData;
navigateToScreen(data);
});
// Etiket ekleme (Add tags)
OneSignal.User.addTags({ user_type: 'premium', language: 'tr' });Expo Notifications
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
// İzin iste ve token al (Request permission and get token)
async function registerForPushNotifications() {
if (!Device.isDevice) {
alert('Fiziksel cihaz gerekli (Physical device required)');
return;
}
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Bildirim izni verilmedi (Permission not granted)');
return;
}
const token = (await Notifications.getExpoPushTokenAsync()).data;
console.log('Expo Push Token:', token);
return token;
}
// Yerel bildirim gönder (Send local notification)
async function sendLocalNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: 'Hatırlatma (Reminder)',
body: 'Görevinizi tamamlamayı unutmayın! (Don\'t forget your task!)',
data: { screen: 'TaskList' },
sound: 'default',
},
trigger: {
seconds: 60, // 60 saniye sonra (after 60 seconds)
},
});
}
// Bildirim alındığında (When notification received)
Notifications.addNotificationReceivedListener((notification) => {
console.log('Bildirim alındı:', notification);
});
// Bildirime tıklandığında (When notification tapped)
Notifications.addNotificationResponseReceivedListener((response) => {
const data = response.notification.request.content.data;
navigateToScreen(data.screen);
});Bildirim İzin Yönetimi (Notification Permission Management)
import { Platform, Alert, Linking } from 'react-native';
import messaging from '@react-native-firebase/messaging';
async function checkAndRequestPermission() {
if (Platform.OS === 'ios') {
const authStatus = await messaging().requestPermission();
if (authStatus === messaging.AuthorizationStatus.DENIED) {
Alert.alert(
'Bildirimler Kapalı (Notifications Disabled)',
'Bildirimleri açmak için Ayarlar\'a gidin (Go to Settings to enable notifications)',
[
{ text: 'İptal (Cancel)', style: 'cancel' },
{ text: 'Ayarlar (Settings)', onPress: () => Linking.openSettings() },
]
);
return false;
}
return true;
}
// Android 13+ için izin gerekli (Permission required for Android 13+)
if (Platform.OS === 'android' && Platform.Version >= 33) {
const { PermissionsAndroid } = require('react-native');
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
}
return true; // Android 12 ve altı, izin gerekmiyor
}3. BaaS Karşılaştırma (BaaS Comparison)
Backend-as-a-Service (BaaS) platformları, sunucu tarafı altyapı kurmadan backend özellikleri sunar.
| Özellik (Feature) | Firebase | Supabase | Appwrite | AWS Amplify | PocketBase |
|---|---|---|---|---|---|
| Geliştirici | Topluluk (Open-source) | Topluluk (Open-source) | Amazon | Topluluk (Open-source) | |
| Veritabanı (Database) | Firestore (NoSQL) | PostgreSQL (SQL) | MariaDB | DynamoDB | SQLite |
| Auth Yöntemleri | Email, Google, Apple, Phone, Anonymous | Email, OAuth, Magic Link, Phone | Email, OAuth, Phone, Magic URL | Cognito (Email, Social, Phone) | Email, OAuth |
| Dosya Depolama (Storage) | Cloud Storage | S3-uyumlu (S3-compatible) | Yerleşik (Built-in) | S3 | Yerleşik (Built-in) |
| Push Bildirim | FCM (dahili) | Harici servis gerekli | Push desteği var | Pinpoint | Harici servis gerekli |
| Gerçek Zamanlı (Real-time) | Firestore Listeners | PostgreSQL Realtime | WebSocket | AppSync (GraphQL) | SSE (Server-Sent Events) |
| Fonksiyonlar (Functions) | Cloud Functions | Edge Functions (Deno) | Cloud Functions | Lambda | Yok (Go ile genişletilir) |
| Self-Host | Hayır (No) | Evet (Yes) | Evet (Yes) | Kısmi (Partial) | Evet (Yes) |
| Ücretsiz Katman (Free Tier) | Spark (cömert) | 500 MB DB, 1 GB Storage | Self-host: sınırsız | 12 ay ücretsiz | Self-host: sınırsız |
| SDK Desteği | iOS, Android, Web, Flutter, Unity | JS, Flutter, Swift, Kotlin | JS, Flutter, Swift, Android | JS, iOS, Android, Flutter | JS, Dart (topluluk) |
| Admin Panel | Firebase Console | Supabase Dashboard | Appwrite Console | AWS Console | Yerleşik Admin UI |
| Fiyatlandırma (Pricing) | Kullanıma göre (Pay-as-you-go) | $0 → $25/ay → Kullanıma göre | Self-host: ücretsiz, Cloud: $15/ay | Kullanıma göre | Ücretsiz (Self-host) |
| En İyi Kullanım | Hızlı prototip, küçük-orta proje | SQL seven ekipler, open-source | Self-host isteyen ekipler | AWS ekosistemi kullanıcıları | Tek dosya, basit projeler |
BaaS Seçim Rehberi (BaaS Selection Guide)
- Firebase: Hızlı başlangıç, Google ekosistemi, küçük-orta projeler
- Supabase: PostgreSQL tercih edenler, açık kaynak, SQL sorguları gerekli projeler
- Appwrite: Kendi sunucunuzda barındırmak isteyenler, veri gizliliği öncelikli projeler
- AWS Amplify: Zaten AWS kullanan ekipler, kurumsal projeler
- PocketBase: Tek dosya backend, hızlı prototip, Go bilgisi olanlar
4. Mobil UI Kütüphaneleri (Mobile UI Libraries)
React Native UI Kütüphaneleri (React Native UI Libraries)
| Kütüphane (Library) | Açıklama (Description) | Tema (Theming) | Boyut (Size) | Popülerlik |
|---|---|---|---|---|
| React Native Paper | Material Design 3 bileşenleri | Evet, kapsamlı | Orta | ⭐ En popüler |
| NativeBase | Platformlar arası UI bileşenleri | Evet | Büyük | Yüksek |
| Tamagui | Optimize, evrensel UI (web + native) | Evet, güçlü | Hafif (compile-time) | Yükselen |
| Gluestack UI | NativeBase'in yeni nesil hali | Evet | Hafif | Yeni |
| React Native Elements | Basit, özelleştirilebilir bileşenler | Kısmi | Orta | Yüksek |
| Shoutem UI | Hazır bileşen seti | Evet | Büyük | Orta |
// React Native Paper kullanım örneği (Usage example)
import { Provider as PaperProvider, Button, Card, Text } from 'react-native-paper';
function App() {
return (
<PaperProvider>
<Card>
<Card.Title title="Ürün Adı (Product Name)" />
<Card.Content>
<Text variant="bodyMedium">Ürün açıklaması (Product description)</Text>
</Card.Content>
<Card.Actions>
<Button mode="contained" onPress={() => console.log('Sepete eklendi')}>
Sepete Ekle (Add to Cart)
</Button>
</Card.Actions>
</Card>
</PaperProvider>
);
}
// Tamagui kullanım örneği (Usage example)
import { Button, H1, Paragraph, YStack } from 'tamagui';
function Screen() {
return (
<YStack padding="$4" gap="$3">
<H1>Başlık (Title)</H1>
<Paragraph>İçerik metni (Content text)</Paragraph>
<Button theme="blue" size="$4">
Devam Et (Continue)
</Button>
</YStack>
);
}Flutter UI Kütüphaneleri (Flutter UI Libraries)
| Kütüphane (Library) | Açıklama (Description) | Platform Görünümü |
|---|---|---|
| Material 3 | Google'ın Material Design 3 | Android (varsayılan) |
| Cupertino | Apple iOS tarzı bileşenler | iOS (yerel görünüm) |
| FlutterFlow | Sürükle-bırak UI oluşturucu | Her iki platform |
| GetWidget | 1000+ hazır bileşen | Her iki platform |
| Flutter Neumorphic | Neumorphic tasarım bileşenleri | Her iki platform |
// Material 3 ve Cupertino birlikte kullanımı (Combined usage)
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:io' show Platform;
Widget buildButton(String text, VoidCallback onPressed) {
if (Platform.isIOS) {
return CupertinoButton.filled(
onPressed: onPressed,
child: Text(text),
);
}
return FilledButton(
onPressed: onPressed,
child: Text(text),
);
}
// Material 3 tema yapılandırması (Theme configuration)
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.blue,
brightness: Brightness.light,
),
darkTheme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.blue,
brightness: Brightness.dark,
),
);İkon Kütüphaneleri (Icon Libraries)
| Kütüphane (Library) | Platform | İkon Sayısı | Kullanım |
|---|---|---|---|
| @expo/vector-icons | React Native (Expo) | 3000+ | <Ionicons name="heart" size={24} /> |
| react-native-vector-icons | React Native (Bare) | 3000+ | <Icon name="heart" size={24} /> |
| flutter_icons | Flutter | Çoklu set | Icon(Icons.favorite) |
| Phosphor Icons | RN + Flutter | 7000+ | Tutarlı, modern tasarım |
| Lucide | React Native | 1500+ | Hafif, SVG tabanlı |
Animasyon Kütüphaneleri (Animation Libraries)
| Kütüphane (Library) | Platform | Açıklama (Description) | Performans |
|---|---|---|---|
| Lottie | RN + Flutter | After Effects JSON animasyonları | İyi, önceden hazırlanmış |
| Rive | RN + Flutter | İnteraktif, durum bazlı animasyonlar | Çok iyi, küçük dosya boyutu |
| Reanimated | React Native | Gelişmiş, UI thread animasyonları | Mükemmel, 60/120 FPS |
| Moti | React Native | Reanimated üzerine deklaratif API | Çok iyi |
| Flutter Animate | Flutter | Kolay zincirleme animasyonlar | İyi |
| Rive (Flutter) | Flutter | İnteraktif animasyon motoru | Çok iyi |
// Lottie kullanımı (Lottie usage) - React Native
import LottieView from 'lottie-react-native';
<LottieView
source={require('./animations/loading.json')}
autoPlay
loop
style={{ width: 200, height: 200 }}
/>
// Reanimated kullanımı (Reanimated usage)
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
} from 'react-native-reanimated';
function AnimatedBox() {
const offset = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: withSpring(offset.value) }],
}));
return (
<Animated.View style={[styles.box, animatedStyle]}>
<Button title="Hareket Et (Move)" onPress={() => { offset.value = offset.value === 0 ? 200 : 0; }} />
</Animated.View>
);
}// Lottie kullanımı (Lottie usage) - Flutter
import 'package:lottie/lottie.dart';
Lottie.asset(
'assets/animations/loading.json',
width: 200,
height: 200,
repeat: true,
);
// Rive kullanımı (Rive usage) - Flutter
import 'package:rive/rive.dart';
const RiveAnimation.asset(
'assets/animations/button.riv',
fit: BoxFit.contain,
);5. Mobil Veritabanları (Mobile Databases)
Cihaz üzerinde (on-device) veri depolama çözümleri.
Karşılaştırma Tablosu (Comparison Table)
| Çözüm (Solution) | Platform | Tür (Type) | Sorgulama (Querying) | Şifreleme (Encryption) | Performans | Boyut |
|---|---|---|---|---|---|---|
| AsyncStorage | React Native | Anahtar-değer (Key-value) | Yok (None) | Yok | Düşük-Orta | Küçük |
| SecureStore | Expo (RN) | Anahtar-değer, şifreli | Yok | Evet (Keychain/Keystore) | Orta | Küçük |
| MMKV | React Native | Anahtar-değer | Yok | Evet (opsiyonel) | Çok hızlı | Küçük |
| SQLite | RN + Flutter | İlişkisel SQL (Relational) | SQL sorguları | Opsiyonel (SQLCipher) | Yüksek | Orta |
| Realm | RN + Flutter | Nesne tabanlı (Object-based) | Realm Query Language | Evet | Çok yüksek | Orta |
| Hive | Flutter | NoSQL, anahtar-değer | Sınırlı | Evet (AES) | Çok hızlı | Küçük |
| WatermelonDB | React Native | İlişkisel, lazy | SQL (SQLite tabanlı) | Opsiyonel | Çok yüksek (lazy loading) | Orta |
| Isar | Flutter | NoSQL, tam metin arama | CRUD + Full-text | Opsiyonel | Çok yüksek | Orta |
| Drift | Flutter | Tip-güvenli SQL (Type-safe SQL) | SQL (kod oluşturma) | Opsiyonel | Yüksek | Orta |
Ne Zaman Hangisi? (When to Use Which?)
| İhtiyaç (Need) | Önerilen (Recommended) |
|---|---|
| Basit ayarlar, token saklama (Simple settings) | MMKV veya SecureStore |
| Hassas veri (şifre, token) (Sensitive data) | SecureStore (Expo) veya Keychain/Keystore |
| Küçük JSON verileri (Small JSON data) | MMKV veya AsyncStorage |
| İlişkisel veri, karmaşık sorgular (Relational data) | SQLite veya WatermelonDB |
| Nesne tabanlı, senkronizasyon (Object-based, sync) | Realm |
| Flutter'da hızlı yerel depolama | Hive veya Isar |
| Büyük veri, performans kritik (Large data, perf-critical) | WatermelonDB (RN) veya Isar (Flutter) |
Kullanım Örnekleri (Usage Examples)
// ---------- MMKV (React Native) ----------
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV();
// Veri kaydet (Save data)
storage.set('user.name', 'Fahri');
storage.set('user.age', 28);
storage.set('user.isPremium', true);
storage.set('user.settings', JSON.stringify({ theme: 'dark', lang: 'tr' }));
// Veri oku (Read data)
const name = storage.getString('user.name'); // 'Fahri'
const age = storage.getNumber('user.age'); // 28
const isPremium = storage.getBoolean('user.isPremium'); // true
const settings = JSON.parse(storage.getString('user.settings') ?? '{}');
// Veri sil (Delete data)
storage.delete('user.name');
// Tüm anahtarlar (All keys)
const allKeys = storage.getAllKeys(); // ['user.age', 'user.isPremium', ...]
// Şifreli depolama (Encrypted storage)
const secureStorage = new MMKV({
id: 'secure-storage',
encryptionKey: 'my-encryption-key',
});// ---------- WatermelonDB (React Native) ----------
import { Database, Model, Q } from '@nozbe/watermelondb';
import { field, date, children } from '@nozbe/watermelondb/decorators';
// Model tanımla (Define model)
class Post extends Model {
static table = 'posts';
static associations = {
comments: { type: 'has_many', foreignKey: 'post_id' },
};
@field('title') title;
@field('body') body;
@field('is_published') isPublished;
@date('created_at') createdAt;
@children('comments') comments;
}
// Sorgu örnekleri (Query examples)
const publishedPosts = await database
.get('posts')
.query(Q.where('is_published', true))
.fetch();
const recentPosts = await database
.get('posts')
.query(
Q.where('is_published', true),
Q.sortBy('created_at', Q.desc),
Q.take(10)
)
.fetch();// ---------- Hive (Flutter) ----------
import 'package:hive_flutter/hive_flutter.dart';
// Başlatma (Initialize)
await Hive.initFlutter();
var box = await Hive.openBox('settings');
// Veri kaydet (Save data)
await box.put('theme', 'dark');
await box.put('language', 'tr');
await box.put('user', {'name': 'Fahri', 'age': 28});
// Veri oku (Read data)
String theme = box.get('theme', defaultValue: 'light');
Map user = box.get('user');
// Veri sil (Delete data)
await box.delete('theme');
// Şifreli kutu (Encrypted box)
final encryptionKey = Hive.generateSecureKey();
var secureBox = await Hive.openBox('secure',
encryptionCipher: HiveAesCipher(encryptionKey),
);// ---------- Isar (Flutter) ----------
import 'package:isar/isar.dart';
part 'user.g.dart'; // Kod oluşturma (Code generation)
@collection
class User {
Id id = Isar.autoIncrement;
@Index()
late String name;
late int age;
@Index(type: IndexType.value)
late String email;
}
// Kullanım (Usage)
final isar = await Isar.open([UserSchema]);
// Yazma (Write)
await isar.writeTxn(() async {
final user = User()
..name = 'Fahri'
..age = 28
..email = 'fahri@example.com';
await isar.users.put(user);
});
// Sorgulama (Query)
final users = await isar.users
.filter()
.ageGreaterThan(18)
.and()
.nameContains('Fah')
.sortByName()
.findAll();
// Tam metin arama (Full-text search)
final results = await isar.users
.filter()
.nameContains('fahri', caseSensitive: false)
.findAll();6. CI/CD & Build Araçları (CI/CD & Build Tools)
CI/CD Platformları Karşılaştırma (CI/CD Platforms Comparison)
| Araç (Tool) | Platform Desteği | Ücretsiz Katman | Özellik (Feature) |
|---|---|---|---|
| Fastlane | iOS + Android | Açık kaynak (Open-source) | Yerel otomasyon, kod imzalama, mağaza yükleme |
| EAS Build | Expo (React Native) | 30 build/ay | Bulut build, OTA güncelleme, mağaza submit |
| Codemagic | Flutter + RN + Native | 500 build dakikası/ay | Flutter'a özel, kod imzalama |
| GitHub Actions | Tüm platformlar | 2000 dakika/ay | Esnek, geniş marketplace |
| App Center | iOS + Android + RN | Sınırsız build (bazı limitler) | Microsoft, test + dağıtım + analitik |
| Bitrise | iOS + Android + Flutter + RN | 300 kredi/ay | Mobil odaklı, hazır adımlar |
Fastlane
Fastlane, mobil uygulama build, test ve dağıtım süreçlerini otomatikleştiren açık kaynak bir araçtır.
# fastlane/Fastfile
default_platform(:ios)
platform :ios do
desc "Beta dağıtımı (Beta distribution)"
lane :beta do
increment_build_number
build_app(
scheme: "MyApp",
export_method: "ad-hoc"
)
upload_to_testflight
slack(message: "iOS beta yüklendi! (iOS beta uploaded!)")
end
desc "App Store'a yükleme (Upload to App Store)"
lane :release do
increment_build_number
build_app(
scheme: "MyApp",
export_method: "app-store"
)
upload_to_app_store(
submit_for_review: true,
automatic_release: false
)
end
end
platform :android do
desc "Play Store internal test"
lane :beta do
gradle(
task: "bundle",
build_type: "Release"
)
upload_to_play_store(
track: "internal",
aab: "app/build/outputs/bundle/release/app-release.aab"
)
end
desc "Play Store production"
lane :release do
gradle(task: "bundle", build_type: "Release")
upload_to_play_store(track: "production")
end
endEAS Build (Expo Application Services)
# EAS CLI kurulumu (Install EAS CLI)
npm install -g eas-cli
# Giriş ve yapılandırma (Login and configure)
eas login
eas build:configure// eas.json
{
"cli": { "version": ">= 5.0.0" },
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": { "simulator": true }
},
"preview": {
"distribution": "internal",
"android": { "buildType": "apk" }
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {
"ios": {
"appleId": "your@email.com",
"ascAppId": "1234567890",
"appleTeamId": "TEAM_ID"
},
"android": {
"serviceAccountKeyPath": "./google-service-account.json",
"track": "internal"
}
}
}
}# Build komutları (Build commands)
eas build --platform ios --profile production # iOS production build
eas build --platform android --profile preview # Android preview build
eas build --platform all --profile production # Her iki platform
# Mağazaya gönder (Submit to store)
eas submit --platform ios --profile production
eas submit --platform android --profile production
# OTA güncelleme (Over-the-Air update)
eas update --branch production --message "Bug düzeltmesi (Bug fix)"GitHub Actions - Mobil CI/CD
# .github/workflows/mobile-ci.yml
name: Mobile CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# React Native Test
test-rn:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test -- --coverage
# Android Build
build-android:
needs: test-rn
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Android Build
working-directory: android
run: ./gradlew assembleRelease
- uses: actions/upload-artifact@v4
with:
name: android-release
path: android/app/build/outputs/apk/release/
# iOS Build
build-ios:
needs: test-rn
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: cd ios && pod install
- name: iOS Build
run: |
xcodebuild -workspace ios/MyApp.xcworkspace \
-scheme MyApp \
-configuration Release \
-sdk iphoneos \
-archivePath build/MyApp.xcarchive \
archiveCodemagic (Flutter CI/CD)
# codemagic.yaml
workflows:
flutter-production:
name: Flutter Production
max_build_duration: 60
environment:
flutter: stable
xcode: latest
cocoapods: default
groups:
- app_store_credentials
- google_play
triggering:
events:
- push
branch_patterns:
- pattern: main
include: true
scripts:
- name: Bağımlılıkları yükle (Install dependencies)
script: flutter pub get
- name: Testleri çalıştır (Run tests)
script: flutter test
- name: Android build
script: flutter build appbundle --release
- name: iOS build
script: flutter build ipa --release --export-options-plist=/path/to/ExportOptions.plist
artifacts:
- build/**/outputs/**/*.aab
- build/ios/ipa/*.ipa
publishing:
google_play:
credentials: $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
track: internal
app_store_connect:
auth: integration7. Test & Debug Araçları (Test & Debug Tools)
Test & Debug Araçları Karşılaştırma (Comparison)
| Araç (Tool) | Platform | Tür (Type) | Açıklama (Description) |
|---|---|---|---|
| Flipper | React Native | Debug | Ağ, veritabanı, layout inceleme |
| React Native Debugger | React Native | Debug | Redux DevTools + Chrome DevTools |
| Reactotron | React Native | Debug | API izleme, state görüntüleme, benchmark |
| Flutter DevTools | Flutter | Debug + Profil | Widget ağacı, performans, bellek |
| Detox | React Native | E2E Test | Gri kutu E2E test framework |
| Patrol | Flutter | E2E Test | Yerel UI etkileşimi destekli E2E |
| Maestro | RN + Flutter + Native | E2E Test | Basit YAML tabanlı UI testleri |
| Firebase Test Lab | Android + iOS | Bulut Test | Gerçek cihazlarda otomatik test |
Detox (React Native E2E Test)
// e2e/login.test.js
describe('Giriş Ekranı (Login Screen)', () => {
beforeAll(async () => {
await device.launchApp();
});
beforeEach(async () => {
await device.reloadReactNative();
});
it('başarılı giriş yapabilmeli (should login successfully)', async () => {
// Email gir (Enter email)
await element(by.id('email-input')).typeText('test@example.com');
// Şifre gir (Enter password)
await element(by.id('password-input')).typeText('password123');
// Giriş butonuna tıkla (Tap login button)
await element(by.id('login-button')).tap();
// Ana ekranın görünmesini bekle (Wait for home screen)
await waitFor(element(by.id('home-screen')))
.toBeVisible()
.withTimeout(5000);
// Karşılama mesajını kontrol et (Check welcome message)
await expect(element(by.text('Hoşgeldiniz'))).toBeVisible();
});
it('hatalı girişte uyarı göstermeli (should show error on invalid login)', async () => {
await element(by.id('email-input')).typeText('wrong@example.com');
await element(by.id('password-input')).typeText('wrongpass');
await element(by.id('login-button')).tap();
await waitFor(element(by.text('Geçersiz kimlik bilgileri')))
.toBeVisible()
.withTimeout(3000);
});
});Flutter Test
// test/widget_test.dart (Birim ve Widget testleri / Unit and Widget tests)
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/screens/login_screen.dart';
void main() {
group('LoginScreen', () {
testWidgets('başarılı giriş (successful login)', (tester) async {
await tester.pumpWidget(const MaterialApp(home: LoginScreen()));
// Email gir (Enter email)
await tester.enterText(find.byKey(const Key('email-input')), 'test@example.com');
// Şifre gir (Enter password)
await tester.enterText(find.byKey(const Key('password-input')), 'password123');
// Giriş butonuna tıkla (Tap login button)
await tester.tap(find.byKey(const Key('login-button')));
await tester.pumpAndSettle();
// Sonucu doğrula (Verify result)
expect(find.text('Hoşgeldiniz'), findsOneWidget);
});
});
}// integration_test/app_test.dart (Entegrasyon testi / Integration test)
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('tam uygulama akışı (full app flow)', (tester) async {
app.main();
await tester.pumpAndSettle();
// Giriş yap (Login)
await tester.enterText(find.byKey(const Key('email')), 'test@example.com');
await tester.enterText(find.byKey(const Key('password')), 'pass123');
await tester.tap(find.byKey(const Key('login-btn')));
await tester.pumpAndSettle();
// Ana sayfa kontrolü (Home page check)
expect(find.text('Ana Sayfa'), findsOneWidget);
});
}Patrol (Flutter E2E with Native)
// integration_test/notifications_test.dart
import 'package:patrol/patrol.dart';
void main() {
patrolTest('bildirim izni testi (notification permission test)', ($) async {
await $.pumpWidgetAndSettle(const MyApp());
// Bildirim izni butonuna tıkla (Tap notification permission button)
await $('Bildirimlere İzin Ver').tap();
// Yerel izin dialogunu kabul et (Accept native permission dialog)
await $.native.tap(NativeSelector(text: 'Allow'));
// Sonucu doğrula (Verify result)
expect($('Bildirimler Açık'), findsOneWidget);
});
}Firebase Test Lab
# Android testlerini Firebase Test Lab'da çalıştır (Run Android tests on Firebase Test Lab)
gcloud firebase test android run \
--type instrumentation \
--app app-debug.apk \
--test app-debug-androidTest.apk \
--device model=Pixel6,version=33,locale=tr,orientation=portrait \
--device model=Pixel4,version=30,locale=tr \
--timeout 300s \
--results-dir test-results
# Robo test (otomatik UI keşfi / automatic UI exploration)
gcloud firebase test android run \
--type robo \
--app app-release.apk \
--device model=Pixel6,version=33 \
--timeout 120s
# iOS testleri (iOS tests)
gcloud firebase test ios run \
--test ios_test.zip \
--device model=iphone14pro,version=16.6Reactotron Yapılandırma (Reactotron Configuration)
// ReactotronConfig.js
import Reactotron from 'reactotron-react-native';
import { reactotronRedux } from 'reactotron-redux';
import reactotronZustand from 'reactotron-plugin-zustand';
const reactotron = Reactotron
.configure({ name: 'MyApp' })
.useReactNative({
networking: { ignoreUrls: /symbolicate/ },
errors: { veto: () => false },
editor: true,
overlay: true,
})
.use(reactotronRedux())
.connect();
// API çağrılarını logla (Log API calls)
reactotron.onCustomCommand({
command: 'clearAsyncStorage',
handler: () => {
AsyncStorage.clear();
reactotron.display({ name: 'AsyncStorage', value: 'Temizlendi (Cleared)' });
},
});
export default reactotron;8. Paket & Versiyon Yönetimi (Package & Version Management)
SemVer (Semantic Versioning / Anlamsal Sürümleme)
SemVer formatı: MAJOR.MINOR.PATCH (örn. 2.4.1)
| Bileşen (Component) | Açıklama (Description) | Ne Zaman Artırılır? (When to Increment?) |
|---|---|---|
| MAJOR | Ana sürüm (Major version) | Geriye uyumsuz değişiklikler (Breaking changes) |
| MINOR | Küçük sürüm (Minor version) | Geriye uyumlu yeni özellikler (Backward-compatible features) |
| PATCH | Yama sürümü (Patch version) | Geriye uyumlu hata düzeltmeleri (Bug fixes) |
Sürüm Aralığı Sembolleri (Version Range Symbols)
| Sembol (Symbol) | Anlamı (Meaning) | Örnek (Example) | Eşleşen Aralık (Matched Range) |
|---|---|---|---|
^ (Caret) | MINOR ve PATCH güncellenebilir | ^2.4.1 | >=2.4.1 <3.0.0 |
~ (Tilde) | Sadece PATCH güncellenebilir | ~2.4.1 | >=2.4.1 <2.5.0 |
| Tam (Exact) | Sadece belirtilen sürüm | 2.4.1 | Yalnızca 2.4.1 |
>= | Belirtilen ve üstü | >=2.4.1 | 2.4.1 ve sonrası |
* | Herhangi bir sürüm | * | Tüm sürümler (önerilmez) |
Öneri (Recommendation): Çoğu paket için
^(caret) kullanın. Kritik paketlerde (native modüller gibi) tam sürüm (exact) tercih edin.
React Native Paket Yönetimi (React Native Package Management)
package.json Yapısı (Structure)
{
"name": "my-app",
"version": "1.2.0",
"dependencies": {
"react": "18.2.0",
"react-native": "0.73.4",
"@react-native-firebase/app": "^19.0.0",
"react-native-reanimated": "~3.6.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"typescript": "^5.3.0",
"jest": "^29.7.0",
"eslint": "^8.56.0"
}
}Temel Komutlar (Essential Commands)
# Bağımlılıkları yükle (Install dependencies)
npm install # veya: yarn install
# Paket ekle (Add package)
npm install lodash # dependencies'e ekler
npm install -D jest # devDependencies'e ekler
# Güncel olmayan paketleri kontrol et (Check outdated packages)
npm outdated
# Örnek çıktı (Example output):
# Package Current Wanted Latest
# react-native 0.73.2 0.73.4 0.74.0
# @react-navigation/... 6.1.9 6.1.11 7.0.0
# Güvenlik denetimi (Security audit)
npm audit
npm audit fix # Otomatik düzelt (Auto-fix)
npm audit fix --force # Zorla düzelt (dikkatli olun / be careful)
# npm-check-updates (ncu) - tüm paketleri güncellemek için
npx npm-check-updates # Güncelleme listesini göster (Show update list)
npx npm-check-updates -u # package.json'ı güncelle (Update package.json)
npx npm-check-updates -i # İnteraktif seçim (Interactive selection)
# Expo projeleri için (For Expo projects)
npx expo-doctor # Uyumluluk kontrolü (Compatibility check)
npx expo install --check # SDK uyumlu sürümleri kontrol et
# Paket bilgisi (Package info)
npm info react-native versions # Mevcut sürümler (Available versions)
npm ls react-native # Bağımlılık ağacı (Dependency tree)Flutter Paket Yönetimi (Flutter Package Management)
pubspec.yaml Yapısı (Structure)
name: my_app
description: Uygulama açıklaması (App description)
version: 1.2.0+3 # version+buildNumber
environment:
sdk: '>=3.2.0 <4.0.0'
flutter: '>=3.16.0'
dependencies:
flutter:
sdk: flutter
firebase_core: ^2.24.0
cloud_firestore: ^4.14.0
provider: ^6.1.0
http: ^1.2.0
shared_preferences: ^2.2.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
build_runner: ^2.4.0
mockito: ^5.4.0Temel Komutlar (Essential Commands)
# Bağımlılıkları yükle (Install dependencies)
flutter pub get
# Paket ekle (Add package)
flutter pub add provider
flutter pub add --dev mockito
# Güncel olmayan paketleri kontrol et (Check outdated)
flutter pub outdated
# Paketleri güncelle (Upgrade packages)
flutter pub upgrade # pubspec.yaml aralığında güncelle
flutter pub upgrade --major-versions # Major sürümlere de güncelle
# Paket arama (Search packages)
# pub.dev adresinden arayın (Search on pub.dev)
# Bağımlılık çözünürlüğü (Dependency resolution)
flutter pub deps # Bağımlılık ağacı (Dependency tree)
# Kod oluşturma (Code generation)
dart run build_runner build --delete-conflicting-outputsnpm vs yarn vs Flutter Hızlı Referans (Quick Reference)
| İşlem (Operation) | npm | yarn | Flutter |
|---|---|---|---|
| Yükle (Install) | npm install | yarn | flutter pub get |
| Paket ekle (Add) | npm install pkg | yarn add pkg | flutter pub add pkg |
| Dev paket ekle | npm install -D pkg | yarn add -D pkg | flutter pub add --dev pkg |
| Paket sil (Remove) | npm uninstall pkg | yarn remove pkg | Pubspec'ten sil + pub get |
| Güncelle (Update) | npm update | yarn upgrade | flutter pub upgrade |
| Güncel olmayan (Outdated) | npm outdated | yarn outdated | flutter pub outdated |
| Çalıştır (Run script) | npm run dev | yarn dev | flutter run |
| Güvenlik (Audit) | npm audit | yarn audit | N/A |
| Temizle (Clean) | rm -rf node_modules | yarn cache clean | flutter clean |
| Lock dosyası | package-lock.json | yarn.lock | pubspec.lock |
| Registry | npmjs.com | npmjs.com | pub.dev |
Best Practices (En İyi Uygulamalar)
Lock dosyasını commit edin (Commit lock file):
package-lock.jsonveyayarn.lockdosyasını her zaman Git'e commit edinpubspec.lockdosyasını uygulama projelerinde commit edin (kütüphanelerde değil)
Paketleri tek tek güncelleyin (Update packages one by one):
bash# Kötü yaklaşım (Bad approach) npx ncu -u && npm install # Hepsini birden güncelleme # İyi yaklaşım (Good approach) npm install react-native@0.73.4 # Tek tek, test ederek güncelle npm test # Her güncellemeden sonra test etDependabot / Renovate kullanın:
yaml# .github/dependabot.yml version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" open-pull-requests-limit: 10 labels: - "dependencies" ignore: - dependency-name: "react-native" update-types: ["version-update:semver-major"]Güvenlik kontrolü otomatikleştirin (Automate security checks):
yaml# CI/CD pipeline'a ekleyin (Add to CI/CD pipeline) - name: Güvenlik denetimi (Security audit) run: npm audit --production --audit-level=highKullanılmayan bağımlılıkları temizleyin (Clean unused dependencies):
bash# React Native npx depcheck # Kullanılmayan paketleri bul (Find unused packages) # Flutter dart pub deps --no-dev # Bağımlılık ağacını incele
9. Diğer Araçlar (Other Tools)
OTA Güncelleme (Over-the-Air Updates)
| Araç (Tool) | Platform | Açıklama (Description) |
|---|---|---|
| Expo Updates / EAS Update | Expo (RN) | JavaScript bundle güncelleme, anında yayınlama |
| CodePush (App Center) | React Native | Microsoft'un OTA çözümü (kullanımdan kalkıyor) |
| Shorebird | Flutter | Flutter için code push çözümü |
// Expo Updates kullanımı (Expo Updates usage)
import * as Updates from 'expo-updates';
async function checkForUpdates() {
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
// Kullanıcıya sor veya otomatik yeniden başlat
Alert.alert(
'Güncelleme Mevcut (Update Available)',
'Yeni bir güncelleme indirildi. Uygulamayı yeniden başlatmak ister misiniz?',
[
{ text: 'Sonra (Later)', style: 'cancel' },
{ text: 'Yeniden Başlat (Restart)', onPress: () => Updates.reloadAsync() },
]
);
}
} catch (error) {
console.log('Güncelleme kontrolü hatası (Update check error):', error);
}
}Hata İzleme & Performans (Error Tracking & Performance)
// Sentry kurulumu (Sentry setup) - React Native
// npm install @sentry/react-native
import * as Sentry from '@sentry/react-native';
Sentry.init({
dsn: 'https://your-dsn@sentry.io/project-id',
tracesSampleRate: 1.0,
environment: __DEV__ ? 'development' : 'production',
});
// Hata yakalama (Error capture)
try {
await riskyOperation();
} catch (error) {
Sentry.captureException(error);
Sentry.addBreadcrumb({
category: 'user-action',
message: 'Kullanıcı ödeme yaptı (User made payment)',
level: 'info',
});
}
// Performans izleme (Performance monitoring)
const transaction = Sentry.startTransaction({ name: 'loadProducts' });
const span = transaction.startChild({ op: 'db.query' });
await fetchProducts();
span.finish();
transaction.finish();Ödeme Sistemleri (Payment Systems)
| Araç (Tool) | Platform | Açıklama (Description) | Komisyon |
|---|---|---|---|
| RevenueCat | RN + Flutter + Native | Abonelik yönetimi (Subscription management) | $0-$2500/ay gelir: ücretsiz |
| Stripe | RN + Flutter + Web | Kapsamlı ödeme altyapısı | %2.9 + $0.30 |
| In-App Purchases | iOS + Android | Mağaza içi satın alma | Apple: %30, Google: %15-30 |
// RevenueCat kullanımı (RevenueCat usage)
import Purchases from 'react-native-purchases';
// Başlatma (Initialize)
Purchases.configure({ apiKey: 'YOUR_REVENUECAT_API_KEY' });
// Mevcut teklifleri al (Get offerings)
async function getSubscriptionPlans() {
const offerings = await Purchases.getOfferings();
if (offerings.current) {
const packages = offerings.current.availablePackages;
return packages.map(pkg => ({
identifier: pkg.identifier,
price: pkg.product.priceString,
title: pkg.product.title,
}));
}
}
// Satın alma (Purchase)
async function purchasePackage(pkg) {
try {
const { customerInfo } = await Purchases.purchasePackage(pkg);
if (customerInfo.entitlements.active['premium']) {
console.log('Premium aktif (Premium active)');
}
} catch (error) {
if (!error.userCancelled) {
console.error('Satın alma hatası (Purchase error):', error);
}
}
}
// Abonelik durumunu kontrol et (Check subscription status)
async function checkSubscription() {
const customerInfo = await Purchases.getCustomerInfo();
return customerInfo.entitlements.active['premium'] !== undefined;
}Diğer Araçlar Referans Tablosu (Other Tools Reference Table)
| Araç (Tool) | Kategori (Category) | Platform | Resmi Link |
|---|---|---|---|
| Expo Updates | OTA Güncelleme | Expo (RN) | docs.expo.dev/versions/latest/sdk/updates |
| Sentry | Hata İzleme | RN + Flutter | sentry.io |
| RevenueCat | Ödeme/Abonelik | RN + Flutter | revenuecat.com |
| Stripe | Ödeme İşleme | RN + Flutter | stripe.com |
| i18next | Çoklu Dil (i18n) | React Native | i18next.com |
| easy_localization | Çoklu Dil (i18n) | Flutter | pub.dev/packages/easy_localization |
| react-native-maps | Harita (Maps) | React Native | github.com/react-native-maps |
| google_maps_flutter | Harita (Maps) | Flutter | pub.dev/packages/google_maps_flutter |
| react-native-camera | Kamera (Camera) | React Native | github.com/mrousavy/react-native-vision-camera |
| camera | Kamera (Camera) | Flutter | pub.dev/packages/camera |
| react-native-image-picker | Galeri/Kamera | React Native | github.com/react-native-image-picker |
| image_picker | Galeri/Kamera | Flutter | pub.dev/packages/image_picker |
| Mapbox | Harita (Maps) | RN + Flutter | mapbox.com |
| Firebase | BaaS | RN + Flutter | firebase.google.com |
| Supabase | BaaS | RN + Flutter | supabase.com |
| Appwrite | BaaS | RN + Flutter | appwrite.io |
| OneSignal | Bildirim | RN + Flutter | onesignal.com |
| Fastlane | CI/CD | iOS + Android | fastlane.tools |
| Codemagic | CI/CD | Flutter + RN | codemagic.io |
i18n (Çoklu Dil Desteği / Internationalization)
// React Native - i18next kullanımı (i18next usage)
// npm install i18next react-i18next
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
const resources = {
tr: {
translation: {
welcome: 'Hoşgeldiniz',
login: 'Giriş Yap',
register: 'Kayıt Ol',
settings: 'Ayarlar',
profile: 'Profil',
itemCount_one: '{{count}} ürün',
itemCount_other: '{{count}} ürün',
},
},
en: {
translation: {
welcome: 'Welcome',
login: 'Login',
register: 'Register',
settings: 'Settings',
profile: 'Profile',
itemCount_one: '{{count}} item',
itemCount_other: '{{count}} items',
},
},
};
i18n.use(initReactI18next).init({
resources,
lng: 'tr', // Varsayılan dil (Default language)
fallbackLng: 'en',
interpolation: { escapeValue: false },
});
// Kullanım (Usage)
import { useTranslation } from 'react-i18next';
function HomeScreen() {
const { t, i18n } = useTranslation();
return (
<View>
<Text>{t('welcome')}</Text>
<Text>{t('itemCount', { count: 5 })}</Text>
<Button
title="English"
onPress={() => i18n.changeLanguage('en')}
/>
</View>
);
}Harita Entegrasyonu (Maps Integration)
// React Native Maps kullanımı (Usage)
import MapView, { Marker, Callout } from 'react-native-maps';
function MapScreen() {
const [region, setRegion] = useState({
latitude: 41.0082,
longitude: 28.9784,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
return (
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={setRegion}
showsUserLocation
showsMyLocationButton
>
<Marker
coordinate={{ latitude: 41.0082, longitude: 28.9784 }}
title="İstanbul"
description="Türkiye'nin en büyük şehri"
>
<Callout>
<View>
<Text>İstanbul (Istanbul)</Text>
<Text>Nüfus: ~16 milyon</Text>
</View>
</Callout>
</Marker>
</MapView>
);
}10. İlgili Rehberler (Related Guides)
| Rehber (Guide) | Açıklama (Description) |
|---|---|
| React Native Rehberi | React Native ile mobil uygulama geliştirme |
| Flutter Rehberi | Flutter ile çapraz platform geliştirme |
| Mobil Genel Bakış | Mobil teknolojiler karşılaştırma ve yol haritası |
| Docker Rehberi | Backend servisleri konteynerleştirme |
| API Geliştirme Rehberi | REST/GraphQL API tasarımı |
| PostgreSQL Rehberi | Supabase'in kullandığı veritabanı |
| Redis Rehberi | Önbellekleme ve oturum yönetimi |
| TypeScript Rehberi | React Native ile TypeScript kullanımı |
Son Güncelleme (Last Updated): 2026-04-11