· Admin

Flutter ile Cross-Platform Uygulama Geliştirme: Tek Kodla Her Platforma

Mobil uygulama gelistirme dunyasinda "iOS ve Android icin ayri ayri mi yazacagiz?" sorusu hep var. Swift ile iOS, Kotlin ile Android gelistirmek ideal gibi gorunse de iki ayri ekip, iki ayri codebase ve iki kati is yuku demek. Flutter bu soruna Google'in cevabi. Ben SmartSepet projesinde Flutter'i sectigimde, tek codebase ile her iki platforma uygulama cikarabilmenin ne kadar verimli oldugunu bizzat deneyimledim. Bu yazida Flutter'i neden sectigimi, nasil calistigini ve gercek dunya deneyimlerimi paylasiyorum.

Flutter Nedir ve Neden Tercih Edilmeli?

Flutter, Google tarafindan gelistirilen acik kaynakli bir UI toolkit'tir. Tek bir Dart codebase ile iOS, Android, Web, Windows, macOS ve Linux uygulamalari gelistirebilirsiniz. Ama "cross-platform" demek "her seyi yarim yamalak yapan" anlamina gelmiyor. Flutter native performansa yakin sonuclar uretiyor cunku kendi rendering engine'ini kullaniyor (Skia/Impeller). Platform'un native widget'larini sarmalamiyor, kendi piksellerini ciziyor.

Tercih nedenlerim:

  • Tek codebase: iOS ve Android icin ayni kodu yaziyorsunuz. Yuzde doksan bes oraninda kod paylasimi mumkun.
  • Hot reload: Kod degisiklikleri aninda ekrana yansiyor. Bu gelistirme hizini inanilmaz artiriyor.
  • Zengin widget kutuphanesi: Material Design ve Cupertino widget'lari hazir geliyor.
  • Dart dili: Ogrenilmesi kolay, tip guvenligi olan modern bir dil.
  • Buyuk topluluk: Google destegi, pub.dev'de binlerce paket.

Dart Dili Hizli Giris

Flutter'in dili Dart, JavaScript ve Java'nin karisimi gibi. Tip guvenligi var ama cok katı degil. Hizli bir bakis:

// Degiskenler
String name = 'ProjeMan';
int age = 30;
double price = 29.99;
bool isActive = true;
var autoType = 'Dart bunu String olarak anlar';

// Null safety (Dart 3+)
String? nullableString; // null olabilir
String nonNullable = 'bos olamaz';

// Fonksiyonlar
int sum(int a, int b) => a + b;

// Named parameters
void createUser({required String name, int? age}) {
  print('$name - ${age ?? "belirtilmedi"}');
}

// Async/Await
Future<String> fetchData() async {
  final response = await http.get(Uri.parse('https://api.projeman.net/data'));
  return response.body;
}

// Koleksiyon tipleri
List<String> fruits = ['elma', 'armut', 'muz'];
Map<String, int> scores = {'math': 90, 'science': 85};
Set<int> uniqueNumbers = {1, 2, 3};

Dart'in null safety ozelligi benim en sevdigim ozelliklerden biri. Compile time'da null hatalarini yakalamanizi sagliyor. JavaScript'te runtime'da "Cannot read property of undefined" gormekten biktiyseniz, Dart sizi mutlu edecek.

Widget Sistemi

Flutter'da her sey bir widget'tir. Bir buton, bir metin, bir sayfa duzeni, hatta uygulamanin kendisi bir widget. Iki temel widget tipi var:

StatelessWidget

Durumu olmayan, degismeyen widget'lar icin:

class WelcomeCard extends StatelessWidget {
  final String name;

  const WelcomeCard({super.key, required this.name});

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 4,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Text(
              'Hosgeldin, $name',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 8),
            const Text('Bugun ne yapmak istersin?'),
          ],
        ),
      ),
    );
  }
}

StatefulWidget

Degisen durumu olan widget'lar icin:

class CounterWidget extends StatefulWidget {
  const CounterWidget({super.key});

  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text('Sayac: $_count', style: const TextStyle(fontSize: 32)),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Artir'),
        ),
      ],
    );
  }
}

setState() cagrisi Flutter'a "bu widget'i yeniden ciz" demektir. Kucuk widget'lar icin bu yeterli ama uygulama buyudukce daha iyi state management cozumleri gerekiyor.

Hot Reload Avantaji

Hot reload, Flutter'in en guclu ozelliklerinden biri. Kodu degistiriyorsunuz, kaydediyorsunuz ve degisiklik aninda ekranda gorunuyor. State korunuyor, uygulama yeniden baslatilmiyor.

Bu ozellik gelistirme surecini dramatik sekilde hizlandiriyor. Ornegin bir UI duzenliyorsunuz: padding'i 16'dan 24'e cektiniz, rengi degistirdiniz, text boyutunu ayarladiniz. Her degisiklik icin uygulamayi yeniden derlemek yerine aninda gorebiliyorsunuz.

Native gelistirmede (Swift/Kotlin) bir degisiklik icin 10-30 saniye beklemeniz gerekebilir. Flutter'da bu sureyi sifira indiriyorsunuz.

State Management

Uygulama buyudukce setState() yetmez olur. Flutter ekosisteminde bircok state management cozumu var. En populerleri:

Provider (Basit projeler icin)

class CartProvider extends ChangeNotifier {
  final List<Product> _items = [];

  List<Product> get items => _items;
  double get totalPrice => _items.fold(0, (sum, item) => sum + item.price);

  void addItem(Product product) {
    _items.add(product);
    notifyListeners(); // Dinleyicilere haber ver
  }

