Глобальный контекст.ПоддерживаетсяФункциональностьМобильногоПриложения

Методы · MobileApplicationFunctionalitySupported

Проверяет, была ли включена запрошенная функциональность в мобильном приложении или мобильном клиенте во время сборки. В мобильном клиенте также сопоставляет с информацией на сервере. Если на сервере данная функциональность выключена, то и на клиенте метод вернет значение Ложь.

Синтаксис

ПоддерживаетсяФункциональностьМобильногоПриложения(<ЗапрашиваемаяФункциональностьМобильногоПриложения>)
Полное описание, параметры и ограничения

Глобальный контекст.ПоддерживаетсяФункциональностьМобильногоПриложения (Global context.MobileApplicationFunctionalitySupported)

Глобальный контекст (Global context)

ПоддерживаетсяФункциональностьМобильногоПриложения (MobileApplicationFunctionalitySupported)

Доступен, начиная с версии 8.3.18.

Синтаксис:
ПоддерживаетсяФункциональностьМобильногоПриложения(<ЗапрашиваемаяФункциональностьМобильногоПриложения>)
Параметры:

<ЗапрашиваемаяФункциональностьМобильногоПриложения> (обязательный)
Тип: ФункциональностьМобильногоПриложения.
Функциональность мобильного приложения, поддержка которой проверяется.
Возвращаемое значение:
Тип: Булево.
И на клиенте, и на сервере возвращает одно и то же (и при разных конфигурациях) значение, объединяя установки на клиенте и сервере "по И".
Для толстого, тонкого и веб-клиентов всегда возвращает Ложь.
Описание:

Проверяет, была ли включена запрошенная функциональность в мобильном приложении или мобильном клиенте во время сборки.
В мобильном клиенте также сопоставляет с информацией на сервере. Если на сервере данная функциональность выключена, то и на клиенте метод вернет значение Ложь.

Доступность:

Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.

Использование в версии:

Доступен, начиная с версии 8.3.18.

Методическая информация

Практические примеры

Свой локальный Android пакет750: настоящий callback формы и осознанная общая отмена

Передайте две собственные строки через native локальное уведомление, проверьте реальный четырехпараметрический callback своей формы и отдельно изучите широкую отмену отложенного опыта.

Где и как запускать

Своя новая Android ARM64 developer лаборатория/CF. MAIN клиентские процедуры: только МобильноеПриложениеКлиент>=8.3.18; own scalar identity/UTC helpers: только МобильноеПриложениеСервер. Настоящие form command и Description callbacks, без push/SDK/личных данных/реальных операций сейчас.

Подготовка

  1. Это будущий ручной опыт только в новой полностью собственной Android ARM64 developer лаборатории/эмуляторе, с одной новой CF. Не личный телефон, рабочая ИБ, старое приложение или стенд с чужими уведомлениями. Лаборатория должна целиком принадлежать вам: ниже есть общая отмена, не фильтр одного nonce. Техническая приватность/изоляция здесь не обещана; сейчас устройство/1С/ОС не запускались.

  2. Создайте пустую CF УчебныеУведомления85, версия = 3b362d96-3be0-49b5-84b8-9f69770d28fb, совместимость Не использовать. Общие → Общие формы: ровно одна управляемая Уведомления85 в рабочей области начальной страницы. Весь MAIN вставьте в модуль этой формы; событие ПриОткрытии свяжите с реальным ПриОткрытии(Отказ), не вызывайте вручную. Общий модуль/APP строковый handler не нужны.

  3. Реквизиты формы: СогласенНаУведомление85 и СогласенНаОбщуюОтмену85 (Булево, исходно Ложь, два отдельных ручных флажка); ВерсияRuntime85/Состояние85 (Строка); ОтветПолучен85/ПоказаноОС85 (Булево); Сумма85 (Число15,2). Поля наблюдения ТолькоПросмотр=Да. Начальные false/0 не являются результатом callback — отдельно смотрите ОтветПолучен85.

  4. Создайте четыре команды формы: ОтправитьСвойПакет85, ОтключитьСвойОбработчик85, ПодготовитьОбщуюОтмену85, ОтменитьОтложенные85. Для каждой назначьте одноименный настоящий обработчик с параметром Команда; добавьте собственные кнопки с соответствующим ИмяКоманды. ПолученСвойПакет85 — отдельная экспортная процедура с четырьмя параметрами, не действие кнопки и не вручную вызываемый пример.

  5. У своей CF установите назначение Приложение для мобильной платформы. Проверьте конфигурацию для мобильного приложения клиент/сервер, целостность и неподдерживаемые функции: при ошибке STOP. Конфигурация → Мобильное приложение → Публиковать…: только свой новый виртуальный каталог OwnLocalNotification85_<ownGUID> и собственная новая папка своей Windows-VM/IIS. Это публикация конфигурации, не сборка APK; рабочую ИБ не подключайте.

  6. Вручную подготовьте на собственном отдельном Android ARM64 стенде официальную developer mobile platform1cem-arm64.apk из своего фактически полученного дистрибутива, не client/standalone. В пустом списке developer приложений: + → Address = реальный URL своей private VM/IIS с точным именем публикации → Load → свое имя УчебныеУведомления85 → OK/Done → открыть новое приложение. Не localhost телефона/придуманный URL/публичный или рабочий сервер. Только собственная лабораторная загрузка, никаких push-сервисов/FCM/APNs/магазина/внешнего SDK. Здесь ничего не скачивается/устанавливается/публикуется.

  7. Официальные инструкции будущей ручной подготовки: https://1c-dn.com/library/publishing_of_1c_mobile_application/ ; https://1c-dn.com/library/tutorials/1c_enterprise_development_tools_user_guide/ ; https://1c-dn.com/library/tutorials/first_application_mobile_platform/ . Их наличие не подтверждает вашу установку/runtime. Windows8.5.1.1343 не доказывает версию APK: реальная ВерсияRuntime85 должна быть не ниже8.3.18.

  8. ПоддерживаетсяФункциональностьМобильногоПриложения проверяет включенную при сборке функциональность ЛокальныеУведомления, а не OS grant или гарантированную доставку. Ложь/неизвестный тип → STOP до подключения/Add; desktop/mobile-client fallback не предусмотрен. Реальные настройки/разрешения ОС на своем стенде проверяются вами вручную, без обхода ограничений.

  9. Фаза A: прочитайте опыт, отдельно установите СогласенНаУведомление85 и нажмите ОтправитьСвойПакет85. Этот экземпляр потребляет согласие один раз. Создаются nonce и две собственные строки A:2×250=500, B:1×250=250. В JSON сохраняются полная версия, nonce, фаза, строки и итог750. Никакие существующие сообщения/получатели/идентификаторы подписчика не читаются.

  10. ОписаниеОповещения содержит имя экспортной процедуры именно этой формы, native ЭтотОбъект формы и непустой собственный state. Родной ctor и readonly ДополнительныеПараметры явно добавляют state последним аргументом: три native поля уведомления плюс четвертый ownstate. Это не String→APP resolver и не CommonModule.ЭтотОбъект. Состояние ожидания установлено ДО Attach/Add; код после Add не перезаписывает пришедший немедленно callback.

  11. Дождитесь только настоящего callback. Он сначала требует Локальное=Истина и фактический Bool Показано, затем проверяет все поля четвертого параметра/consumed consent, только native Текст/Данные, целый JSON и повторный расчет750. Точный класс первого native объекта не объявлен: нет fake cast; его Заголовок/Дата/Получатели/Наклейка после доставки не читаются, поскольку native обещает заполненными лишь Текст/Данные. ПоказаноОС85 — фактический флаг callback, не чтение текущего центра ОС.

  12. После ОтветПолучен85=Истина и Сумма85=750 нажмите ОтключитьСвойОбработчик85. Native Detach получает сохраненный ТОТ ЖЕ Description явным аргументом. Параметр optional в native, но здесь не опускается: не отключаем неизвестные handlers. Никакая автоматическая отмена/уборка не выполняется.

  13. Фаза B необязательна для ручного запуска: только на полностью собственной НОВОЙ лаборатории без чужих pending уведомлений. Прочитайте широкую область действия и отдельно установите СогласенНаОбщуюОтмену85. ПодготовитьОбщуюОтмену85 потребляет второе согласие и создает новый nonce/отложенный опыт. Настоящий сервер собственной CF возвращает scalar UTC дату, на клиенте к ней прибавляются180 секунд; ИнтервалПовтора=0. Это wall-clock, не точный таймер и не monotonic clock.

  14. Нажмите отдельную ОтменитьОтложенные85 до прихода delayed callback. Native cancel0 отменяет все отложенные локальные уведомления, которые еще не выведены: нет nonce/ID/фильтра. У процедуры нет результата Bool/ID или queue-readback. Наблюдение лишь «запрос общей отмены без синхронного исключения», не «очередь пуста»/«данное уведомление точно отменено». Отсутствие callback не доказательство. В конце отдельной кнопкой отключите свой Description; это также не проверяет очередь.

  15. Если delayed callback пришел раньше общей отмены, его реальные данные/четвертый state проверяются, затем опыт STOP: не переименовывайте уже доставленное уведомление в успешно отмененное. Любая ошибка/unknown/повтор/чужой nonce/changed version дает sticky STOP этого экземпляра без retry, rollback, cancel-cleanup или восстановления prior state. Повтор возможен лишь новой явной ручной подготовкой собственной лаборатории/формы; блокировка не обещана сохраняющейся между экземплярами. Здесь нет доказанного Android GUI/runtime успеха.

