Получите настоящий библиотечный каталог обычным вызовом и изучите разницу между поддержкой функции, доступом ОС и фактическим результатом записи своего PNG.
Где и как запускать
Отдельное собственное новое Android ARM64 developer mobile-platform приложение. Только МобильноеПриложениеКлиент; свой локальный МобильноеПриложениеСервер используется для scalar guard. Минимум8.3.18, фактическая версия отдельно.
Подготовка
Урок описывает будущий ручной опыт только на своем отдельном новом Android ARM64 стенде, не личном устройстве и не рабочем приложении. Сейчас 1С, устройство, сеть и файлы не запускались. Просмотр карточки ничего не создает.
Создайте свою новую пустую конфигурацию УчебнаяМедиатека85: Версия = d25140f9-aa1c-4422-a508-c4ad87c10457, режим совместимости Не использовать, назначение использования Приложение для мобильной платформы. Это учебная метка пакета, не криптографическое доказательство и не идентификатор ИБ/устройства.
Общие → Общие формы: создайте ровно четыре управляемые формы ГлавнаяМедиатеки85, ПультМедиатекиОбычный85, ПультМедиатекиАсинх85, ПультМедиатекиОповещения85. В главной форме создайте команды ОткрытьОбычный85, ОткрытьАсинх85, ОткрытьОповещения85 с одноименными обработчиками и кнопками. Вставьте поддерживающий полный модуль главной формы и добавьте эту форму в рабочую область начальной страницы. Она открывает пульты, но не начинает запись.
В каждом пульте создайте реквизиты СогласенНаОпыт85 (Булево, исходно Ложь), ВерсияRuntime85/Состояние85/СвойКаталог85/СвойФайл85 (Строка неограниченной длины), Размер85/Площадь85 (Число15,0). Выведите флажок и поля наблюдения; поля наблюдения ТолькоПросмотр=Да. Создайте команду ПройтиОпыт85, обработчик ПройтиОпыт85(Команда) и кнопку. Событие формы ПриОткрытии свяжите с ПриОткрытии(Отказ), не вызывайте события вручную.
В соответствующий пульт вставьте именно его полный MAIN модуль. У трех пультов отдельные экземпляры внутреннего состояния, nonce и согласия. Серверный helper внутри формы имеет &НаСервереБезКонтекста, выполняется только как МобильноеПриложениеСервер и возвращает Булево; картинки, файлы, обещания и callback через RPC не передаются.
В свойствах новой конфигурации Используемая функциональность мобильного приложения укажите нужные библиотеки картинок и видео. Это заявленная потребность, а не выдача разрешения ОС. Фактическая функциональность/разрешения зависят от полученного мобильного бинарного пакета и ОС. Getter metadata этого свойства всегда Неопределено, его не используем для проверки или включения.
Вручную проверьте свою конфигурацию для Мобильное приложение — клиент и Мобильное приложение — сервер, целостность и неподдерживаемые функции. Затем Конфигурация → Мобильное приложение → Публиковать… только в собственный новый виртуальный каталог OwnMedia85_<ownGUID> и собственную новую папку своей VM/IIS. Публикация создает мобильную конфигурацию, не APK; автоматическое обновление и чужая/рабочая ИБ не нужны. При любой ошибке остановитесь.
Повторите уже документированный путь developer-платформы: только официальная 1cem-arm64.apk из своего фактически полученного мобильного дистрибутива, не 1cem-client-arm64.apk и не 1cem-standalone-arm64.apk. Здесь нет скачивания, установки, сборки, SDK или настройки разрешений. Windows8.5.1.1343 не доказывает версию мобильного APK. Не обещаем наличие подходящего бинарного пакета; неподходящая фактическая сборка — STOP.
После самостоятельной установки developer-платформы на своем стенде: + → Address = реальный URL своей private VM/IIS с точным именем своей публикации → Load → имя УчебнаяМедиатека85 → OK/Done → открыть свое приложение из списка. Не localhost телефона, не file://, не придуманный URL. Своя локальная лабораторная сеть и новая пустая мобильная ИБ; никаких производственных данных.
Официальный маршрут публикации: 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-проверки.
Откройте один пульт: поле ВерсияRuntime85 показывает фактическую мобильную версию. Нужен минимум8.3.18 и действительная функциональность БиблиотекиКартинокИВидео=True. Это только проверка включения в сборку, не probe разрешения ОС. False, ошибка, другой контекст или версия — STOP; без desktop fallback и без AllFilesAccess/пересборки как обхода.
Смысл библиотечного пути — потенциально общая библиотека картинок. Собственный GUID-подкаталог не делает ее приватным sandbox. Урок принимает только фактический обычный абсолютный локальный Android filesystem path с доступным существующим родителем. URI, относительный/корневой/неподдерживаемый путь или отказ ОС — STOP; URI не преобразуется и разрешения не расширяются.
Прочитайте последствия и отдельно поставьте флажок выбранного пульта. Одно нажатие потребляет его согласие: запрос библиотечного каталога может взаимодействовать с ОС; далее максимум один собственный новый GUID-каталог и один собственный новый PNG. Другие пульты требуют отдельного согласия. Нет операций при открытии формы, повторной попытки или автоматического запуска.
Собственный PNG — 1x1 RGB(21,98,232), ровно69 байт, не секрет и не чужая фотография; в карточке дан его фиксированный Base64. Сначала actual Exists=True родителя, затем IsDirectory=True; свой дочерний каталог обязан отсутствовать до CreateDirectory и реально существовать после. Файл обязан отсутствовать непосредственно до Write, поскольку native Write способен перезаписывать.
После записи прочитайте только свой новый файл: actual Exists/IsFile, размер69, все байты через Новый ДвоичныеДанные(имя), полное сравнение двух native Base64Строка и actual Картинка ширина1/высота1. Base64Строка использует MIME строки64 с CR+LF; не сравнивайте reread с исходной неразбитой Base64-литералой.
Свой 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(Команда);
Каталог = КаталогБиблиотекиМобильногоУстройства(
ТипКаталогаБиблиотекиМобильногоУстройства.Картинки);
ПродолжитьОпыт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 ИБ";
#КонецЕсли
КонецФункции
Разбор по шагам
Прочитайте подготовку своего отдельного стенда и однократно согласитесь на один каталог/PNG.
MAIN реально проверяет БиблиотекиКартинокИВидео и вызывает КаталогБиблиотекиМобильногоУстройства(Картинки). BoolTrue не означает разрешение записи.
Фактический String проходит ограниченную проверку ordinary local path. Если путь/доступ неподходящий, STOP без заменителя каталога.
Создайте только свежий GUID-child после фактической проверки родителя и отсутствия child; снова прочитайте Exists и IsDirectory после CreateDirectory.
После проверки отсутствия своего PNG запишите69 собственных байт. Фактически прочитайте весь файл и сравните native Base64 representations целиком.
Создайте native Картинка из reread, проверьте типы и1x1, получите площадь1. Каталог и PNG оставьте без удаления.
Как проверить результат
Getter результата не подменяется Windows путем, пользовательским параметром, fake Promise или ручным callback.
До любого filesystem вызова есть отдельное consumed-согласие, метка своей CF, фактическая версия, native capability и допустимый actual path.
Exists проверяется перед IsDirectory/IsFile. CreateDirectory не считается успешным просто из-за отсутствия исключения.
Write вызывается один раз с одним своим именем после свежего Exists=False; реальный native writer может перезаписывать, поэтому коллизия всегда STOP.
Контрольное чтение получает реальные69 байт, сравнивает полное native Base64 с own producer и потребляет actual Width/Height как площадь1.
Ожидаемый результат
Ожидаемый ручной результат: Размер85=69, Площадь85=1; СвойКаталог85 и СвойФайл85 показывают только свой созданный GUID-child/PNG. Файл оставлен. Здесь runtime и доступ ОС не проверены.
На что обратить внимание
Библиотека потенциально общая, не sandbox. GUID-name не доказывает приватность, отсутствие симлинков/гонки или атомарность записи.
Built-feature=True не выдает разрешения ОС и не гарантирует ordinary writable path. Unsupported representation/URI/отказ ОС — STOP без обходов.
Проверка path — ограничение учебного опыта, не canonical resolver или security boundary. Нет claims приватного parent/canonical containment/race-safe exclusivity.
Неопределенные размеры картинки, пустой каталог и неожиданные типы не превращаем в значения по умолчанию.
Base64Строка native MIME64/CRLF: сравниваются две native строки целиком, не исходная неразбитая литерала.
Нет гарантированного canceled-Bool в данном callback. Неожиданный/пустой результат остановит опыт, но не называем его документированным флагом отмены.
Sticky STOP и consumed-согласие принадлежат текущему экземпляру формы; закрытие/перезапуск не обещаны сохраняющими их.
Файл/child не удаляются даже при ошибке; неизвестный исход не является доказанным отсутствием. Здесь нет actual device/SDK/network/filesystem операций.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.