Почему файлы, сохраненные на Android из мобильной платформы 1С, не видны на компьютере по USB, и как это исправить?

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

Разработчики мобильных приложений на платформе 1С часто сталкиваются с неприятной особенностью: мобильное приложение успешно генерирует файл (например, выгрузку данных в формате XML), во встроенном диспетчере файлов Android этот файл прекрасно виден и открывается, но стоит подключить устройство к компьютеру через USB-кабель — и целевая папка на ПК оказывается пустой. При этом, если вручную скопировать файл внутри мобильного устройства через любой файловый менеджер, копия мгновенно отображается на компьютере. Создается ложное ощущение, что у созданного файла некорректно настроены права доступа.

В этой статье мы подробно разберем природу этого поведения, которая кроется в особенностях работы операционной системы Android, и рассмотрим практические способы решения этой проблемы для разработчиков 1С.

В чем причина? Разбираемся в архитектуре Android и MTP

Для начала проанализируем, как современный компьютер взаимодействует с памятью смартфона. В старых версиях Android (до версии 4.0) при подключении к ПК память устройства монтировалась как обычная флешка (режим Mass Storage). Компьютер получал прямой низкоуровневый доступ к файловой системе. Минус этого подхода заключался в том, что в момент подключения память была заблокирована для самого телефона.

В современных устройствах используется протокол MTP (Media Transfer Protocol). Компьютер больше не работает с файловой системой напрямую. Вместо этого он отправляет запросы операционной системе Android, которая обращается к специальной базе данных индексатора — MediaStorage. ПК «видит» только то, что зарегистрировано в этой базе данных.

Когда мы программно создаем файл из мобильной платформы 1С, происходят следующие процессы:

  1. Файл физически записывается на накопитель устройства.
  2. Внутренний файловый менеджер Android обращается к диску напрямую, поэтому сразу видит новый файл.
  3. Служба индексирования Android (MediaScanner) еще не знает о существовании нового файла. Она работает по расписанию, при перезагрузке устройства или при определенных системных триггерах.
  4. Поскольку в базе данных MediaStore записи о файле нет, протокол MTP сообщает компьютеру, что папка пуста.

Таким образом, наша задача как разработчиков — заставить операционную систему Android принудительно проиндексировать только что созданный файл, чтобы он немедленно стал доступен по USB.

Решение 1. Обходной путь через перезапись файла (быстрый «костыль»)

Автор темы на форуме опытным путем обнаружил интересную закономерность: если заменять (перезаписывать) уже существующий файл, с которым ранее все было в порядке, то изменения сразу видны на ПК.

Выясним, почему это работает. Если файл с определенным именем уже был однажды проиндексирован системой MediaScanner, запись о нем присутствует в базе данных MediaStore. При перезаписи этого файла (даже если у него меняется размер и содержимое) операционная система не создает новую запись, а лишь обновляет существующую. Соответственно, компьютер через протокол MTP мгновенно видит обновленный файл.

Как реализовать этот метод в коде 1С:

Мы можем один раз вручную или программно создать «файл-пустышку» в целевой директории, дождаться его индексации (например, перезагрузив устройство), а затем в регулярных процессах обмена просто перезаписывать его содержимое.


// Пример перезаписи существующего XML-файла в мобильной 1С
ПутьКФайлу = ОбщегоНазначенияКлиентСервер.ПолучитьИмяФайлаВоВременномКаталоге("export.xml");
НовыйФайл = Новый Файл(ПутьКФайлу);

// Если файл уже создан ранее, мы просто открываем его на запись без изменения пути
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, ПараметрыЗаписи);

ЗаписьXML.ЗаписатьОбъявление();
ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеМобильногоПриложения");
// ... запись основного тела документа ...
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();

Этот метод хорош своей простотой и отсутствием необходимости писать дополнительный низкоуровневый код. Однако он не подходит для систем, где имя файла должно быть динамическим (например, содержать дату и время выгрузки или уникальный GUID).

Решение 2. Использование внешних компонент (Native API)

Для полноценного и надежного решения проблемы необходимо использовать возможности операционной системы Android по «проталкиванию» файлов в медиа-базу. Самым правильным способом является вызов метода MediaScannerConnection.scanFile().

