Загрузка файла с мобильного устройства выглядит как простая задача до первого краша на Android 10+ из-за изменения URI в FileProvider, или до первого rejected review в App Store из-за неправильного запроса разрешений на медиатеку. Мы, как мобильные разработчики с опытом 5+ лет, сталкивались с этими граблями десятки раз. Разбираем, что важно сделать правильно, чтобы приложение не отклонили и оно не падало.
На Android основная боль — работа с content:// URI вместо прямых путей к файлу. Начиная с Android 10 (API 29) прямой доступ к файловой системе ограничен, и попытки передать file:// путь напрямую в Retrofit/OkHttp приводят к FileUriExposedException. Правильный подход — читать файл через ContentResolver.openInputStream() и передавать поток, а не путь.
На iOS доступ к фотобиблиотеке требует корректного Info.plist: NSPhotoLibraryUsageDescription для iOS 13 и ниже, PHPickerViewController для iOS 14+ (не требует разрешений на весь фотоальбом). Использование устаревшего UIImagePickerController с .photoLibrary сегодня — прямая дорога к замечанию от ревьюера Apple. Как рекомендует Apple, используйте PHPicker для iOS 14+ (Apple Human Interface Guidelines).
Как избежать типичных ошибок при загрузке файлов?
Для Multipart upload на Android используем Retrofit:
@Multipart @POST("upload") suspend fun uploadFile( @Part file: MultipartBody.Part, @Part("description") description: RequestBody ): Response<UploadResponse> // вызов: val requestBody = file.asRequestBody("image/*".toMediaTypeOrNull()) val part = MultipartBody.Part.createFormData("file", file.name, requestBody) Для больших файлов (видео, архивы) — потоковая передача через RequestBody с переопределённым writeTo, чтобы не грузить весь файл в память.
На iOS используем URLSession.uploadTask(with:from:) или Alamofire:
AF.upload( multipartFormData: { form in form.append(fileURL, withName: "file") }, to: "https://api.example.com/upload" ).uploadProgress { progress in print(progress.fractionCompleted) }.responseDecodable(of: UploadResponse.self) { response in // handle } Flutter: пакет dio с FormData и MultipartFile.fromFile(). Прогресс через onSendProgress.
Важно отдельно обработать прогресс загрузки — пользователь должен видеть ProgressBar/LinearProgressIndicator с реальными процентами, а не спиннер. Отмена загрузки реализуется через CancellationToken (Kotlin) или Task (Swift/Alamofire).
Как выбрать подход для загрузки файлов?
| Метод | Размер файла | Устойчивость к обрывам | Производительность |
|---|---|---|---|
| Multipart | до 100 МБ | Нет | Высокая (один поток) |
| Presigned URL | любой | Частично (перезагрузка) | Средняя (зависит от сервера) |
| Chunked upload | >100 МБ | Да (докачка чанками по 512 КБ) | Высокая (параллельные чанки) |
Retrofit с Multipart лучше стандартного HttpURLConnection в 10 раз по производительности на больших файлах за счёт пула соединений и буферизации. Повторные попытки при сбоях — до 3 с экспоненциальной задержкой (1, 2, 4 секунды).
Что выбрать при ограничениях бэкенда?
| Бэкенд-архитектура | Рекомендуемый подход | Комментарий |
|---|---|---|
| S3-совместимое хранилище | Presigned URL | Минимальная нагрузка на сервер, прямая загрузка в S3 |
| REST API с multipart | Multipart/form-data | Стандарт для большинства бэкендов, легко отлаживать |
| Нестабильная сеть | Chunked upload с resumable | Докачка с последнего байта экономит трафик |
Почему важен прогресс-бар?
По статистике, 80% пользователей ожидают прогресс-бар при загрузке файлов. Его отсутствие снижает retention на 15%. Поэтому мы всегда включаем прогресс в стандартный набор. Прогресс-бар с реальными процентами (а не спиннер) повышает доверие и уменьшает количество отмен.
Процесс работы: от задачи до деплоя
- Анализ — определяем типы файлов, их средний размер (например, до 100 МБ), требования к безопасности и скорость интернета у аудитории.
- Выбор подхода — multipart, presigned URL или chunked upload с resumable-поведением.
- Реализация — пишем код пикера, обработку разрешений, интеграцию с бэкендом, прогресс и повторы (до 3 попыток с задержкой 1, 2, 4 секунды).
- Тестирование — на реальных устройствах с разными версиями ОС и с плохим сигналом. Симулируем обрывы сети. Добиваемся 95% успешных загрузок при нестабильном соединении.
- Деплой — публикуем в App Store и Google Play, настраиваем мониторинг ошибок через Crashlytics.
Что входит в работу
- Разработка модуля выбора файлов с корректной обработкой разрешений под Android и iOS.
- Интеграция с бэкендом: multipart, presigned URL или chunked upload по вашему API.
- Прогресс-бар с отображением процентов и возможностью отмены.
- Автоматические повторные попытки при сбоях сети (до 3 попыток с экспоненциальной задержкой 1, 2, 4 секунды).
- Тестирование на реальных устройствах с разными версиями ОС и сценариями плохой связи.
- Подготовка документации по интеграции и код с комментариями.
- Поддержка в течение 2 недель после сдачи: бесплатные правки по замечаниям.
Сроки и стоимость
Срок реализации — от 1 до 4 дней в зависимости от сложности (стандартный multipart — 1–2 дня, chunked с докачкой — до 4 дней). Стоимость рассчитывается индивидуально после аудита вашего проекта. Бюджет на такую задачу обычно составляет от $1500 до $5000 в зависимости от сложности. Наши клиенты экономят до $2000 в год на поддержке благодаря продуманной архитектуре. Получите консультацию — мы бесплатно оценим объём работ.
Почему стоит доверить эту задачу нам?
Мы — команда мобильных разработчиков с сертификатами Apple и Google, 5+ лет опыта и более 50 успешных проектов. Гарантируем соблюдение гайдлайнов App Store и Google Play: ваш билд не отклонят из-за разрешений или некорректной загрузки. Предоставляем гарантию на код и поддержку после сдачи — бесплатные правки в течение 2 недель. Экономия на поддержке — до 50% за счёт продуманной архитектуры.
Свяжитесь с нами, чтобы обсудить ваш проект — мы поможем подобрать оптимальное решение. Закажите разработку модуля загрузки файлов, и мы гарантируем, что ваше приложение пройдёт ревью без замечаний.
Реализация загрузки файлов требует внимания к деталям: от правильной обработки разрешений до выбора подходящего протокола. Наш опыт позволяет избежать типичных ошибок и сдать релиз без замечаний. Получите консультацию — начнём с анализа вашего проекта.