&НаКлиенте
Перем Остановка85, Этап85, ВерсияЗапуска85, НомерОпыта85, ВидОпыта85;
&НаКлиенте
Перем СогласиеИспользовано85, СогласиеОтменыИспользовано85, Пакет85, Описание85;

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Если СогласиеИспользовано85 <> Неопределено Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    Остановка85 = Истина;
    СогласиеИспользовано85 = Ложь;
    СогласиеОтменыИспользовано85 = Ложь;
    СогласенНаУведомление85 = Ложь;
    СогласенНаОбщуюОтмену85 = Ложь;
    ОтветПолучен85 = Ложь;
    ПоказаноОС85 = Ложь;
    Сумма85 = 0;
    Попытка
        ВерсияЗапуска85 = ПроверитьСреду85();
        ВерсияRuntime85 = ВерсияЗапуска85;
        Этап85 = "Готов";
        Остановка85 = Ложь;
        Состояние85 = "Прочитайте опыт. Согласие на одно свое уведомление пока не дано";
    Исключение
        Остановить85(ОписаниеОшибки());
        Отказ = Истина;
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура Остановить85(Причина)
    Остановка85 = Истина;
    Этап85 = "STOP";
    СогласенНаУведомление85 = Ложь;
    СогласенНаОбщуюОтмену85 = Ложь;
    Состояние85 = "STOP этого экземпляра. Без повторов и автоматической уборки. " + Причина;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьКоманду85(Команда, Имя, НужныйЭтап)
    Если Остановка85 <> Ложь Или Этап85 <> НужныйЭтап
        Или ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Найти(Имя)
        Или ВерсияЗапуска85 <> ПроверитьСреду85() Тогда
        ВызватьИсключение "Не совпала своя команда, фаза или мобильная среда";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтправитьСвойПакет85(Команда)
    Попытка
        ПроверитьКоманду85(Команда, "ОтправитьСвойПакет85", "Готов");
        Если СогласиеИспользовано85 <> Ложь Или СогласенНаУведомление85 <> Истина Тогда
            ВызватьИсключение "Нужно отдельное согласие на собственный учебный пакет";
        КонецЕсли;
        СогласиеИспользовано85 = Истина;
        СогласенНаУведомление85 = Ложь;
        НачатьСвойОпыт85("СЕЙЧАС", Неопределено);
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ПодготовитьОбщуюОтмену85(Команда)
    Попытка
        ПроверитьКоманду85(Команда, "ПодготовитьОбщуюОтмену85", "ГотовКОтмене");
        Если СогласиеОтменыИспользовано85 <> Ложь Или СогласенНаОбщуюОтмену85 <> Истина Тогда
            ВызватьИсключение "Нужно новое отдельное согласие: отмена всех отложенных уведомлений своей новой лаборатории";
        КонецЕсли;
        СогласиеОтменыИспользовано85 = Истина;
        СогласенНаОбщуюОтмену85 = Ложь;
        UTC = ПолучитьСвоюUTC85();
        Если ТипЗнч(UTC) <> Тип("Дата") Тогда
            ВызватьИсключение "Свой сервер не вернул фактическую UTC дату";
        КонецЕсли;
        НачатьСвойОпыт85("ОТЛОЖЕННО", UTC + 180);
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура НачатьСвойОпыт85(Вид, UTCСрабатывания)
    Если Остановка85 <> Ложь Тогда
        ВызватьИсключение "Остановленный экземпляр не начинает новый опыт";
    КонецЕсли;
    ВидОпыта85 = Вид;
    НомерОпыта85 = Строка(Новый УникальныйИдентификатор);
    Если СтрДлина(НомерОпыта85) <> 36 Или НомерОпыта85 = "00000000-0000-0000-0000-000000000000" Тогда
        ВызватьИсключение "Нет собственного ненулевого номера опыта";
    КонецЕсли;
    Строки = Новый Массив;
    Строки.Добавить(Новый Структура("Item,Qty,Price", "A", 2, 250));
    Строки.Добавить(Новый Структура("Item,Qty,Price", "B", 1, 250));
    Источник = Новый Структура("Version,Nonce,Phase,Rows,Total",
        ВерсияЗапуска85, НомерОпыта85, ВидОпыта85, Строки, 750);
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    ЗаписатьJSON(Запись, Источник);
    Пакет85 = Запись.Закрыть();
    Если ПроверитьПакет85(Пакет85) <> 750 Тогда
        ВызватьИсключение "Свой исходный пакет не дал 750";
    КонецЕсли;
    СвоеСостояние = Новый Структура("Nonce,Phase,Version,SourcePacket,Consent",
        НомерОпыта85, ВидОпыта85, ВерсияЗапуска85, Пакет85, Истина);
    Описание85 = Новый ОписаниеОповещения("ПолученСвойПакет85", ЭтотОбъект, СвоеСостояние);
    ПроверитьОписание85();
    Уведомление = Новый ДоставляемоеУведомление;
    Уведомление.Заголовок = "Учебный пакет 750";
    Уведомление.Текст = "Свой расчет 750. Опыт " + НомерОпыта85;
    Уведомление.Данные = Пакет85;
    Уведомление.ИнтервалПовтора = 0;
    Если ВидОпыта85 = "ОТЛОЖЕННО" Тогда
        Если ТипЗнч(UTCСрабатывания) <> Тип("Дата") Или UTCСрабатывания <= ПолучитьСвоюUTC85() Тогда
            ВызватьИсключение "Нет собственной будущей UTC даты";
        КонецЕсли;
        Если Остановка85 <> Ложь Тогда
            ВызватьИсключение "Не продолжаем после неизвестного исхода во время проверки UTC";
        КонецЕсли;
        Уведомление.ДатаПоявленияУниверсальноеВремя = UTCСрабатывания;
        Этап85 = "ЖдемОтмены";
        Состояние85 = "Создается свой отложенный опыт. Затем нажмите отдельную общую отмену";
    ИначеЕсли ВидОпыта85 = "СЕЙЧАС" И UTCСрабатывания = Неопределено Тогда
        Этап85 = "Ждем";
        Состояние85 = "Ожидается настоящий callback; отсутствие ответа не означает успех";
    Иначе
        ВызватьИсключение "Неизвестный собственный вид опыта";
    КонецЕсли;
    ОтветПолучен85 = Ложь;
    Менеджер = ПолучитьМенеджер85();
    Менеджер.ПодключитьОбработчикУведомлений(Описание85);
    Если Остановка85 <> Ложь Или (Этап85 <> "Ждем" И Этап85 <> "ЖдемОтмены") Тогда
        ВызватьИсключение "Во время подключения возник неизвестный исход";
    КонецЕсли;
    Менеджер.ДобавитьЛокальноеУведомление(Уведомление);