Поскольку в мобильной платформе 1С нет прямого доступа к Java-классам Android, мы можем наладить эту связь с помощью создания Внешней Компоненты (ВК) для мобильной платформы. Компонента пишется на языке Java (или C++) и компилируется в виде библиотеки.

Рассмотрим по шагам, какой Java-код должен выполняться внутри компоненты для принудительного сканирования созданного файла:


// Java-код для интеграции во внешнюю компоненту
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.content.Context;

public void scanNewFile(Context context, String filePath) {
    MediaScannerConnection.scanFile(
        context,
        new String[] { filePath },
        null,
        new MediaScannerConnection.OnScanCompletedListener() {
            @Override
            public void onScanCompleted(String path, Uri uri) {
                // Сканирование успешно завершено, файл внесен в базу MediaStore
                // Теперь компьютер гарантированно увидит его по USB
            }
        }
    );
}

После интеграции такой компоненты в мобильное приложение 1С, сразу после закрытия файла (например, метода Записать() или Закрыть() у соответствующих объектов 1С), достаточно вызвать метод компоненты, передав туда полный путь к файлу на устройстве. Система Android мгновенно проиндексирует файл.

Решение 3. Использование вспомогательного Android-приложения

Если разработка собственной внешней компоненты кажется вам слишком трудоемкой, можно воспользоваться альтернативным вариантом, предложенным в обсуждении форума. Мы можем создать простейшее Android-приложение (в формате APK), которое будет выполнять единственную задачу — принимать путь к файлу и отправлять системный Intent сканирования, а затем вызывать его из мобильной 1С.

Для вызова внешнего приложения из мобильной платформы используется метод ЗапуститьПриложение(). Разберем пример реализации вызова:


// Код в мобильном приложении 1С
// Предполагается, что на устройстве установлено наше вспомогательное APK-приложение
ИмяФайлаДляСканирования = "/storage/emulated/0/Download/export_data.xml";

ПараметрыЗапуска = Новый Массив;
ПараметрыЗапуска.Добавить("-d");
ПараметрыЗапуска.Добавить("file://" + ИмяФайлаДляСканирования);

// Запуск сторонней утилиты, умеющей инициировать сканирование медиа-файлов
ЗапуститьПриложение("android.intent.action.MEDIA_SCANNER_SCAN_FILE", ПараметрыЗапуска);

Важное примечание: Начиная с Android 10 (API level 29) и выше, в операционной системе была введена концепция Scoped Storage (изолированное хранилище). Прямой вызов общего сканера через Intent ACTION_MEDIA_SCANNER_SCAN_FILE для произвольных папок может быть ограничен политиками безопасности. Поэтому настоятельно рекомендуется сохранять файлы в стандартные публичные директории.

Решение 4. Выбор правильной директории сохранения

При разработке мобильного приложения важно правильно выбирать пути для сохранения файлов. Если вы сохраняете файлы во внутренний кэш приложения или в глубоко вложенные произвольные папки в корне памяти устройства, служба MediaScanner будет игнорировать их с высокой долей вероятности.

Для файлов, предназначенных для передачи на ПК, старайтесь использовать системные публичные папки:

Операционная система Android настроена таким образом, что сканирование этих папок происходит значительно чаще, а ограничения безопасности Scoped Storage для них более гибкие. Получить пути к этим папкам в мобильной 1С можно с помощью системных функций работы с файловой системой или стандартных путей окружения Android.

Что можно сделать вручную прямо сейчас для проверки?

Если вам нужно срочно скопировать файлы на компьютер во время тестирования разработки, а код еще не доработан, можно воспользоваться одним из административных методов «сброса» кэша индексатора:

  1. Откройте настройки мобильного устройства Android.
  2. Перейдите в раздел «Приложения» и включите отображение системных процессов.
  3. Найдите приложение «Хранилище мультимедиа» (Media Storage).
  4. Очистите кэш и данные этого приложения.
  5. Перезагрузите мобильное устройство.

После перезапуска Android запустит полное сканирование всей файловой системы устройства заново, база MediaStore обновится, и все ранее созданные файлы из мобильной 1С отобразятся на вашем компьютере.

← На главную