  void removeItem(Product product) {
    _items.remove(product);
    notifyListeners();
  }
}

// Kullanim
class CartScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final cart = context.watch<CartProvider>();

    return ListView.builder(
      itemCount: cart.items.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(cart.items[index].name),
          trailing: Text('${cart.items[index].price} TL'),
        );
      },
    );
  }
}

Riverpod (Orta-buyuk projeler icin)

Provider'in evrilmis hali. Compile-time guvenlik saglar, global erisim mumkun:

final productsProvider = FutureProvider<List<Product>>((ref) async {
  final response = await ref.read(apiClientProvider).getProducts();
  return response;
});

class ProductListScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final productsAsync = ref.watch(productsProvider);

    return productsAsync.when(
      data: (products) => ListView.builder(
        itemCount: products.length,
        itemBuilder: (_, i) => ProductCard(product: products[i]),
      ),
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (err, stack) => Center(child: Text('Hata: $err')),
    );
  }
}

SmartSepet projesinde Riverpod kullanmayi tercih ettim. Ozellikle API cagrilarinin durumunu yonetmek (loading, error, data) icin FutureProvider ve AsyncNotifier harika calisiyorlar.

REST API Entegrasyonu

Flutter'da API istekleri icin http veya dio paketleri kullanilir. Ben daha kapsamli olan dio'yu tercih ediyorum:

class ApiService {
  final Dio _dio;

  ApiService() : _dio = Dio(BaseOptions(
    baseUrl: 'https://api.projeman.net',
    connectTimeout: const Duration(seconds: 10),
    receiveTimeout: const Duration(seconds: 10),
    headers: {'Accept': 'application/json'},
  )) {
    _dio.interceptors.add(LogInterceptor(responseBody: true));
  }

  Future<List<Product>> getProducts({int page = 1}) async {
    try {
      final response = await _dio.get('/products', queryParameters: {'page': page});
      final List data = response.data['data'];
      return data.map((json) => Product.fromJson(json)).toList();
    } on DioException catch (e) {
      throw ApiException(message: e.message ?? 'Baglanti hatasi');
    }
  }

  Future<void> addToCart(int productId, int quantity) async {
    await _dio.post('/cart', data: {
      'product_id': productId,
      'quantity': quantity,
    });
  }
}

Platform-Specific Kod Yazma

Bazi durumlarda platforma ozel kod yazmaniz gerekir. Flutter bunu Platform sinifi ve method channel ile saglar:

import 'dart:io' show Platform;

Widget buildButton() {
  if (Platform.isIOS) {
    return CupertinoButton(
      child: const Text('iOS Butonu'),
      onPressed: () {},
    );
  }
  return ElevatedButton(
    onPressed: () {},
    child: const Text('Android Butonu'),
  );
}

Flutter vs React Native

Bu karsilastirmayi sik duyuyorum. Kendi deneyimime gore:

  • Performans: Flutter genelde daha hizli. Kendi rendering engine'i var, native kopru (bridge) yok.
  • Gelistirme hizi: Flutter'in hot reload'u daha stabil. React Native'de bazen tam yeniden baslatma gerekiyor.
  • Ekosistem: React Native'in npm ekosistemi daha buyuk ama Flutter'in pub.dev'i hizla buyuyor.
  • Ogrenme egrisi: React biliyorsaniz React Native daha kolay. Sifirdan basliyorsaniz Flutter/Dart daha tutarli.
  • Web destegiw: Flutter web stabil ama SEO icin ideal degil. React Native'de (Expo) web destegi daha olgun.

Ben Flutter'i sectim cunku tek bir dil (Dart) ile her seyi yapabiliyorum ve performans konusunda taviz vermek istemiyordum.

SmartSepet Projesinde Flutter Deneyimim

SmartSepet, market alisverisini akillilastirmayi hedefleyen bir mobil uygulama. OCR ile fiyat etiketi okuma, sepet takibi ve fiyat karsilastirma gibi ozellikler iceriyor.

Flutter'i bu projede secmemin ana nedeni: hem iOS hem Android'de kamera erisimi, OCR isleme ve konum hizmetlerine ihtiyacim vardi. Tek codebase ile bunlarin hepsini yonetebildim.

Karsilastigim zorluklar ve cozumler:

  • Kamera ve OCR: camera paketi ile canli onizleme, Google ML Kit ile metin tanima. Platform-specific ayarlamalar gerekti ama Flutter'in method channel yapisi bunu kolaylastirdi.
  • Konum servisleri: geolocator paketi ile konum alma, yakin marketleri listeleme.
  • State yonetimi: Sepet durumu, API cache, kullanici ayarlari gibi farkli state katmanlari icin Riverpod kullandim.

Flutter ile bir MVP'yi hizla ayaga kaldirmak mumkun. SmartSepet'in ilk calisan prototipini iki haftada cikardim. Ayni isi native olarak yapsaydim en az iki kati zaman alirdi.

Sonuc

Flutter, cross-platform mobil gelistirme icin su an en guclu seceneklerden biri. Hot reload ile hizli gelistirme, Dart'in modern dil ozellikleri, zengin widget kutuphanesi ve native performansa yakin sonuclar uretiyor. Eger hem iOS hem Android icin uygulama gelistirmek istiyorsaniz ve ayri codebase'ler yonetmek istemiyorsaniz, Flutter'a bir sans verin. Dart'i ogrenmek bir-iki hafta surecektir ama o yatirim uzun vadede fazlasiyla karsiligini veriyor.