КонецПроцедуры

&НаКлиенте
Процедура ПолученСвойПакет85(Уведомление, Локальное, Показано, СостояниеОпыта85) Экспорт
    Попытка
        Если Остановка85 <> Ложь Или (Этап85 <> "Ждем" И Этап85 <> "ЖдемОтмены")
            Или ВерсияЗапуска85 <> ПроверитьСреду85()
            Или ТипЗнч(Локальное) <> Тип("Булево") Или Локальное <> Истина
            Или ТипЗнч(Показано) <> Тип("Булево") Тогда
            ВызватьИсключение "Не свой локальный callback, фаза или тип native флага; чужие данные не читаются";
        КонецЕсли;
        ПроверитьСостояние85(СостояниеОпыта85);
        Текст = Уведомление.Текст;
        Данные = Уведомление.Данные;
        Если ТипЗнч(Текст) <> Тип("Строка") Или Текст <> "Свой расчет 750. Опыт " + НомерОпыта85
            Или ТипЗнч(Данные) <> Тип("Строка") Или Данные <> СостояниеОпыта85.SourcePacket Тогда
            ВызватьИсключение "Native Text/Data не совпали с целым своим пакетом";
        КонецЕсли;
        Сумма85 = ПроверитьПакет85(Данные);
        ОтветПолучен85 = Истина;
        ПоказаноОС85 = Показано;
        Если ВидОпыта85 <> "СЕЙЧАС" Тогда
            ВызватьИсключение "Отложенный callback уже пришел. Не объявляйте последующую отмену успешной";
        КонецЕсли;
        Этап85 = "Доставлено";
        Состояние85 = "Настоящий свой callback: сумма 750. Флаг ОС показан отдельно. Отключите свой handler отдельной кнопкой";
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ОтменитьОтложенные85(Команда)
    Попытка
        ПроверитьКоманду85(Команда, "ОтменитьОтложенные85", "ЖдемОтмены");
        ПроверитьОписание85();
        Если ВидОпыта85 <> "ОТЛОЖЕННО" Или СогласиеОтменыИспользовано85 <> Истина Тогда
            ВызватьИсключение "Нет своего отложенного опыта с использованным отдельным согласием";
        КонецЕсли;
        Менеджер = ПолучитьМенеджер85();
        Менеджер.ОтменитьЛокальныеУведомления();
        Если Остановка85 <> Ложь Или Этап85 <> "ЖдемОтмены" Тогда
            ВызватьИсключение "Не перезаписываем исход callback во время запроса отмены";
        КонецЕсли;
        Этап85 = "ОтменаЗапрошена";
        Состояние85 = "Запрос ОБЩЕЙ отмены выполнен без синхронного исключения. Пустая очередь и точная отмена не доказаны";
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ОтключитьСвойОбработчик85(Команда)
    Попытка
        Если Этап85 <> "Доставлено" И Этап85 <> "ОтменаЗапрошена" Тогда
            ВызватьИсключение "Нет законченной ручной фазы для отключения своего handler";
        КонецЕсли;
        ПроверитьКоманду85(Команда, "ОтключитьСвойОбработчик85", Этап85);
        ПроверитьОписание85();
        Менеджер = ПолучитьМенеджер85();
        Менеджер.ОтключитьОбработчикУведомлений(Описание85);
        Если Остановка85 <> Ложь Или (Этап85 <> "Доставлено" И Этап85 <> "ОтменаЗапрошена") Тогда
            ВызватьИсключение "Не перезаписываем неизвестный исход во время отключения";
        КонецЕсли;
        Если ВидОпыта85 = "СЕЙЧАС" Тогда
            Этап85 = "ГотовКОтмене";
        Иначе
            Этап85 = "Завершено";
        КонецЕсли;
        Состояние85 = "Явно отключен свой сохраненный Description. Это не очистка уведомлений и не подтверждение очереди";
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьОписание85()
    Если ТипЗнч(Описание85) <> Тип("ОписаниеОповещения")
        Или Описание85.ИмяПроцедуры <> "ПолученСвойПакет85" Или Описание85.Модуль <> ЭтотОбъект Тогда
        ВызватьИсключение "Подменен native Description или контекст собственной формы";
    КонецЕсли;
    ПроверитьСостояние85(Описание85.ДополнительныеПараметры);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьСостояние85(Состояние)
    Если ТипЗнч(Состояние) <> Тип("Структура") Или Состояние.Количество() <> 5
        Или Не Состояние.Свойство("Nonce") Или Не Состояние.Свойство("Phase")
        Или Не Состояние.Свойство("Version") Или Не Состояние.Свойство("SourcePacket")
        Или Не Состояние.Свойство("Consent") Тогда
        ВызватьИсключение "Не совпали поля собственного четвертого параметра";
    КонецЕсли;
    Если ТипЗнч(Состояние.Nonce) <> Тип("Строка") Или Состояние.Nonce <> НомерОпыта85
        Или ТипЗнч(Состояние.Phase) <> Тип("Строка") Или Состояние.Phase <> ВидОпыта85
        Или ТипЗнч(Состояние.Version) <> Тип("Строка") Или Состояние.Version <> ВерсияЗапуска85
        Или ТипЗнч(Состояние.SourcePacket) <> Тип("Строка") Или Состояние.SourcePacket <> Пакет85
        Или ТипЗнч(Состояние.Consent) <> Тип("Булево") Или Состояние.Consent <> Истина
        Или (ВидОпыта85 = "СЕЙЧАС" И СогласиеИспользовано85 <> Истина)
        Или (ВидОпыта85 = "ОТЛОЖЕННО" И СогласиеОтменыИспользовано85 <> Истина)
        Или ПроверитьПакет85(Состояние.SourcePacket) <> 750 Тогда
        ВызватьИсключение "Не совпал own nonce, фаза, версия, полный пакет или использованное согласие";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Функция ПроверитьПакет85(JSON)
    Если ТипЗнч(JSON) <> Тип("Строка") Или JSON = "" Тогда
        ВызватьИсключение "Нет целого JSON пакета";
    КонецЕсли;
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(JSON);
    Попытка
        Пакет = ПрочитатьJSON(Чтение);
        Чтение.Закрыть();
    Исключение
        Чтение.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
    Если ТипЗнч(Пакет) <> Тип("Структура") Или Пакет.Количество() <> 5
        Или Не Пакет.Свойство("Version") Или Не Пакет.Свойство("Nonce")
        Или Не Пакет.Свойство("Phase") Или Не Пакет.Свойство("Rows") Или Не Пакет.Свойство("Total") Тогда
        ВызватьИсключение "Не совпали все поля пакета";
    КонецЕсли;
    Если ТипЗнч(Пакет.Version) <> Тип("Строка") Или Пакет.Version <> ВерсияЗапуска85
        Или ТипЗнч(Пакет.Nonce) <> Тип("Строка") Или Пакет.Nonce <> НомерОпыта85
        Или ТипЗнч(Пакет.Phase) <> Тип("Строка") Или Пакет.Phase <> ВидОпыта85
        Или ТипЗнч(Пакет.Rows) <> Тип("Массив") Или Пакет.Rows.Количество() <> 2
        Или ТипЗнч(Пакет.Total) <> Тип("Число") Или Пакет.Total <> 750 Тогда
        ВызватьИсключение "Не свой пакет, типы или количество строк";
    КонецЕсли;
    Итог = 0;
    Для Индекс = 0 По 1 Цикл
        СтрокаПакета = Пакет.Rows[Индекс];
        Если ТипЗнч(СтрокаПакета) <> Тип("Структура") Или СтрокаПакета.Количество() <> 3
            Или Не СтрокаПакета.Свойство("Item") Или Не СтрокаПакета.Свойство("Qty")
            Или Не СтрокаПакета.Свойство("Price") Тогда
            ВызватьИсключение "Не совпали все поля строки";
        КонецЕсли;
        Если ТипЗнч(СтрокаПакета.Item) <> Тип("Строка") Или ТипЗнч(СтрокаПакета.Qty) <> Тип("Число")
            Или ТипЗнч(СтрокаПакета.Price) <> Тип("Число") Или СтрокаПакета.Price <> 250
            Или (Индекс = 0 И (СтрокаПакета.Item <> "A" Или СтрокаПакета.Qty <> 2))
            Или (Индекс = 1 И (СтрокаПакета.Item <> "B" Или СтрокаПакета.Qty <> 1)) Тогда
            ВызватьИсключение "Подменены собственные две строки, числовые типы, порядок или цены";
        КонецЕсли;
        Итог = Итог + СтрокаПакета.Qty * СтрокаПакета.Price;
    КонецЦикла;
    Если Итог <> Пакет.Total Тогда
        ВызватьИсключение "500 + 250 не совпало с заявленным итогом";
    КонецЕсли;
    Возврат Итог;
