Почему журнал звонков в мобильном приложении 1С оказывается пустым?

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

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

Анализ исходной проблемы: почему не срабатывает отбор?

Рассмотрим ситуацию, с которой столкнулся автор темы. В коде используется стандартный механизм получения журнала звонков с применением ОтборКомпоновкиДанных. Автор устанавливает фильтр по дате, отнимая 3 секунды от текущего времени, чтобы захватить последний совершенный звонок. Однако цикл по результату поиска не выполняется.

Основная причина, как выяснилось в ходе обсуждения, заключается в том, что мобильная платформа 1С возвращает дату и время звонка в формате UTC (Universal Coordinated Time — время по Гринвичу), в то время как функция ТекущаяДата() на устройстве возвращает локальное время пользователя. Если ваш часовой пояс отличается от UTC (например, МСК — UTC+3), то отбор БольшеИлиРавно по локальному времени просто «отсечет» все записи, так как в базе данных журнала они числятся на несколько часов «в прошлом».

Решение №1: Использование универсального времени (UTC)

Для того чтобы отбор работал корректно в любом часовом поясе, нам необходимо привести текущую дату устройства к универсальному формату. Разберем, как изменить исходный код для правильной работы.

Вместо использования прямой даты, мы применим функцию УниверсальноеВремя(). Рассмотрим исправленный пример кода:


// Получаем текущую локальную дату
ТекущаяЛокальнаяДата = ТекущаяДата();

// Преобразуем ее в UTC, чтобы соответствовать формату хранения в журнале звонков
ДатаОтбораUTC = УниверсальноеВремя(ТекущаяЛокальнаяДата) - 3;

Отбор = Новый ОтборКомпоновкиДанных;
ЭлементОтбора = Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Дата");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
ЭлементОтбора.ПравоеЗначение = ДатаОтбораUTC;
ЭлементОтбора.Использование = Истина;

ЖурналЗвонков = СредстваТелефонии.ПолучитьЖурналЗвонков();
СписокЗаписей = ЖурналЗвонков.НайтиЗаписи(Отбор);

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

Решение №2: Проверка разрешений и прав доступа

Даже если код написан идеально, операционная система Android может заблокировать доступ к конфиденциальным данным, таким как журнал вызовов. Одной проверки ПоддерживаетсяЖурналЗвонков() недостаточно.

Начиная с Android 6.0, приложения должны запрашивать разрешения в режиме реального времени (runtime permissions). Разберем шаги, которые необходимо выполнить:

  1. Настройка сборщика: Убедитесь, что при сборке мобильного приложения в конфигураторе (или в файле манифеста) отмечено разрешение READ_CALL_LOG.
  2. Программный запрос: В коде перед обращением к журналу следует вызвать метод запроса прав.

Проанализируем пример безопасного получения данных:


Если СредстваТелефонии.ПоддерживаетсяЖурналЗвонков() Тогда
    // Запрашиваем доступ у пользователя, если он еще не предоставлен
    СредстваТелефонии.ЗапроситьРазрешениеНаИспользованиеЖурналаЗвонков();
    
    // Только после этого пытаемся получить данные
    Журнал = СредстваТелефонии.ПолучитьЖурналЗвонков();
Иначе
    Сообщить("Данное устройство не поддерживает чтение журнала звонков.");
КонецЕсли;

Помните, что в Android 10 и выше политика безопасности стала еще строже. Если ваше приложение не является основным обработчиком звонков, Google может ограничивать доступ к номерам телефонов (вместо номера может прийти пустая строка).

Решение №3: Учет задержки записи в системный журнал

Существует технический нюанс, называемый «состоянием гонки» (race condition). Когда звонок завершается, операционной системе Android требуется время (от 500 мс до 2 секунд), чтобы фактически записать данные в системную базу CallLog. Если ваше мобильное приложение просыпается по событию завершения звонка и тут же обращается к журналу, запись может еще не существовать.

Рассмотрим стратегию обхода этой проблемы:

Решение №4: Альтернатива фильтрации через компоновку

Иногда объекты ОтборКомпоновкиДанных в мобильной платформе могут вести себя нестабильно или не учитывать тонкие нюансы типов данных. Если отбор по дате все равно не срабатывает, мы рекомендуем использовать «ручной» перебор массива.

Выясним, как это реализовать эффективно:


// Получаем весь журнал (или за очень большой период)
ЖурналЗвонков = СредстваТелефонии.ПолучитьЖурналЗвонков();
// Получаем все записи без жесткого отбора компоновки
ВсеЗаписи = ЖурналЗвонков.НайтиЗаписи(); 

НужнаяДата = УниверсальноеВремя(ТекущаяДата()) - 60; // Ищем за последнюю минуту

Для Каждого Запись Из ВсеЗаписи Цикл
    Если Запись.Дата >= НужнаяДата Тогда
        // Обрабатываем найденный звонок
        ОбменСЦентральнойБазой.ЗаписатьЛог("Найден звонок: " + Запись.НомерТелефона);
    КонецЕсли;
КонецЦикла;

Такой подход исключает ошибки в работе движка компоновки данных на специфических прошивках Android.

Ограничения платформы iOS

Важно помнить, что если вы разрабатываете приложение под iPhone (iOS), то доступ к системному журналу звонков невозможен в принципе. Политика безопасности Apple запрещает сторонним приложениям читать историю вызовов. Метод ПоддерживаетсяЖурналЗвонков() на устройствах Apple всегда будет возвращать Ложь. Для таких случаев необходимо реализовывать собственный журнал внутри приложения, фиксируя только те звонки, которые были инициированы непосредственно из интерфейса 1С.

Итоги и рекомендации

Подводя итог, при работе с телефонией в мобильной 1С следует придерживаться следующих правил:

  1. Всегда используйте UTC: Сравнивайте даты только через УниверсальноеВремя().
  2. Проверяйте разрешения: Не забывайте про ЗапроситьРазрешениеНаИспользованиеЖурналаЗвонков().
  3. Делайте задержку: Дайте операционной системе время зафиксировать звонок в базе.
  4. Используйте логирование: В мобильном приложении сложнее использовать отладчик, поэтому записывайте каждый шаг (количество найденных записей, текущую дату и дату из журнала) в текстовый файл или специальный регистр сведений.

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

← На главную