Как загрузить файл или фото на сервер из Android‑приложения
Короткий ответ: используйте POST с Content-Type: multipart/form-data (Retrofit + OkHttp) — подготовьте файл (или InputStream → временный файл), создайте MultipartBody.Part и RequestBody для дополнительных полей, отправляйте в фоне, показывайте прогресс, проверяйте ошибки сети и используйте HTTPS.
Что выбрать и какие договорённости нужны с backend
Прежде чем писать код, согласуйте с backend:
- URL и метод (например, POST /api/upload).
- Имя поля для файла (file, image и т. п.).
- Требуемые доп. поля (user_id, token, description).
- Максимальный размер и допустимые MIME‑типы.
- Формат успешного ответа (JSON: url, id, size).
Если контролируете сервер — предпочтительнее отдавать клиенту endpoint с multipart/form-data. Для больших файлов лучше использовать pre-signed URL (S3/GCS) и загружать напрямую в хранилище.
Практическая реализация (Kotlin, Retrofit + OkHttp)
- Разрешения и получение файла
- Для выбора файла используйте ACTION_OPEN_DOCUMENT (SAF) — не требует READ_EXTERNAL_STORAGE на новых Android.
- Для камеры — ACTION_IMAGE_CAPTURE + FileProvider, не забудьте runtime‑разрешение CAMERA при необходимости.
- По Uri открывайте contentResolver.openInputStream(uri) и копируйте в временный файл в context.cacheDir.
- Подготовка Multipart
- Получив File или временный файл: val requestFile = file.asRequestBody(mimeType.toMediaType()) val part = MultipartBody.Part.createFormData("file", file.name, requestFile) val desc = "Описание".toRequestBody("text/plain".toMediaType())
-
Retrofit API interface UploadApi { @Multipart @POST("upload") suspend fun uploadFile( @Part file: MultipartBody.Part, @Part("description") description: RequestBody ): Response
} -
Отправка и обработка ответа
- Выполняйте вызов в корутине (IO Dispatcher) или через WorkManager для фоновой загрузки.
- Проверяйте response.isSuccessful и разбирайте body() или errorBody() для сообщений об ошибке.
- Настройте таймауты в OkHttpClient (connect/read/write) для больших файлов.
Как показывать прогресс загрузки
Создайте обёртку RequestBody, которая в writeTo(...) считает отправленные байты и через callback обновляет UI (через Main thread):
- Не обновляйте UI прямо из writeTo — используйте Handler или сompletion callback, который переключается в основной поток.
- Для множества файлов реализуйте очередь и атомарные статусы (загружается, успешно, ошибка).
Храните большие временные файлы в context.cacheDir и очищайте их после успешной загрузки.
Обработка ошибок и устойчивость
Частые ситуации:
- Нет сети: показывайте понятное сообщение и кнопку "Повторить".
- Таймаут: предложите повторную попытку с экспоненциальной задержкой или по кнопке.
- 4xx: проверьте авторизацию/поля — покажите текст ошибки от сервера.
- 5xx: серверная проблема — предложите повтор позже. Технически: разделяйте сетевые ошибки и ошибки API, логируйте (interceptor) и не блокируйте UI.
Безопасность и валидация
- Всегда используйте HTTPS.
- Не отправляйте лишних метаданных (пути, локальные идентификаторы).
- Храните токены безопасно (EncryptedSharedPreferences/Keystore).
- На сервере проверяйте MIME по сигнатуре, ограничивайте размер и форматы, не полагайтесь на клиентскую проверку.
Частые ошибки
- Отправка больших изображений без ресайза → таймауты и высокий расход трафика.
- Неправильное имя поля multipart → 400/422 от сервера.
- Попытка читать Uri напрямую как File на Android 10+ — используйте InputStream/SAF.
- Обновление UI из фонового потока внутри RequestBody.writeTo.
FAQ
- Нужно ли копировать Uri в File? Часто да: многие библиотеки удобнее работают с File, а также чтобы определить размер и имя. Для больших файлов лучше стримить без полного чтения в память.
- Можно ли отправить файл в JSON (Base64)? Можно, но плохо: размер растёт ~33%, нагрузка на CPU/память; годится только для очень маленьких файлов.
- Как загрузить в фоне при уходе из приложения? Используйте WorkManager (особенно если нужно гарантировать доставку при рестарте устройства).
Если укажете стек (Kotlin/Java, Retrofit/OkHttp или чистый OkHttp) и точный контракт API — пришлю минимальный рабочий пример кода под вашу конфигурацию.