КонецФункции

&НаКлиенте
Функция ПолучитьМенеджер85()
    Менеджер = ДоставляемыеУведомления;
    Если ТипЗнч(Менеджер) <> Тип("МенеджерДоставляемыхУведомлений") Тогда
        ВызватьИсключение "Не получен настоящий global менеджер";
    КонецЕсли;
    Возврат Менеджер;
КонецФункции

&НаКлиенте
Функция ПроверитьСреду85()
    #Если МобильноеПриложениеКлиент Тогда
        Информация = Новый СистемнаяИнформация;
        Версия = Информация.ВерсияПриложения;
        Если ПодтвердитьСвойПакет85() <> Истина Тогда
            ВызватьИсключение "Нужно собственное мобильное приложение не ниже 8.3.18";
        КонецЕсли;
        Поддержка = ПоддерживаетсяФункциональностьМобильногоПриложения(ФункциональностьМобильногоПриложения.ЛокальныеУведомления);
        Если ТипЗнч(Поддержка) <> Тип("Булево") Или Поддержка <> Истина Тогда
            ВызватьИсключение "Функциональность не включена. Это проверка сборки, не разрешение ОС";
        КонецЕсли;
        Возврат Версия;
    #Иначе
        ВызватьИсключение "Только свое мобильное приложение; desktop/mobile-client fallback запрещен";
    #КонецЕсли
КонецФункции

&НаСервереБезКонтекста
Функция ПодтвердитьСвойПакет85()
    #Если МобильноеПриложениеСервер Тогда
        Если Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеФормы.Найти("Уведомления85") = Неопределено Тогда
            ВызватьИсключение "Не совпала своя новая мобильная CF и единственная форма";
        КонецЕсли;
        Возврат Истина;
    #Иначе
        ВызватьИсключение "Нужен сервер своего мобильного приложения";
    #КонецЕсли
КонецФункции

