Gereksinimler ve Ön Hazırlık
Projenize başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. Flutter 3.24 ve üzeri sürümleri, performans iyileştirmeleri ve yeni "dart" özellikleri nedeniyle önerilmektedir. Projenizde kullanacağımız temel paketler şunlardır:
- file_picker: Cihazdan çoklu dosya seçimi yapmak için.
- dio: HTTP isteklerini yönetmek ve yükleme ilerlemesini (progress) takip etmek için.
- path: Dosya yollarını yönetmek için.
Projenizin pubspec.yaml dosyasına şu bağımlılıkları ekleyerek işe başlayın:
dependencies:
flutter:
sdk: flutter
file_picker: ^8.0.0
dio: ^5.7.0
path: ^1.9.0
Paketleri ekledikten sonra terminalinizde flutter pub get komutunu çalıştırarak bağımlılıkları projenize dahil edin. Ayrıca Android için AndroidManifest.xml dosyanızda internet izninin tanımlı olduğundan emin olun.
Adım Adım Çoklu Dosya Seçme Mekanizması
Kullanıcının cihazından dosya seçmesini sağlamak için file_picker paketini kullanacağız. Bu paket, hem galeriye erişim hem de dosya yöneticisi entegrasyonu konusunda oldukça esnektir. Aşağıdaki kod bloğu, kullanıcının birden fazla dosyayı aynı anda seçmesini sağlar.
Future pickMultipleFiles() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true,
type: FileType.any,
);
if (result != null) {
return result.files;
}
return null;
}
Bu fonksiyon, kullanıcı dosyaları seçtiğinde bir PlatformFile listesi döndürür. Eğer kullanıcı işlemi iptal ederse null değeri döner. Bu yapıyı bir StatefulWidget içerisinde çağırarak seçilen dosyaları bir listede tutabiliriz.
Dio ile İleri Düzey Yükleme Yönetimi
Dosyaları sunucuya gönderirken Dio kütüphanesini tercih etmemizin en büyük nedeni, onSendProgress fonksiyonudur. Bu fonksiyon sayesinde yükleme yüzdesini anlık olarak takip edebilir ve kullanıcıya görsel geri bildirim verebiliriz. Aşağıdaki örnekte çoklu dosyaların nasıl yükleneceğini görebilirsiniz.
Future uploadFiles(List files) async {
Dio dio = Dio();
for (var file in files) {
FormData formData = FormData.fromMap({
"file": await MultipartFile.fromFile(file.path!, filename: file.name),
});
await dio.post(
"https://api.sunucunuz.com/upload",
data: formData,
onSendProgress: (int sent, int total) {
double progress = sent / total;
print("Yükleme durumu: ${(progress * 100).toStringAsFixed(0)}%");
},
);
}
}
Bu fonksiyon, her bir dosyayı döngüye alarak sırayla yükler. Eğer paralel yükleme yapmak isterseniz, Future.wait metodunu kullanabilirsiniz; ancak bu durum ağ trafiğini aşırı zorlayabilir.
Dosya Yükleme Paneli Arayüzü Tasarımı
Kullanıcıların yükleme sürecini takip edebilmesi için bir ListView ve LinearProgressIndicator kullanmak en temiz yaklaşımdır. Her bir dosya için ayrı bir durum (state) tutarak arayüzü güncel tutabiliriz.
ListView.builder(
itemCount: selectedFiles.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(selectedFiles[index].name),
subtitle: LinearProgressIndicator(value: uploadProgress[index]),
);
},
)
Bu arayüz bileşeni, uploadProgress listesindeki değerlere göre ilerleme çubuğunu günceller. setState metodunu çağırarak arayüzün yeniden çizilmesini tetiklemeyi unutmayın.
Yöntemlerin Karşılaştırılması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Dio (Multipart) | İlerleme takibi ve hata yönetimi kolay. | Büyük dosyalarda bellek kullanımı artabilir. |
| Firebase Storage | Backend kurulumu gerektirmez. | Daha maliyetli olabilir. |
Güvenlik ve Hata Yönetimi
Kritik Güvenlik Uyarısı: Dosya yükleme panelleri, sunucu tarafında en büyük güvenlik açıklarından biridir. Sunucunuza yüklenen dosyaların uzantılarını mutlaka kontrol edin (mime-type validation). Asla kullanıcı tarafından sağlanan dosya isimlerine güvenmeyin; sunucuda dosyaları rastgele UUID isimlerle kaydedin ve SQL injection riskine karşı veritabanı sorgularınızı parametreli olarak çalıştırın.
Yükleme sırasında oluşabilecek hataları yakalamak için try-catch bloklarını kullanmak zorunludur. Özellikle ağın koptuğu veya sunucunun zaman aşımına uğradığı durumları yönetmelisiniz.
try {
await uploadFiles(files);
} on DioException catch (e) {
print("Hata oluştu: ${e.message}");
} catch (e) {
print("Beklenmedik bir hata: $e");
}
Sıkça Sorulan Sorular
Çoklu dosya yükleme sırasında uygulama donuyor, ne yapmalıyım?
İşlemleri ana thread (UI thread) üzerinde yapıyorsanız bu normaldir. Dio'nun asenkron yapısını kullandığınızdan ve ağır işlemleri compute fonksiyonu ile isolate üzerinde yürüttüğünüzden emin olun.
Yükleme sırasında dosya boyutu sınırını nasıl aşabilirim?
Dosya boyutu sınırı genellikle sunucu tarafındadır (Nginx/Apache). Flutter tarafında ise file_picker ile seçilen dosyaları yüklemeden önce boyut kontrolü yaparak kullanıcıyı uyarabilirsiniz.
Aynı anda kaç dosya yüklenmeli?
Kullanıcı deneyimi açısından aynı anda 3-5 dosyadan fazlasının yüklenmesi önerilmez. Kuyruk (queue) yönetimi yaparak dosyaları sırayla yüklemek en sağlıklı yöntemdir.
Arka planda yükleme devam edebilir mi?
Evet, flutter_background_service gibi paketler kullanarak uygulamanız kapansa bile yükleme işleminin devam etmesini sağlayabilirsiniz.
Yükleme iptal edilebilir mi?
Evet, Dio'nun CancelToken özelliğini kullanarak kullanıcının "İptal Et" butonuna basması durumunda yükleme işlemini anında durdurabilirsiniz.
Performans Optimizasyonu ve Bellek Yönetimi
Çoklu dosya yükleme işlemlerinde karşılaşılan en büyük sorunlardan biri, büyük boyutlu dosyaların belleğe (RAM) yüklenmesi sonucu oluşan OutOfMemory hatalarıdır. Flutter uygulamanızın stabil kalması için dosyaları doğrudan belleğe okumak yerine Stream yapısını kullanmalısınız.
Aşağıdaki örnek, bir dosyanın belleği yormadan, parçalar halinde (chunk) nasıl okunup yüklenebileceğini göstermektedir:
Future uploadFileInChunks(File file, String url) async {
final dio = Dio();
final length = await file.length();
await dio.put(
url,
data: file.openRead(),
options: Options(
headers: {
Headers.contentLengthHeader: length,
'Content-Type': 'application/octet-stream',
},
),
);
}
Bu yöntem, dosyanın tamamını RAM'e yüklemeden, openRead() metodu ile veriyi akış (stream) olarak sunucuya iletir. Özellikle yüksek çözünürlüklü video veya büyük veri dosyalarıyla çalışırken bu yaklaşım uygulamanızın donmasını engeller.
İleri Düzey Hata Ayıklama ve Loglama
Yükleme süreçlerinde yaşanan başarısızlıkların kaynağını bulmak için Dio kütüphanesinin LogInterceptor özelliğini aktif etmeniz kritik öneme sahiptir. Bu sayede, sunucuya giden isteklerin başlıklarını ve dönen hata kodlarını detaylıca inceleyebilirsiniz.
Uygulamanızın geliştirme aşamasında hata ayıklama süreçlerini yönetmek için şu yapılandırmayı kullanabilirsiniz:
final dio = Dio();
dio.interceptors.add(
LogInterceptor(
request: true,
requestHeader: true,
requestBody: true,
responseHeader: true,
responseBody: true,
error: true,
),
);
// Hata durumunda kullanıcıya anlamlı mesaj döndürme
try {
await dio.post('/upload', data: formData);
} on DioException catch (e) {
if (e.type == DioExceptionType.connectionTimeout) {
print("Sunucuya bağlanılamadı, internet bağlantınızı kontrol edin.");
} else if (e.response?.statusCode == 413) {
print("Dosya boyutu sunucu limitlerini aşıyor.");
}
}
Yükleme Süreçlerinde İzleme Tablosu
Yükleme işlemlerini yönetirken uygulamanızın durumunu şu kriterlere göre takip etmeniz önerilir:
| Durum | Açıklama | Önerilen Aksiyon |
|---|---|---|
| Pending | Dosya kuyruğa eklendi. | Kullanıcıya "Sıraya alındı" bilgisi ver. |
| Uploading | Veri transferi devam ediyor. | İlerleme çubuğunu (Progress Bar) güncelle. |
| Failed | Bağlantı veya sunucu hatası. | Otomatik yeniden deneme (Retry) mekanizması kur. |
| Completed | Yükleme başarıyla bitti. | Dosya listesini yenile. |
Bu stratejiler, uygulamanızın sadece çalışmasını değil, aynı zamanda zorlu ağ koşullarında bile profesyonel bir kullanıcı deneyimi sunmasını sağlar.
Sonuç
Flutter ile ileri düzey bir çoklu dosya yükleme paneli oluşturmak, doğru kütüphane seçimi ve iyi bir hata yönetimi ile oldukça verimli bir süreçtir. Bu rehberde öğrendiğiniz Dio ile ilerleme takibi ve file_picker ile dosya seçimi, profesyonel bir mobil uygulamanın temel taşlarıdır. Bir sonraki adım olarak, yüklenen dosyaların sunucuda işlenmesi ve veritabanı ile ilişkilendirilmesi konularına odaklanabilirsiniz.
Yasal Sorumluluk Reddi: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce, sunucu tarafındaki güvenlik duvarı kurallarını ve dosya yükleme izinlerini kendi sistem mimarinize göre yapılandırmanız gerekmektedir. Yazılım güvenliği sorumluluğu geliştiriciye aittir.

Yorumlar (0)
Yorum Yaz