Mobile App
Mobil Marketplace Uygulaması
React Native ve Flutter ile iOS/Android e-ticaret uygulaması geliştirme. Push notification, ödeme, offline mode ve performance optimization.
📱Mobil Geliştirme Teknolojileri
Mobil marketplace kullanıcı trafiğinin %70-80'ini oluşturur. React Native veya Flutter ile hem iOS hem Android için tek kod tabanı.
React Native
• Dil: JavaScript/TypeScript
• Performans: İyi (native bridge)
• Ekosistem: Çok geniş
• Örnekler: Facebook, Instagram, Shopify
• Maliyet: 150-300K TL
Flutter
• Dil: Dart
• Performans: Çok iyi (direkt compile)
• Ekosistem: Büyüyor
• Örnekler: Alibaba, eBay, Google Pay
• Maliyet: 120-250K TL
React Native Marketplace
// React Native E-Ticaret Ana Ekran
import React, { useState, useEffect } from 'react';
import { View, FlatList, StyleSheet, RefreshControl } from 'react-native';
import { SearchBar, Card, Button } from 'react-native-elements';
const HomeScreen = ({ navigation }) => {
const [products, setProducts] = useState([]);
const [search, setSearch] = useState('');
const [refreshing, setRefreshing] = useState(false);
useEffect(() => {
fetchProducts();
}, []);
const fetchProducts = async () => {
try {
const response = await fetch('https://api.example.com/products');
const data = await response.json();
setProducts(data.products);
} catch (error) {
console.error('Error fetching products:', error);
}
};
const onRefresh = async () => {
setRefreshing(true);
await fetchProducts();
setRefreshing(false);
};
const renderProduct = ({ item }) => (
<Card containerStyle={styles.card}>
<Card.Image
source={{ uri: item.image }}
style={styles.productImage}
resizeMode="cover"
/>
<Card.Title>{item.name}</Card.Title>
<View style={styles.priceContainer}>
<Text style={styles.price}>{item.price} TL</Text>
{item.discount && (
<Text style={styles.oldPrice}>{item.oldPrice} TL</Text>
)}
</View>
<Button
title="Sepete Ekle"
onPress={() => addToCart(item)}
buttonStyle={styles.addButton}
/>
</Card>
);
return (
<View style={styles.container}>
<SearchBar
placeholder="Ürün ara..."
onChangeText={setSearch}
value={search}
platform="ios"
containerStyle={styles.searchBar}
/>
<FlatList
data={products.filter(p =>
p.name.toLowerCase().includes(search.toLowerCase())
)}
renderItem={renderProduct}
keyExtractor={item => item.id}
numColumns={2}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
/>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f5f5f5' },
searchBar: { backgroundColor: 'transparent' },
card: { borderRadius: 8, margin: 5, padding: 10 },
productImage: { height: 150, borderRadius: 8 },
priceContainer: { flexDirection: 'row', marginTop: 10 },
price: { fontSize: 18, fontWeight: 'bold', color: '#10B981' },
oldPrice: { fontSize: 14, textDecorationLine: 'line-through', marginLeft: 8 },
addButton: { backgroundColor: '#10B981', marginTop: 10 }
});
export default HomeScreen;Push Notification
// Firebase Cloud Messaging (FCM) entegrasyonu
import messaging from '@react-native-firebase/messaging';
import notifee from '@notifee/react-native';
// Notification permission
async function requestUserPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
getFCMToken();
}
}
// FCM Token al
async function getFCMToken() {
const fcmToken = await messaging().getToken();
console.log('FCM Token:', fcmToken);
// Token'ı backend'e gönder
await fetch('https://api.example.com/users/fcm-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: fcmToken })
});
}
// Foreground notification (app açıkken)
messaging().onMessage(async remoteMessage => {
console.log('Notification received:', remoteMessage);
// Notifee ile local notification göster
await notifee.displayNotification({
title: remoteMessage.notification.title,
body: remoteMessage.notification.body,
android: {
channelId: 'default',
smallIcon: 'ic_launcher',
pressAction: {
id: 'default',
},
},
ios: {
sound: 'default',
},
});
});
// Background notification (app kapalıyken)
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Background notification:', remoteMessage);
});
// Notification tıklama
messaging().onNotificationOpenedApp(remoteMessage => {
console.log('Notification opened:', remoteMessage);
// Deep linking
if (remoteMessage.data.productId) {
navigation.navigate('ProductDetail', {
productId: remoteMessage.data.productId
});
}
});
// App Service Worker (backend - Node.js)
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert('serviceAccountKey.json')
});
async function sendPushNotification(userId, title, body, data) {
// User'ın FCM token'ını database'den al
const user = await getUserById(userId);
if (user.fcmToken) {
const message = {
notification: { title, body },
data: data || {},
token: user.fcmToken
};
try {
const response = await admin.messaging().send(message);
console.log('Notification sent:', response);
} catch (error) {
console.error('Error sending notification:', error);
}
}
}
// Toplu gönderim (batch)
async function sendBulkNotifications(userIds, title, body) {
const tokens = await getUserTokens(userIds);
const message = {
notification: { title, body },
tokens: tokens // Max 500 token
};
const response = await admin.messaging().sendMulticast(message);
console.log(`${response.successCount} notifications sent`);
}Ödeme Entegrasyonu (iyzico)
// React Native iyzico WebView ödeme
import { WebView } from 'react-native-webview';
const PaymentScreen = ({ route }) => {
const { orderId, amount } = route.params;
const [paymentUrl, setPaymentUrl] = useState(null);
useEffect(() => {
initiatePayment();
}, []);
const initiatePayment = async () => {
// Backend'den ödeme URL'i al
const response = await fetch('https://api.example.com/payments/initiate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderId,
amount,
returnUrl: 'myapp://payment-success',
cancelUrl: 'myapp://payment-cancel'
})
});
const data = await response.json();
setPaymentUrl(data.paymentPageUrl); // iyzico 3D Secure URL
};
const onNavigationStateChange = (navState) => {
// Ödeme sonucu kontrolü
if (navState.url.includes('payment-success')) {
navigation.navigate('OrderSuccess', { orderId });
} else if (navState.url.includes('payment-cancel')) {
navigation.navigate('OrderFailed');
}
};
return (
<View style={{ flex: 1 }}>
{paymentUrl ? (
<WebView
source={{ uri: paymentUrl }}
onNavigationStateChange={onNavigationStateChange}
startInLoadingState
/>
) : (
<ActivityIndicator size="large" color="#10B981" />
)}
</View>
);
};
// Alternatif: Native ödeme (Apple Pay, Google Pay)
import { PaymentRequest } from 'react-native-payments';
const payWithApplePay = async (amount) => {
const METHOD_DATA = [{
supportedMethods: ['apple-pay'],
data: {
merchantIdentifier: 'merchant.com.yourapp',
supportedNetworks: ['visa', 'mastercard'],
countryCode: 'TR',
currencyCode: 'TRY'
}
}];
const DETAILS = {
total: {
label: 'Toplam',
amount: { currency: 'TRY', value: amount.toString() }
}
};
const paymentRequest = new PaymentRequest(METHOD_DATA, DETAILS);
try {
const paymentResponse = await paymentRequest.show();
const { paymentToken } = paymentResponse.details;
// Token'ı backend'e gönder
await processPayment(paymentToken);
paymentResponse.complete('success');
} catch (error) {
console.error('Payment error:', error);
}
};Offline Mode ve Caching
// AsyncStorage ile offline data
import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';
class OfflineManager {
static async saveProductsCache(products) {
await AsyncStorage.setItem('cached_products', JSON.stringify(products));
}
static async getCachedProducts() {
const cached = await AsyncStorage.getItem('cached_products');
return cached ? JSON.parse(cached) : [];
}
static async fetchProductsWithOffline() {
const netInfo = await NetInfo.fetch();
if (netInfo.isConnected) {
// Online: API'den çek
try {
const response = await fetch('https://api.example.com/products');
const products = await response.json();
// Cache'e kaydet
await this.saveProductsCache(products);
return { products, source: 'api' };
} catch (error) {
// API başarısız, cache'den oku
const cached = await this.getCachedProducts();
return { products: cached, source: 'cache' };
}
} else {
// Offline: Cache'den oku
const cached = await this.getCachedProducts();
return { products: cached, source: 'offline' };
}
}
// Pending actions (sepete ekleme vb.)
static async addPendingAction(action) {
const pending = await this.getPendingActions();
pending.push(action);
await AsyncStorage.setItem('pending_actions', JSON.stringify(pending));
}
static async syncPendingActions() {
const pending = await this.getPendingActions();
for (const action of pending) {
try {
await this.executeAction(action);
// Başarılı, listeden çıkar
pending.shift();
} catch (error) {
// Hata, daha sonra tekrar dene
break;
}
}
await AsyncStorage.setItem('pending_actions', JSON.stringify(pending));
}
}
// Network durumunu dinle
NetInfo.addEventListener(state => {
if (state.isConnected) {
// İnternet geri geldi, pending actions'ları senkronize et
OfflineManager.syncPendingActions();
}
});Performance Optimization
Optimizasyon Teknikleri:
• Image caching: react-native-fast-image kullan
• Lazy loading: FlatList için initialNumToRender=10
• Memoization: React.memo(), useMemo(), useCallback()
• Bundle size: Hermes engine kullan (Android)
• Network: GraphQL + caching (Apollo Client)
• Analytics: Crash reporting (Sentry, Firebase Crashlytics)
// Performance best practices
import React, { memo, useMemo, useCallback } from 'react';
import FastImage from 'react-native-fast-image';
// 1. Memo ile gereksiz render'ları önle
const ProductCard = memo(({ product, onPress }) => {
return (
<TouchableOpacity onPress={() => onPress(product.id)}>
<FastImage
source={{ uri: product.image, priority: FastImage.priority.normal }}
style={styles.image}
resizeMode={FastImage.resizeMode.cover}
/>
<Text>{product.name}</Text>
<Text>{product.price} TL</Text>
</TouchableOpacity>
);
});
// 2. useCallback ile fonksiyon referansını sabit tut
const ProductList = ({ products }) => {
const handlePress = useCallback((productId) => {
navigation.navigate('ProductDetail', { productId });
}, []);
// 3. useMemo ile pahalı hesaplamaları cache'le
const sortedProducts = useMemo(() => {
return products.sort((a, b) => b.rating - a.rating);
}, [products]);
return (
<FlatList
data={sortedProducts}
renderItem={({ item }) => (
<ProductCard product={item} onPress={handlePress} />
)}
keyExtractor={item => item.id}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index
})}
/>
);
};Geliştirme Süreci ve Maliyet
| Özellik | Süre | Maliyet | Öncelik |
|---|---|---|---|
| Temel UI/UX (ürün, sepet, profil) | 4 hafta | 60K TL | Must-have |
| Ödeme entegrasyonu | 2 hafta | 25K TL | Must-have |
| Push notification | 1 hafta | 15K TL | Should-have |
| Offline mode | 2 hafta | 20K TL | Nice-to-have |
| Test + yayınlama (App Store, Play Store) | 2 hafta | 30K TL | Must-have |
Toplam Maliyet (MVP):
• Geliştirme: 150K TL (React Native, 11 hafta)
• Tasarım: 30K TL (UI/UX designer)
• Backend: 50K TL (API geliştirme, varsa)
• App Store/Play Store: 2.5K TL/yıl
• Toplam: 230K TL
Mobil Marketplace Uygulamanızı Geliştirelim
React Native veya Flutter ile iOS/Android e-ticaret uygulaması. Push notification, ödeme, offline mode ile tam özellikli çözüm.
Demo İste→