&НаСервереБезКонтекста
Функция ПолучитьСвоюUTC85()
    #Если МобильноеПриложениеСервер Тогда
        Если ПодтвердитьСвойПакет85() <> Истина Тогда
            ВызватьИсключение "Нет своего сервера";
        КонецЕсли;
        UTC = ТекущаяУниверсальнаяДата();
        Если ТипЗнч(UTC) <> Тип("Дата") Тогда
            ВызватьИсключение "Нет native UTC даты";
        КонецЕсли;
        Возврат UTC;
    #Иначе
        ВызватьИсключение "UTC берется на сервере, не прямым mobile-client вызовом";
    #КонецЕсли
КонецФункции

Разбор по шагам

  1. Подготовьте свою новую CF/единственную форму/четыре реальные команды и actual Android developer runtime. Открытие только проверяет свою среду.

  2. Дайте первое отдельное согласие и запустите фазу A. Native global manager получает настоящий DTO, собственный Description и пакет A500+B250=750.

  3. Настоящий callback проверяет свои четвертые параметры, local/shown Bool и целый native Text/Data; после повторного расчета наблюдайте ОтветПолучен85,750 и actual ПоказаноОС85.

  4. Реальной кнопкой явно отключите тот же свой Description, без optional omission/массового отключения.

  5. Только в новой полностью своей лаборатории дайте второе отдельное согласие. Native серверная UTC дата+180 готовит delayed опыт с новым nonce и interval0.

  6. Отдельная ручная cancel0 запрашивает широкую отмену без success/ID/empty-queue обещания. После этого отдельной кнопкой отключите свой handler; early delayed callback дает STOP.

Как проверить результат

  1. Все6 PRIMARY входят в реальный единый producer→consumer: readonly global manager, native DTO/Add, реальный formDescription callback4, явный savedDescription Detach и отдельный delayed cancel0.

  2. Четвертый callback formal документирован constructor/AdditionalParameters и целиком потребляется по полям nonce/phase/version/sourcepayload/consent; первые3 native аргумента также потребляются.

  3. Source пакет и принятый packet проверяются полностью: exact fields/types/2rows/order/A2×250/B1×250/total750. Unknown/foreign данные не становятся успешным результатом.

  4. Оба согласия отдельные, исходноFalse и потребляются только настоящими командами; waiting установлен до Attach/Add, немедленный callback не затирается.

  5. UTC native call находится только в actual mobile-server helper собственной формы, возвращает safe scalar Дата; native void procedures не присваиваются выдуманному результату.

  6. Нет автоматических повторов/cleanup/ручных callbacks, caller-owned ИсходныйОбъект, push-ID или dummy coverage вызовов; runtimeVerified остаетсяFalse.

Ожидаемый результат

Будущая ручная проверка: actual callback дает750 и собственный факт BoolПоказано. Вторая фаза показывает только запрос общей отмены без синхронного исключения. Настоящие Android OS/UI/доставка здесь не проверены.

На что обратить внимание

  1. Attach rawHTML ошибочно помещает ОписаниеОповещения/Строка под «Значение по умолчанию». Description route подтвержден отдельным native ctor/AdditionalParameters/Module и реальным конфигурационным caller; source ошибку не переписываем.

  2. CommonModule.ЭтотОбъект имеет иной native список доступности; не переносим его на mobile APPclient. Здесь используется только прямо документированный native ЭтотОбъект собственной managedформы.

  3. Точный класс callback Уведомление native не указан; onlyText/Data не означает сохранение остальных полей DTO. Actual LocalFalse не читается как свой payload.

  4. Cancel0 широкая, не адресная и не гарантированный rollback. Возвращаемого Bool/ID, чтения очереди и доказательства по отсутствию callback нет.

  5. Мин8.3.18 относится capability guard; фактический APK/runtime отдельно от установленной Windows платформы. OS grant/точный alarm/изоляция/атомарность не обещаны.

  6. STOP относится текущему экземпляру формы. Исключение после Attach/Add/Cancel оставляет неизвестный исход без автоматической уборки; реальный новый опыт требует новой явной ручной подготовки.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Каталог мобильной библиотеки через Ждать: свой PNG без подмены обещания

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

Где и как запускать

Отдельное собственное новое Android ARM64 developer mobile-platform приложение. Только МобильноеПриложениеКлиент; свой локальный МобильноеПриложениеСервер используется для scalar guard. Минимум8.3.18, фактическая версия отдельно.

