Не удается открыть почтовый клиент с вложением (проблема с intent, схемами file и content)

1. bytecoded 26 02.08.18 10:11 Сейчас в теме
Команда мобильного приложения для Android должна выполнить два действия:

1. Записать PDF-документ в произвольное место.
2. Открыть форму мобильного клиента с определенным текстом, темой и (главное) с вложенным файлом, записанным в предыдущем пункте.

Я действовал следующим образом: получал директорию для записи через DocumentsDir() и записывал файл в неё, после чего вызывал следующий код:

		
		MDARun = New MobileDeviceApplicationRun();
		
		MDARun.Action = "android.intent.action.SEND";
		                                     
		MDARun.AdditionalData.Add("android.intent.extra.STREAM",	"file://" + FilePath, "Uri");
		MDARun.AdditionalData.Add("android.intent.extra.SUBJECT",	Subject);
		MDARun.AdditionalData.Add("android.intent.extra.TEXT",		Text);
				
		MDARun.Run(False);
Показать


FilePath здесь — это путь к файлу, образованный из ответа DocumentsDir() и имени файла.

Код хорошо работает до 6-го android'а включительно, но начиная с 7-го его вызов приводит к аварийному завершению приложения с ошибкой FileUriExposedException. Насколько я понял, причина в том, что с 7-й версии разработчики больше не допускают использования схемы обращения file:// в intent'ах — необходимо использовать content://. Между тем, DocumentsDir() возвращает только путь по схеме file://.

Вопрос: как можно решить эту проблему?

Я пытался получить ссылку по схеме content:// для файла, записанного в директорию приложения, но не понял, как это можно сделать — не нашел подходящих intent'ов или встроенного в 1С метода. Примеры в поиске в основном предлагают создавать свой экземпляр класса FileProvider, что видится мне невозможным изнутри 1С.

Также пытался писать файл в директории, которые возвращает метод КаталогБиблиотекиМобильногоУстройства() — этот метод возвращает ссылки по схеме content://, но в предлагаемые им директории записать файл, по-видимому, нельзя.
Найденные решения
9. bytecoded 26 07.08.18 15:17 Сейчас в теме
На случай, если кто-то будет искать решение проблемы: следует использовать объект СредстваПочты и проверить актуальность версии платформы (собрал на 8.3.12.67).
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. kuld 248 02.08.18 10:36 Сейчас в теме
(1) В Android, что бы отправить вложенный файл, нужно записать его в общие папки, ну что бы и приложение и почтовый клиент имели к нему доступ. А что бы туда писать, нужно получить разрешение. На старых версиях API достаточно было прописать в манифесте разрешение WRITE_EXTERNAL_STORAGE. Но начиная с Android 6 нужно в явном виде запрашивать разрешение на подобные действия у пользователя.
Подробней см. тут https://developer.android.com/distribute/best-practices/develop/runtime-permissions?hl=ru

И да, в намерение нужно передавать не путь к файлу, а uri. До версии API 24 uri можно было получить просто вызвав Uri.parse(filePath), а в новых следует это делать через FileProvider, см. тут https://developer.android.com/reference/android/support/v4/content/FileProvider

Всё вышенаписанное про Android )) как оно там в 1С реализовано - не знаю :)
3. bytecoded 26 02.08.18 10:58 Сейчас в теме
(2) Да, разрешение на запись запрашивается сразу при запуске — с этим, видимо, проблем нет.

Проблема именно с получением URI внутри 1C — если я верно понял, все что я могу сделать — это объявить намерение, а через намерения URI по пути к файлу не получить.
4. kuld 248 02.08.18 11:41 Сейчас в теме
(3)
а через намерения URI по пути к файлу не получить
в намерение как раз нужно запихнуть uri.
На джаве это выглядит так
intent.putExtra(Intent.EXTRA_STREAM, uri)

Если в эту extra запихнуть путь к файлу (file://) вместо uri (content://) ошибки не будет, но и файл не прицепится, параметр просто будет проигнорирован.

uri получается или по старинке, через класс Uri, но в версиях Nougat и старше это вызывает ошибку. Там следует пользоваться классом FileProvider, предварительно объявив о своих намерениях в манифесте.

И еще такой момент, намерению желательно сделать setType("application/octet-stream"). Без него у меня родной почтовый клиент от производителя железяки не хотел прикреплять файл.
5. bytecoded 26 03.08.18 14:53 Сейчас в теме
Блин, даже ЗапуститьПриложение() не срабатывает :) Неужели никто не решал?

(4), а если пересобрать приложения с более старым SDK — доступ по старой схеме (через file://) в намерениях будет работать? Или это ограничение накладывается независимо от использованного SDK.
6. kuld 248 03.08.18 16:24 Сейчас в теме
(5) Решал, но не на 1С )) Вот тут у меня без проблем собирается csv файл, сохраняется в общий Downloads и отправляется через любую службу, поддерживающую отправку файлов.
Через file:// не будет работать вообще никак, ни на каком SDK. В это намерение всегда нужно было передавать uri, т.е. content://
Если только 1С на уровне платформы сама это парсила, то могло проканать.
7. bytecoded 26 04.08.18 05:21 Сейчас в теме
(6), ясно. Я верно понимаю, что URI той же папки Downloads, например, будет отличаться от устройства к устройству и заранее его спрогнозировать без обращения к классам Java невозможно?
8. kuld 248 04.08.18 10:53 Сейчас в теме
(7) Верно. Парсить самостоятельно - плохая практика.
9. bytecoded 26 07.08.18 15:17 Сейчас в теме
На случай, если кто-то будет искать решение проблемы: следует использовать объект СредстваПочты и проверить актуальность версии платформы (собрал на 8.3.12.67).
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот