Gereksinimler ve Ön Hazırlık
Geliştirme ortamınızın güncel olduğundan emin olmalısınız. Bu rehberde Flutter 3.24 ve üzeri sürümler baz alınmıştır. Projenize eklemeniz gereken temel paketler şunlardır: file_picker (dosya seçimi için), dio (HTTP istekleri ve yükleme ilerlemesi için) ve path_provider (yerel dosya erişimi için).
Projenizin pubspec.yaml dosyasına gerekli bağımlılıkları ekleyerek başlayın:
dependencies:
flutter:
sdk: flutter
file_picker: ^8.0.0
dio: ^5.5.0
path_provider: ^2.1.0
Bağımlılıkları ekledikten sonra terminalde flutter pub get komutunu çalıştırarak paketlerin indirilmesini sağlayın. Ayrıca, Android ve iOS için gerekli izinleri (Manifest ve Info.plist dosyalarına) eklemeyi unutmayın.
Çoklu Dosya Seçimi ve Yönetim Arayüzü
Kullanıcının dosyaları seçebileceği ve seçilen dosyaların listelendiği bir arayüz oluşturmak, sürecin ilk adımıdır. FilePicker sınıfı, platforma özgü dosya seçicileri tetiklemek için en güvenilir yöntemdir.
Future dosyalariSec() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true,
type: FileType.any,
);
if (result != null) {
List dosyalar = result.paths.map((path) => File(path!)).toList();
// Seçilen dosyaları state yönetimi ile ekrana yansıtın
}
}
Bu kod bloğu, kullanıcının cihazından birden fazla dosyayı aynı anda seçmesine izin verir. allowMultiple: true parametresi, çoklu seçim modunu aktif eder.
Dio ile İlerleme Durumunu İzleyerek Yükleme
Dosya yükleme sırasında kullanıcının "yükleniyor" çubuğunu görmesi, uygulamanın profesyonelliğini artırır. Dio kütüphanesi, onSendProgress özelliği ile dosya yükleme oranını yüzde bazında takip etmemize olanak tanır.
Future dosyaYukle(File dosya) async {
Dio dio = Dio();
String fileName = dosya.path.split('/').last;
FormData formData = FormData.fromMap({
"file": await MultipartFile.fromFile(dosya.path, filename: fileName),
});
await dio.post(
"https://api.ornek.com/upload",
data: formData,
onSendProgress: (int sent, int total) {
double ilerleme = sent / total;
print("Yükleme durumu: ${(ilerleme * 100).toStringAsFixed(0)}%");
},
);
}
Burada FormData yapısı, dosyayı sunucunun anlayacağı "multipart/form-data" formatına dönüştürür. onSendProgress geri çağrısı, her veri paketinde tetiklenerek ilerlemeyi günceller.
Dosya Yükleme Yöntemlerinin Karşılaştırılması
Farklı dosya yükleme yaklaşımlarını performans ve güvenlik açısından değerlendirmek, projeniz için en doğru yöntemi seçmenize yardımcı olur.
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Multipart/Form-Data | Standart ve kolay uygulanabilir | Büyük dosyalarda bellek tüketimi |
| Chunked Upload (Parçalı) | Kesintiye dayanıklı, büyük dosyalar için uygun | Sunucu tarafında karmaşık mantık gerektirir |
| Direct to S3 (Signed URL) | Sunucu yükünü azaltır, çok hızlı | Güvenlik yapılandırması dikkat ister |
Güvenlik ve Hata Yönetimi
Kritik Güvenlik Uyarısı: Kullanıcıdan gelen dosyaları asla doğrudan sunucunuzun kök dizinine kaydetmeyin. Dosya uzantılarını ve MIME tiplerini mutlaka sunucu tarafında doğrulayın. Ayrıca, yüklenen dosyalara benzersiz isimler vererek "Path Traversal" saldırılarını engelleyin.
Uygulama tarafında hata yönetimi için try-catch bloklarını kullanmak, ağ hatalarını veya yetkilendirme sorunlarını yakalamanızı sağlar.
try {
await dosyaYukle(dosya);
} on DioException catch (e) {
// Sunucu hatalarını veya bağlantı kopmalarını burada yönetin
print("Hata oluştu: ${e.message}");
}
Sıkça Sorulan Sorular
Çok büyük dosyaları yüklerken uygulama neden çöküyor?
Büyük dosyalar cihazın RAM'ini tüketebilir. Bu durumda File nesnesi yerine Stream kullanarak dosyayı parçalar halinde okumayı ve yüklemeyi deneyin.
Arka planda yükleme yapmak mümkün mü?
Evet, flutter_background_service veya workmanager paketlerini kullanarak uygulama kapalıyken bile yükleme işlemlerini devam ettirebilirsiniz.
Sunucu tarafında dosya güvenliğini nasıl sağlarım?
Sunucuda dosya türünü (MIME type) mutlaka kontrol edin. Sadece izin verilen uzantıları (jpg, pdf, vb.) kabul edin ve dosyaları çalıştırılamaz bir dizinde saklayın.
İptal edilen yüklemeleri nasıl yönetirim?
CancelToken kullanarak devam eden bir Dio isteğini kullanıcı iptal ettiğinde durdurabilirsiniz.
Aynı anda kaç dosya yüklenmeli?
Cihaz kaynaklarını korumak için aynı anda en fazla 3-5 dosya yüklenmesini öneririz. Geri kalan dosyaları bir kuyruk (queue) yapısına alarak sırayla işleyebilirsiniz.
Yasal Uyarı: Bu rehberdeki kodlar eğitim amaçlıdır. Yazılım güvenliği, sunucu yapılandırması ve veri gizliliği konusunda sorumluluk geliştiriciye aittir. Üretim ortamına geçmeden önce mutlaka sızma testleri yapın.
İleri Düzey Performans Optimizasyonu: Chunked Uploads
Büyük boyutlu dosyaların tek bir HTTP isteği ile gönderilmesi, ağ kesintileri ve sunucu zaman aşımı (timeout) sorunlarına yol açabilir. Bu durumu aşmak için dosyayı küçük parçalara (chunk) bölerek yüklemek, profesyonel mobil uygulamalarda standart bir yaklaşımdır. Bu yöntem, yükleme başarısız olduğunda tüm dosyayı değil, sadece son parçayı tekrar göndermenize olanak tanır.
Dosyayı Parçalara Bölme Mantığı
Dosyayı RandomAccessFile kullanarak belirli bayt aralıklarıyla okuyup sunucuya gönderen bir yapı kurmalısınız. Aşağıdaki örnek, bir dosyanın nasıl parçalara ayrılacağını ve Dio ile nasıl gönderileceğini göstermektedir:
Future uploadFileInChunks(File file, String url) async {
final int chunkSize = 1024 * 1024; // 1MB parçalar
final int fileSize = await file.length();
int offset = 0;
while (offset < fileSize) {
final List bytes = await file.openRead(offset, offset + chunkSize).first;
await Dio().post(
url,
data: Stream.fromIterable(bytes.map((e) => [e])),
options: Options(
headers: {
'Content-Range': 'bytes $offset-${offset + bytes.length - 1}/$fileSize',
},
),
);
offset += bytes.length;
}
}
Yükleme Süreçlerinde Hata Ayıklama ve Loglama
Dosya yükleme hataları genellikle ağ katmanında veya sunucu tarafındaki dosya boyutu sınırlamalarında (upload_max_filesize) oluşur. Uygulamanızın üretim aşamasında hata ayıklama sürecini kolaylaştırmak için Dio interceptor yapısını kullanmak en sağlıklı yoldur.
Interceptor ile Hata Takibi
Aşağıdaki yapı, yükleme sırasında oluşan tüm hataları yakalar ve sunucudan gelen detaylı hata mesajlarını konsola veya bir log servisine (Sentry, Firebase Crashlytics vb.) aktarır:
dio.interceptors.add(InterceptorsWrapper(
onError: (DioException e, handler) {
print("Hata Detayı: ${e.response?.statusCode} - ${e.message}");
if (e.type == DioExceptionType.connectionTimeout) {
// Kullanıcıya ağ bağlantısını kontrol etmesini söyleyin
}
return handler.next(e);
},
));
İpucu: Yükleme panelinizde "Retry" (Yeniden Dene) mekanizması kurarken, üstel geri çekilme (exponential backoff) algoritmasını kullanın. Bu, sunucunun aşırı yüklenmesini engeller.
Alternatif Kütüphane Seçenekleri
Dio dışında, özellikle büyük dosya transferlerinde özelleşmiş kütüphaneler de tercih edilebilir:
- flutter_uploader: Arka plan yüklemeleri (Background Upload) için en kararlı kütüphanelerden biridir. İşletim sistemi seviyesinde yükleme yönetimi sağlar.
- tus_client_dart: "Resumable Upload" (kaldığı yerden devam eden yükleme) protokolü olan TUS.io için geliştirilmiştir. Profesyonel dosya sunucuları ile mükemmel uyum sağlar.
Sonuç
Flutter ile çoklu dosya yükleme paneli geliştirmek, doğru araçlar ve iyi bir mimari ile oldukça verimli bir süreçtir. Dio ve FilePicker ikilisi, modern mobil uygulamalar için en sağlam temeli sunar. Bir sonraki adım olarak, yüklenen dosyaların sunucuda işlenmesi (örneğin görsel ise yeniden boyutlandırılması) ve veritabanı ile eşleştirilmesi süreçlerine odaklanabilirsiniz. Başarılı kodlamalar dileriz.

Yorumlar (0)
Yorum Yaz