Подготовка

  1. Урок описывает будущий ручной опыт только на своем отдельном новом Android ARM64 стенде, не личном устройстве и не рабочем приложении. Сейчас 1С, устройство, сеть и файлы не запускались. Просмотр карточки ничего не создает.

  2. Создайте свою новую пустую конфигурацию УчебнаяМедиатека85: Версия = d25140f9-aa1c-4422-a508-c4ad87c10457, режим совместимости Не использовать, назначение использования Приложение для мобильной платформы. Это учебная метка пакета, не криптографическое доказательство и не идентификатор ИБ/устройства.

  3. Общие → Общие формы: создайте ровно четыре управляемые формы ГлавнаяМедиатеки85, ПультМедиатекиОбычный85, ПультМедиатекиАсинх85, ПультМедиатекиОповещения85. В главной форме создайте команды ОткрытьОбычный85, ОткрытьАсинх85, ОткрытьОповещения85 с одноименными обработчиками и кнопками. Вставьте поддерживающий полный модуль главной формы и добавьте эту форму в рабочую область начальной страницы. Она открывает пульты, но не начинает запись.

  4. В каждом пульте создайте реквизиты СогласенНаОпыт85 (Булево, исходно Ложь), ВерсияRuntime85/Состояние85/СвойКаталог85/СвойФайл85 (Строка неограниченной длины), Размер85/Площадь85 (Число15,0). Выведите флажок и поля наблюдения; поля наблюдения ТолькоПросмотр=Да. Создайте команду ПройтиОпыт85, обработчик ПройтиОпыт85(Команда) и кнопку. Событие формы ПриОткрытии свяжите с ПриОткрытии(Отказ), не вызывайте события вручную.

  5. В соответствующий пульт вставьте именно его полный MAIN модуль. У трех пультов отдельные экземпляры внутреннего состояния, nonce и согласия. Серверный helper внутри формы имеет &НаСервереБезКонтекста, выполняется только как МобильноеПриложениеСервер и возвращает Булево; картинки, файлы, обещания и callback через RPC не передаются.

  6. В свойствах новой конфигурации Используемая функциональность мобильного приложения укажите нужные библиотеки картинок и видео. Это заявленная потребность, а не выдача разрешения ОС. Фактическая функциональность/разрешения зависят от полученного мобильного бинарного пакета и ОС. Getter metadata этого свойства всегда Неопределено, его не используем для проверки или включения.

  7. Вручную проверьте свою конфигурацию для Мобильное приложение — клиент и Мобильное приложение — сервер, целостность и неподдерживаемые функции. Затем Конфигурация → Мобильное приложение → Публиковать… только в собственный новый виртуальный каталог OwnMedia85_<ownGUID> и собственную новую папку своей VM/IIS. Публикация создает мобильную конфигурацию, не APK; автоматическое обновление и чужая/рабочая ИБ не нужны. При любой ошибке остановитесь.

  8. Повторите уже документированный путь developer-платформы: только официальная 1cem-arm64.apk из своего фактически полученного мобильного дистрибутива, не 1cem-client-arm64.apk и не 1cem-standalone-arm64.apk. Здесь нет скачивания, установки, сборки, SDK или настройки разрешений. Windows8.5.1.1343 не доказывает версию мобильного APK. Не обещаем наличие подходящего бинарного пакета; неподходящая фактическая сборка — STOP.

  9. После самостоятельной установки developer-платформы на своем стенде: + → Address = реальный URL своей private VM/IIS с точным именем своей публикации → Load → имя УчебнаяМедиатека85 → OK/Done → открыть свое приложение из списка. Не localhost телефона, не file://, не придуманный URL. Своя локальная лабораторная сеть и новая пустая мобильная ИБ; никаких производственных данных.

  10. Официальный маршрут публикации: https://1c-dn.com/library/publishing_of_1c_mobile_application/ ; developer ARM64 и импорт приложения: https://1c-dn.com/library/tutorials/1c_enterprise_development_tools_user_guide/ ; первая собственная мобильная ИБ: https://1c-dn.com/library/tutorials/first_application_mobile_platform/ . Это подготовка для будущего ручного опыта, а не результат runtime-проверки.

  11. Откройте один пульт: поле ВерсияRuntime85 показывает фактическую мобильную версию. Нужен минимум8.3.18 и действительная функциональность БиблиотекиКартинокИВидео=True. Это только проверка включения в сборку, не probe разрешения ОС. False, ошибка, другой контекст или версия — STOP; без desktop fallback и без AllFilesAccess/пересборки как обхода.

  12. Смысл библиотечного пути — потенциально общая библиотека картинок. Собственный GUID-подкаталог не делает ее приватным sandbox. Урок принимает только фактический обычный абсолютный локальный Android filesystem path с доступным существующим родителем. URI, относительный/корневой/неподдерживаемый путь или отказ ОС — STOP; URI не преобразуется и разрешения не расширяются.

  13. Прочитайте последствия и отдельно поставьте флажок выбранного пульта. Одно нажатие потребляет его согласие: запрос библиотечного каталога может взаимодействовать с ОС; далее максимум один собственный новый GUID-каталог и один собственный новый PNG. Другие пульты требуют отдельного согласия. Нет операций при открытии формы, повторной попытки или автоматического запуска.

  14. Собственный PNG — 1x1 RGB(21,98,232), ровно69 байт, не секрет и не чужая фотография; в карточке дан его фиксированный Base64. Сначала actual Exists=True родителя, затем IsDirectory=True; свой дочерний каталог обязан отсутствовать до CreateDirectory и реально существовать после. Файл обязан отсутствовать непосредственно до Write, поскольку native Write способен перезаписывать.

  15. После записи прочитайте только свой новый файл: actual Exists/IsFile, размер69, все байты через Новый ДвоичныеДанные(имя), полное сравнение двух native Base64Строка и actual Картинка ширина1/высота1. Base64Строка использует MIME строки64 с CR+LF; не сравнивайте reread с исходной неразбитой Base64-литералой.

  16. Свой PNG и подкаталог остаются на стенде для ручного просмотра. Никакого удаления, sweeping библиотеки, retry, rollback или уборки. STOP означает неизвестный/частичный исход, а не отсутствие файла. Состояние одного экземпляра формы не обещано переживающим закрытие/перезапуск. Не закрывайте и не открывайте пульт ради обхода STOP; сначала самостоятельно выясните исход только своего опыта.

&НаКлиенте
Перем СогласиеИспользовано85, Остановка85, Неизвестно85, Этап85, Токен85;

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Если СогласиеИспользовано85 <> Неопределено Или Остановка85 <> Неопределено Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    СогласиеИспользовано85 = Ложь;
    Остановка85 = Истина;
    Неизвестно85 = Истина;
    СогласенНаОпыт85 = Ложь;
    СвойКаталог85 = "";
    СвойФайл85 = "";
    Размер85 = 0;
    Площадь85 = 0;
    Попытка
        ВерсияRuntime85 = ПроверитьМобильнуюВерсию85();
        Этап85 = "Готов";
        Остановка85 = Ложь;
        Неизвестно85 = Ложь;
        Состояние85 = "Прочитайте последствия. Отдельно согласитесь на свой каталог и PNG";
    Исключение
        Остановить85(ОписаниеОшибки());
        Отказ = Истина;
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура Остановить85(Причина)
    Остановка85 = Истина;
    Неизвестно85 = Истина;
    СогласенНаОпыт85 = Ложь;
    Этап85 = "STOP";
    Состояние85 = "STOP. Исход неизвестен; повтор и уборка запрещены. " + Причина;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьФакт85(Значение, Ожидалось)
    Если ТипЗнч(Значение) <> Тип("Булево") Или Значение <> Ожидалось Тогда
        ВызватьИсключение "Фактическое состояние файловой системы не соответствует ожиданию";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьЧисло85(Значение, Ожидалось)
    Если ТипЗнч(Значение) <> Тип("Число") Или Значение <> Ожидалось Тогда
        ВызватьИсключение "Фактический размер или измерение не соответствует собственному PNG";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьВозможность85()
    Поддерживается = ПоддерживаетсяФункциональностьМобильногоПриложения(
        ФункциональностьМобильногоПриложения.БиблиотекиКартинокИВидео);
    Если ТипЗнч(Поддерживается) <> Тип("Булево") Или Поддерживается <> Истина Тогда
        ВызватьИсключение "В фактическую сборку не включена нужная мобильная функциональность";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПодготовитьОпыт85(Команда)
    #Если МобильноеПриложениеКлиент Тогда
        Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Найти("ПройтиОпыт85")
            Или СогласиеИспользовано85 <> Ложь Или Остановка85 <> Ложь Или Неизвестно85 <> Ложь
            Или Этап85 <> "Готов" Или СогласенНаОпыт85 <> Истина Тогда
            ВызватьИсключение "Нужна своя команда и отдельное неиспользованное согласие; повтор запрещен";
        КонецЕсли;
        СогласиеИспользовано85 = Истина;
        СогласенНаОпыт85 = Ложь;
        Неизвестно85 = Истина;
        Этап85 = "Получение";
        Токен85 = Новый УникальныйИдентификатор;
        ПроверитьСостояние85("Получение");
    #Иначе
        ВызватьИсключение "Этот файловый опыт запрещен в другой среде";
    #КонецЕсли
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьСостояние85(ОжидаемыйЭтап)
    #Если МобильноеПриложениеКлиент Тогда
        Если Остановка85 <> Ложь Или СогласиеИспользовано85 <> Истина Или Неизвестно85 <> Истина
            Или Этап85 <> ОжидаемыйЭтап Или ТипЗнч(Токен85) <> Тип("УникальныйИдентификатор")
            Или ВерсияRuntime85 <> ПроверитьМобильнуюВерсию85() Тогда
            ВызватьИсключение "Не совпадает собственный незавершенный опыт или мобильная версия";
        КонецЕсли;
        ПроверитьВозможность85();
    #Иначе
        ВызватьИсключение "Продолжение опыта запрещено в другой среде";
    #КонецЕсли
