Как исправить ошибку FileUriExposedException при отправке вложений в мобильном приложении 1С на Android

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке мобильных приложений на платформе 1С:Предприятие часто возникает задача программной отправки электронных писем с вложениями (например, счетами в формате PDF или отчетами в Excel). Однако, начиная с версии Android 7.0 (API level 24), разработчики сталкиваются с серьезным препятствием: приложение аварийно завершается с ошибкой FileUriExposedException. В этой статье мы подробно разберем, почему это происходит и какими способами можно реализовать корректную отправку файлов на современных версиях Android.

Причина проблемы: Безопасность и смена схем URI

Разберем ситуацию: раньше для передачи файла во внешнее приложение (например, почтовый клиент Gmail) достаточно было сформировать путь по схеме file:// и передать его через механизм Intent. Начиная с Android 7.0, Google ужесточил правила безопасности. Теперь передача «голых» путей к файлам во внутреннем хранилище приложения запрещена, так как принимающее приложение может не иметь прав доступа к этой папке.

Вместо схемы file:// система требует использовать схему content://. Для этого в Android используется специальный механизм — FileProvider. Он выступает посредником, который предоставляет временный доступ к файлу другому приложению. Проанализируем, как эти изменения отражаются на разработке в 1С и какие инструменты у нас есть.

Решение №1: Использование объекта СредстваПочты (Рекомендуемый способ)

Наиболее простым и стабильным способом решения проблемы является использование встроенного объекта 1С СредстваПочты. Платформа 1С в своих современных сборках (начиная с 8.3.12 и выше) берет на себя всю сложную работу по взаимодействию с Android API. Она сама упаковывает путь к файлу в формат content://, инициализирует FileProvider и выставляет необходимые флаги разрешений.

Рассмотрим пример кода, который позволит нам отправить письмо с вложением без необходимости вручную прописывать Intent:


// Создаем объект сообщения
Сообщение = Новый СообщениеПочты;
Сообщение.Тема = "Тема вашего письма";
Сообщение.Текст = "Текст сообщения здесь";
Сообщение.Получатели.Добавить("example@mail.com");

// Указываем путь к нашему PDF-файлу
ПутьКФайлу = DocumentsDir() + "/Invoice.pdf";
Вложение = Сообщение.Вложения.Добавить(ПутьКФайлу);
Вложение.Наименование = "Invoice.pdf";

// Вызываем системный диалог отправки
СредстваПочты.Послать(Сообщение, СпособОтправкиПочты.ИспользоватьПочтовыйКлиент);

Важный момент: Для того чтобы этот метод работал корректно, убедитесь, что вы используете актуальную версию сборщика мобильных приложений. Платформа должна автоматически прописать в манифест AndroidManifest.xml необходимые разрешения и описание провайдера файлов.

Решение №2: Использование функции ПоказатьПлатформенныйРесурсОбмена

Если ваша задача не ограничивается только почтой, а вы хотите дать пользователю выбор (отправить через почту, Telegram, WhatsApp или сохранить на диск), наиболее современным подходом будет использование объекта ПоказатьПлатформенныйРесурсОбмена. Это аналог системной кнопки «Поделиться» (Sharing).

Разберем, как это работает:

  1. Мы подготавливаем файл во временном хранилище или в доступной директории.
  2. Вызываем метод обмена ресурсом.
  3. Система сама генерирует безопасную ссылку content://.

Пример реализации:


ПутьКФайлу = DocumentsDir() + "/Report.pdf";
ФайлОбмена = Новый Файл(ПутьКФайлу);

Если ФайлОбмена.Существует() Тогда
    ОписаниеРесурса = Новый ОписаниеПередаваемогоФайла(ПутьКФайлу);
    МассивРесурсов = Новый Массив;
    МассивРесурсов.Добавить(ОписаниеРесурса);
    
    СредстваМультимедиа.ПоказатьПлатформенныйРесурсОбмена(МассивРесурсов);
КонецЕсли;

Этот метод считается самым «правильным» с точки зрения гайдлайнов Android, так как он минимизирует риски блокировок со стороны системы безопасности и не требует от разработчика 1С знаний о внутреннем устройстве URI провайдеров.

Решение №3: Ручное формирование Intent через MobileDeviceApplicationRun

В некоторых случаях (например, если нужно использовать специфические параметры стороннего приложения) разработчики пытаются использовать MobileDeviceApplicationRun (ЗапускПриложенияМобильногоУстройства). Как мы выяснили из обсуждения, именно здесь возникает FileUriExposedException при использовании file://.

Если вы все же решили идти по этому пути, вам необходимо знать, что в мобильной платформе 1С уже встроен стандартный FileProvider. Чтобы сформировать URI вручную, вам нужно знать идентификатор пакета вашего приложения (Package ID). Обычно путь к файлу через провайдер выглядит так:

content://[ИдентификаторПакета].fileprovider/external_storage_root/[ПутьКФайлу]

Однако, проанализируем ситуацию: ручное формирование таких ссылок крайне затруднительно, так как структура XML-описания путей внутри платформы может меняться от версии к версии. Если вы используете старый код, как в сообщении автора темы:


MDARun = New MobileDeviceApplicationRun;
MDARun.Action = "android.intent.action.SEND";
MDARun.AdditionalData.Add("android.intent.extra.STREAM", "file://" + FilePath, "Uri");

То на Android 7+ он гарантированно не будет работать. Единственный вариант заставить работать MobileDeviceApplicationRun с файлами — это использовать метод ЗапуститьПриложение (LaunchApplication) в новых версиях платформы, передавая туда объект типа Файл. В этом случае 1С сама попытается выполнить преобразование схемы.

Рекомендации по работе с разрешениями и MIME-типами

При работе с внешними приложениями на Android крайне важно учитывать два фактора:

  1. Разрешения (Permissions): Начиная с Android 6.0, недостаточно просто прописать разрешения в манифесте. Для доступа к внешним папкам (например, Downloads) нужно запрашивать разрешение в явном виде у пользователя в момент выполнения операции. В 1С это делается через метод СредстваМультимедиа.ЗапроситьРазрешение(). Однако, если вы пишете файлы в DocumentsDir() (внутренняя папка приложения), дополнительные разрешения обычно не требуются, но доступ к ним через file:// извне закрыт.
  2. MIME-типы: При передаче вложения почтовому клиенту обязательно указывайте тип контента. Для PDF-документов это application/pdf. Если передать универсальный application/octet-stream, некоторые клиенты (например, Outlook) могут не распознать файл или отобразить его как поврежденный.

Итоги

Подведем итог нашему разбору. Если вы столкнулись с ошибкой FileUriExposedException в мобильном приложении 1С:

Следуя этим правилам, вы обеспечите стабильную работу вашего мобильного приложения на всех версиях Android, начиная от старых пятых версий и заканчивая современными Android 13/14.

← На главную