Реализация отправки файлов в чате мобильного приложения
Мы сталкивались с десятками проектов, где отправка файлов в чате превращается в головную боль: утечка security scope на iOS, пустые файлы из iCloud, content:// URI на Android, которые не передать в сеть. Задача не сводится к кнопке «прикрепить файл»: нужно правильно обработать file picker на обеих платформах, корректно отобразить тип файла, организовать загрузку и безопасное скачивание на устройство получателя. Рассказываем, как это делаем мы.
Как мы выбираем файл: подводные камни платформ
На iOS системный UIDocumentPickerViewController возвращает URL с security-scoped bookmark. Доступ к файлу открывается через startAccessingSecurityScopedResource() и обязательно закрывается через stopAccessingSecurityScopedResource() после копирования во временную директорию. Если забыть второй вызов – утечка security scope, и при следующем запуске приложения доступ к файлу будет заблокирован системой. Мы гарантируем, что в нашем коде эти вызовы всегда парные.
Файлы из iCloud Drive приходят не сразу: NSMetadataQuery показывает статус загрузки. Если файл не скачан на устройство – нужно дождаться завершения NSMetadataUbiquitousItemIsDownloadingKey перед копированием. Без этого получим пустой файл размером 0 байт в upload-очереди.
На Android – Intent(Intent.ACTION_OPEN_DOCUMENT) с addCategory(Intent.CATEGORY_OPENABLE). Uri из content provider нельзя напрямую передавать в сетевые запросы – нужно скопировать содержимое через contentResolver.openInputStream() в кэш-директорию приложения. Файлы из Google Drive и других провайдеров не имеют реального пути в файловой системе, только content:// URI.
| Параметр | iOS | Android |
|---|---|---|
| Механизм доступа | security-scoped bookmark + временное копирование | contentResolver + кэш-директория |
| Управление ресурсами | Явное открытие/закрытие | Закрытие InputStream в finally |
| Работа с облачными файлами | Ожидание загрузки iCloud | Автоматическое копирование провайдером |
| Риски | Утечка scope → потеря доступа | Неправильный URI → сбой сети |
MIME-тип и иконки: почему проверка magic bytes лучше расширения
Определяем MIME по расширению через UTType (iOS 14+) или MimeTypeMap (Android). На сервере – дополнительно проверяем через magic bytes (первые байты файла). PDF начинается с %PDF, ZIP – с PK\x03\x04. Это защищает от переименованных исполняемых файлов. Сравнение: проверка по расширению занимает 1 мс, но mortal; magic bytes – 10 мс, но детектит 99.9% подделок.
В чате показываем иконку по категории: документ, таблица, архив, аудио, прочее. Не пытаться рендерить превью для каждого типа – только для PDF (через PDFKit на iOS или PdfRenderer на Android) и офисных форматов через QuickLook / ACTION_VIEW с системным приложением.
Загрузка и скачивание: background session и WorkManager
Upload – те же принципы, что для видео: чанкование для файлов > 5 МБ, background session на iOS, WorkManager на Android. Прогресс в байтах, не процентах – пользователь понимает 1.2 МБ из 8.4 МБ лучше, чем 14%. На iOS background session позволяет загрузке продолжаться даже после закрытия приложения – пользователь получит уведомление о завершении.
Скачивание на устройство получателя – отдельная история. На iOS файл сохраняем в FileManager.default.urls(for: .documentDirectory) и предлагаем через UIActivityViewController открыть в другом приложении. Прямое сохранение в «Файлы» – через UIDocumentPickerViewController в режиме экспорта.
На Android – DownloadManager системный: он корректно обрабатывает фоновую загрузку, показывает прогресс в шторке уведомлений и сохраняет в Downloads. Прямой путь через FileOutputStream в getExternalFilesDir() – только для внутреннего кэша приложения, не видного пользователю в файловом менеджере.
Безопасность: белый список и presigned URL
Белый список MIME-типов на сервере – обязательно. Исполняемые файлы (.exe, .apk, .ipa, .sh) блокируем или проверяем через антивирусный скан (ClamAV, VirusTotal API). Максимальный размер файла – лимит на уровне API gateway, не только на клиенте. Опыт показывает, что ограничение на клиенте легко обходится.
Ссылки на скачивание – presigned URL с TTL. Прямые ссылки на S3 без подписи означают публичный доступ к приватным чатам. Наши инженеры настраивают TTL так, чтобы ссылка работала 10–15 минут – достаточно для скачивания, но не для распространения.
Как мы подходим к реализации?
- Анализируем вашу аудиторию и типы файлов, которые будут передаваться.
- Проектируем архитектуру: выбираем механизм загрузки (чанки/весь файл), определяем лимиты.
- Реализуем file picker с учётом особенностей платформы.
- Настраиваем background upload и возобновление прерванных загрузок.
- Подключаем проверку MIME на сервере и генерацию presigned URL.
- Тестируем на реальных файлах: от 1 КБ до 2 ГБ.
Что входит в работу?
- Исходный код модуля отправки/скачивания файлов.
- Документация по API и интеграции.
- Доступ к репозиторию с примерами.
- Поддержка в течение 30 дней после сдачи.
Сроки ориентировочно
Базовая реализация (file picker, upload с прогрессом, отображение в чате, скачивание) – 2–3 дня. Поддержка background upload + возобновление + белый список типов – ещё 1 день. Стоимость рассчитывается индивидуально.
Оцените свой проект – свяжитесь с нами. Опыт 5+ лет и более 30 успешных проектов с чатами гарантируют, что отправка файлов будет работать стабильно и безопасно. Получите консультацию уже сегодня.