КонецПроцедуры

&НаКлиенте
Функция ПроверитьЛокальныйПуть85(Каталог)
    Если ТипЗнч(Каталог) <> Тип("Строка") Или СтрДлина(Каталог) <= 1 Тогда
        ВызватьИсключение "Native getter не вернул непустую строку каталога";
    КонецЕсли;
    Если Лев(Каталог, 1) <> "/" Или СтрНайти(Каталог, ":") > 0
        Или СтрНайти(Каталог, "\") > 0 Или СтрНайти(Каталог, "//") > 0
        Или СтрНайти(Каталог, Символы.ПС) > 0 Или СтрНайти(Каталог, Символы.ВК) > 0 Тогда
        ВызватьИсключение "Нужен обычный абсолютный Android filesystem path; URI не преобразуем";
    КонецЕсли;
    Части = СтрРазделить(Каталог, "/", Истина);
    Для Каждого Часть Из Части Цикл
        Если Часть = "." Или Часть = ".." Тогда
            ВызватьИсключение "Путь с переходами между каталогами не принимается";
        КонецЕсли;
    КонецЦикла;
    Если Прав(Каталог, 1) = "/" Тогда
        Возврат Лев(Каталог, СтрДлина(Каталог) - 1);
    КонецЕсли;
    Возврат Каталог;
КонецФункции

&НаКлиенте
Процедура ПродолжитьОпыт85(Каталог, ОжидаемыйЭтап)
    ПроверитьСостояние85(ОжидаемыйЭтап);
    Этап85 = "Файлы";
    Родитель = ПроверитьЛокальныйПуть85(Каталог);
    Данные = Base64Значение("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGMQTXoBAAHvAWBSkKSJAAAAAElFTkSuQmCC");
    Если ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Собственный PNG не декодирован в двоичные данные";
    КонецЕсли;
    ПроверитьЧисло85(Данные.Размер(), 69);
    ОжидаемыеБайты = Base64Строка(Данные);
    Если ТипЗнч(ОжидаемыеБайты) <> Тип("Строка") Или ОжидаемыеБайты = "" Тогда
        ВызватьИсключение "Не получено полное native Base64 представление своего PNG";
    КонецЕсли;
    ФайлРодителя = Новый Файл(Родитель);
    ПроверитьФакт85(ФайлРодителя.Существует(), Истина);
    ПроверитьФакт85(ФайлРодителя.ЭтоКаталог(), Истина);
    СвойКаталог = Родитель + "/OwnMedia85_" + Строка(Токен85);
    СвойФайл = СвойКаталог + "/pixel_" + Строка(Токен85) + ".png";
    ФайлКаталога = Новый Файл(СвойКаталог);
    ПроверитьФакт85(ФайлКаталога.Существует(), Ложь);
    ПроверитьСостояние85("Файлы");
    СоздатьКаталог(СвойКаталог);
    ФайлКаталога = Новый Файл(СвойКаталог);
    ПроверитьФакт85(ФайлКаталога.Существует(), Истина);
    ПроверитьФакт85(ФайлКаталога.ЭтоКаталог(), Истина);
    ФайлКартинки = Новый Файл(СвойФайл);
    ПроверитьФакт85(ФайлКартинки.Существует(), Ложь);
    ПроверитьСостояние85("Файлы");
    Данные.Записать(СвойФайл);
    ФайлКартинки = Новый Файл(СвойФайл);
    ПроверитьФакт85(ФайлКартинки.Существует(), Истина);
    ПроверитьФакт85(ФайлКартинки.ЭтоФайл(), Истина);
    ФактическийРазмер = ФайлКартинки.Размер();
    ПроверитьЧисло85(ФактическийРазмер, 69);
    Прочитано = Новый ДвоичныеДанные(СвойФайл);
    Если ТипЗнч(Прочитано) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Не прочитаны реальные двоичные данные собственного файла";
    КонецЕсли;
    ПроверитьЧисло85(Прочитано.Размер(), 69);
    ФактическиеБайты = Base64Строка(Прочитано);
    Если ТипЗнч(ФактическиеБайты) <> Тип("Строка") Или ФактическиеБайты <> ОжидаемыеБайты Тогда
        ВызватьИсключение "Полное фактическое содержимое своего PNG отличается от producer";
    КонецЕсли;
    Картинка = Новый Картинка(Прочитано);
    Ширина = Картинка.Ширина();
    Высота = Картинка.Высота();
    ПроверитьЧисло85(Ширина, 1);
    ПроверитьЧисло85(Высота, 1);
    ПроверитьСостояние85("Файлы");
    СвойКаталог85 = СвойКаталог;
    СвойФайл85 = СвойФайл;
    Размер85 = ФактическийРазмер;
    Площадь85 = Ширина * Высота;
    Неизвестно85 = Ложь;
    Этап85 = "Завершен";
    Состояние85 = "Полные байты и картинка 1x1 проверены. Свой PNG оставлен без удаления";
КонецПроцедуры
&НаКлиенте
Функция ПроверитьМобильнуюВерсию85()
    #Если МобильноеПриложениеКлиент Тогда
        Информация = Новый СистемнаяИнформация;
        Версия = Информация.ВерсияПриложения;
        Если ПроверитьСвойПакетНаСервере85() <> Истина Тогда
            ВызватьИсключение "Своя метка мобильного пакета не подтверждена";
        КонецЕсли;
        Возврат Версия;
    #Иначе
        ВызватьИсключение "Только собственное мобильное приложение, без desktop/mobile-client fallback";
    #КонецЕсли
КонецФункции
&НаКлиенте
Асинх Процедура ПройтиОпыт85(Команда)
    Попытка
        ПодготовитьОпыт85(Команда);
        ОбещаниеКаталога = КаталогБиблиотекиМобильногоУстройстваАсинх(
            ТипКаталогаБиблиотекиМобильногоУстройства.Картинки);
        Если ТипЗнч(ОбещаниеКаталога) <> Тип("Обещание") Тогда
            ВызватьИсключение "Не получено настоящее native обещание каталога";
        КонецЕсли;
        Каталог = Ждать ОбещаниеКаталога;
        ПродолжитьОпыт85(Каталог, "Получение");
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьСвойПакетНаСервере85()
    #Если МобильноеПриложениеСервер Тогда
        Если Метаданные.ОбщиеФормы.Количество() <> 4 Или Метаданные.ОбщиеФормы.Найти("ГлавнаяМедиатеки85") = Неопределено Или Метаданные.ОбщиеФормы.Найти("ПультМедиатекиОбычный85") = Неопределено Или Метаданные.ОбщиеФормы.Найти("ПультМедиатекиАсинх85") = Неопределено Или Метаданные.ОбщиеФормы.Найти("ПультМедиатекиОповещения85") = Неопределено Тогда
            ВызватьИсключение "Не совпадает собственный новый учебный мобильный пакет";
        КонецЕсли;
        Возврат Истина;
    #Иначе
        ВызватьИсключение "Нужен локальный сервер своего мобильного приложения, не desktop ИБ";
    #КонецЕсли
КонецФункции
Главная форма: три настоящие команды, ни одной операции с библиотекой при открытии

Своя CF → Общие → Общие формы → ГлавнаяМедиатеки85 → полный управляемый модуль

МобильноеПриложениеКлиент; серверный helper только МобильноеПриложениеСервер. Проверяется метка собственного пакета и фактическая версия, затем открывается выбранная своя форма. Directory/File/Write не вызываются.

&НаКлиенте
Процедура ОткрытьОбычный85(Команда)
    Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Найти("ОткрытьОбычный85") Тогда
        ВызватьИсключение "Нужна собственная команда главной формы";
    КонецЕсли;
    ПроверитьМобильнуюВерсию85();
    ОткрытьФорму("ОбщаяФорма.ПультМедиатекиОбычный85");
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьАсинх85(Команда)
    Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Найти("ОткрытьАсинх85") Тогда
        ВызватьИсключение "Нужна собственная команда главной формы";
    КонецЕсли;
    ПроверитьМобильнуюВерсию85();
    ОткрытьФорму("ОбщаяФорма.ПультМедиатекиАсинх85");
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьОповещения85(Команда)
    Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Найти("ОткрытьОповещения85") Тогда
        ВызватьИсключение "Нужна собственная команда главной формы";
    КонецЕсли;
    ПроверитьМобильнуюВерсию85();
    ОткрытьФорму("ОбщаяФорма.ПультМедиатекиОповещения85");
КонецПроцедуры
&НаКлиенте
Функция ПроверитьМобильнуюВерсию85()
    #Если МобильноеПриложениеКлиент Тогда
        Информация = Новый СистемнаяИнформация;
        Версия = Информация.ВерсияПриложения;
        Если ПроверитьСвойПакетНаСервере85() <> Истина Тогда
            ВызватьИсключение "Своя метка мобильного пакета не подтверждена";
        КонецЕсли;
        Возврат Версия;
    #Иначе
        ВызватьИсключение "Только собственное мобильное приложение, без desktop/mobile-client fallback";
    #КонецЕсли
КонецФункции
&НаСервереБезКонтекста
Функция ПроверитьСвойПакетНаСервере85()
    #Если МобильноеПриложениеСервер Тогда
        Если Метаданные.ОбщиеФормы.Количество() <> 4 Или Метаданные.ОбщиеФормы.Найти("ГлавнаяМедиатеки85") = Неопределено Или Метаданные.ОбщиеФормы.Найти("ПультМедиатекиОбычный85") = Неопределено Или Метаданные.ОбщиеФормы.Найти("ПультМедиатекиАсинх85") = Неопределено Или Метаданные.ОбщиеФормы.Найти("ПультМедиатекиОповещения85") = Неопределено Тогда
            ВызватьИсключение "Не совпадает собственный новый учебный мобильный пакет";
        КонецЕсли;
        Возврат Истина;
    #Иначе
        ВызватьИсключение "Нужен локальный сервер своего мобильного приложения, не desktop ИБ";
    #КонецЕсли
КонецФункции

Разбор по шагам

  1. В отдельном пульте отдельно согласитесь на собственный каталог/PNG; согласие потребляется до native вызова.

  2. Реальный КаталогБиблиотекиМобильногоУстройстваАсинх(Картинки) обязан вернуть Обещание, не строку и не поддельный объект.

  3. Настоящий Ждать дает фактический каталог; прямое/конечное Неопределено, пустая строка, ошибка или уже STOP запрещают продолжение.

  4. Повторная проверка после Ждать предшествует любому File/CreateDirectory/Write. Только поддерживаемый ordinary local path своего стенда принимается.

  5. Создайте один свежий GUID-child/PNG с collision STOP. После записи прочитайте только свой69-byte файл и проверьте целое содержимое.

  6. Native Картинка из reread должна дать числовые1x1; площадь1 и размер69 наблюдаются на форме. Никакого retry/delete.

Как проверить результат

  1. Getter результата не подменяется Windows путем, пользовательским параметром, fake Promise или ручным callback.

  2. До любого filesystem вызова есть отдельное consumed-согласие, метка своей CF, фактическая версия, native capability и допустимый actual path.

  3. Exists проверяется перед IsDirectory/IsFile. CreateDirectory не считается успешным просто из-за отсутствия исключения.

  4. Write вызывается один раз с одним своим именем после свежего Exists=False; реальный native writer может перезаписывать, поэтому коллизия всегда STOP.

  5. Контрольное чтение получает реальные69 байт, сравнивает полное native Base64 с own producer и потребляет actual Width/Height как площадь1.

Ожидаемый результат

Ожидаемый ручной результат: Размер85=69, Площадь85=1; СвойКаталог85 и СвойФайл85 показывают только свой созданный GUID-child/PNG. Файл оставлен. Здесь runtime и доступ ОС не проверены.

На что обратить внимание

  1. Библиотека потенциально общая, не sandbox. GUID-name не доказывает приватность, отсутствие симлинков/гонки или атомарность записи.

  2. Built-feature=True не выдает разрешения ОС и не гарантирует ordinary writable path. Unsupported representation/URI/отказ ОС — STOP без обходов.

  3. Проверка path — ограничение учебного опыта, не canonical resolver или security boundary. Нет claims приватного parent/canonical containment/race-safe exclusivity.

  4. Неопределенные размеры картинки, пустой каталог и неожиданные типы не превращаем в значения по умолчанию.

  5. Base64Строка native MIME64/CRLF: сравниваются две native строки целиком, не исходная неразбитая литерала.

  6. Нет гарантированного canceled-Bool в данном callback. Неожиданный/пустой результат остановит опыт, но не называем его документированным флагом отмены.

  7. Sticky STOP и consumed-согласие принадлежат текущему экземпляру формы; закрытие/перезапуск не обещаны сохраняющими их.

  8. Файл/child не удаляются даже при ошибке; неизвестный исход не является доказанным отсутствием. Здесь нет actual device/SDK/network/filesystem операций.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.