При разработке тиражных мобильных приложений на платформе 1С часто возникает задача индивидуализации расходов на сторонние сервисы. Типичный пример — интеграция картографических сервисов Google Maps. Каждый клиент, приобретающий тиражное решение, должен использовать свой собственный API-ключ Google, чтобы самостоятельно оплачивать запросы к геосервисам в соответствии со своими объемами эксплуатации. Однако на практике разработчики сталкиваются с серьезным техническим ограничением мобильной платформы 1С и операционной системы Android: стандартный ключ прописывается на этапе сборки приложения и не подлежит динамическому изменению из кода «на лету».
В этой статье мы подробно разберем, почему классический путь интеграции карт блокирует возможность динамической подмены ключа, проанализируем архитектурные ограничения мобильных операционных систем и рассмотрим эффективные практические альтернативы, которые позволят вашим клиентам использовать собственные API-ключи без необходимости пересборки мобильного приложения.
Начнем с анализа стандартного механизма работы мобильной платформы 1С. Когда мы используем нативные средства геопозиционирования (например, объект СредстваГеопозиционирования или метод ПоказатьНаКарте()), платформа обращается к системным библиотекам операционной системы. На устройствах Android для этого задействуется нативный Google Maps SDK.
Этот SDK требует жесткой авторизации приложения на стороне серверов Google. Безопасность и идентификация обеспечиваются тем, что ваш API-ключ должен быть обязательно прописан в главном конфигурационном файле приложения — манифесте (AndroidManifest.xml). Секция выглядит следующим образом:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="ВАШ_КОНСТАНТНЫЙ_API_КЛЮЧ" />
Этот манифест компилируется, упаковывается внутрь бинарного файла APK (или AAB) и подписывается цифровым сертификатом разработчика при сборке в сборщике мобильных приложений 1С. Операционная система Android из соображений безопасности строго запрещает любым приложениям изменять собственный манифест или файлы в системном каталоге после установки. Попытка программно перезаписать этот файл приведет к нарушению целостности подписи, и операционная система просто заблокирует работу приложения. Именно поэтому хранить ключ в константе 1С и программно передавать его в нативную карту не получится.
Самым надежным, гибким и кроссплатформенным решением данной проблемы является полный отказ от использования нативных средств геопозиционирования в пользу элемента формы ПолеHTMLДокумента. Вместо нативного окна карты мы будем выводить обычную веб-страницу, на которой карта инициализируется с помощью Google Maps JavaScript API.
Этот подход полностью снимает ограничения операционной системы, так как JavaScript-скрипт карты загружается динамически в контексте браузера (Web-View), встроенного в мобильное приложение 1С. API-ключ при этом передается как обычный параметр в URL-строке подключения скрипта.
Рассмотрим по шагам, как реализовать этот механизм в конфигурации 1С:
Константы.КлючGoogleMaps.Получить()).ПолеHTMLДокумента и назовем его КартаПолеHTML.Проанализируем пример кода на встроенном языке 1С, который формирует и выводит карту на форму мобильного приложения:
&Процедура ОбновитьКартуНаФорме(Широта, Долгота)
// Получаем индивидуальный ключ клиента из базы данных 1С
ТекущийКлючAPI = Константы.КлючGoogleMaps.Получить();
Если ПустаяСтрока(ТекущийКлючAPI) Тогда
ВызватьИсключение "Не задан API-ключ Google Maps в настройках системы!";
КонецЕсли;
// Формируем динамический HTML-код с подстановкой ключа и координат
ШаблонHTML =
"<!DOCTYPE html>
|<html>
|<head>
| <meta name=""viewport"" content=""initial-scale=1.0, user-scalable=no"" />
| <style type=""text/css"">
| html { height: 100% }
| body { height: 100%; margin: 0; padding: 0 }
| #map-canvas { height: 100% }
| </style>
| <script type=""text/javascript""
| src=""https://maps.googleapis.com/maps/api/js?key=[API_KEY]&sensor=false"">
| </script>
| <script type=""text/javascript"">
| function initialize() {
| var mapOptions = {
| center: new google.maps.LatLng([LATITUDE], [LONGITUDE]),
| zoom: 15,
| mapTypeId: google.maps.MapTypeId.ROADMAP
| };
| var map = new google.maps.Map(document.getElementById(""map-canvas""), mapOptions);
|
| // Добавляем маркер на карту
| var marker = new google.maps.Marker({
| position: new google.maps.LatLng([LATITUDE], [LONGITUDE]),
| map: map,
| title: ""Ваша точка""
| });
| }
| google.maps.event.addDomListener(window, 'load', initialize);
| </script>
|</head>
|<body>
| <div id=""map-canvas""/>
|</body>
|</html>";
// Производим замену параметров в шаблоне
ИтоговыйHTML = СтрЗаменить(ШаблонHTML, "[API_KEY]", ТекущийКлючAPI);
ИтоговыйHTML = СтрЗаменить(ИтоговыйHTML, "[LATITUDE]", Формат(Широта, "ЧРД=.; ЧГ=0"));
ИтоговыйHTML = СтрЗаменить(ИтоговыйHTML, "[LONGITUDE]", Формат(Долгота, "ЧРД=.; ЧГ=0"));
// Загружаем готовый код в элемент формы
Элементы.КартаПолеHTML.Документ.открыть();
Элементы.КартаПолеHTML.Документ.писать(ИтоговыйHTML);
Элементы.КартаПолеHTML.Документ.закрыть();
КонецПроцедуры
Преимущества данного подхода:
Бывают ситуации, когда карты как визуальный элемент на форме не нужны, а требуется лишь использовать геосервисы Google для служебных задач: прямого и обратного геокодирования (определения координат по адресу или адреса по координатам), расчета расстояний между точками или построения оптимальных маршрутов (Matrix API).
Передавать клиентские ключи напрямую из мобильного приложения в Google в виде открытых HTTP-запросов небезопасно. Злоумышленники могут перехватить трафик или декомпилировать приложение и использовать чужой ключ в своих целях, за что владельцу ключа придет огромный счет.
В этом случае мы рекомендуем использовать архитектуру с промежуточным сервером (Proxy):
Этот подход гарантирует максимальную безопасность: ключи клиентов никогда не передаются на мобильные устройства и хранятся в защищенной базе данных на сервере.
Если нативные карты жизненно необходимы для проекта (например, требуется глубокая интеграция со стандартными жестами ОС, высокая производительность при отображении сотен тысяч точек на слабых устройствах), то единственным легальным и стабильным путем остается сборка индивидуальных мобильных приложений.
Вы можете автоматизировать этот процесс, чтобы не тратить время на ручную сборку:
AndroidManifest.xml и в конфигурационные файлы iOS.Обратите внимание, что правила Google Play запрещают приложениям скачивать и устанавливать другие исполняемые файлы программно внутри себя. Поэтому устанавливать такое собранное приложение пользователь должен будет вручную, предварительно разрешив в настройках Android установку приложений из неизвестных источников.
В кругах разработчиков иногда обсуждается возможность обойти ограничение манифеста с помощью рефлексии (Java Reflection). Идея заключается в том, чтобы программно внедриться в работающий процесс Android-приложения, найти в оперативной памяти объект ApplicationInfo, содержащий метаданные запущенного пакета, и принудительно перезаписать значение ключа в оперативной памяти до того, как Google Maps SDK выполнит инициализацию.
Мы настоятельно не рекомендуем использовать этот метод в коммерческих тиражных решениях по следующим причинам:
Подводя итог, можно сделать однозначный вывод: для создания надежного, масштабируемого и удобного тиражного решения на мобильной платформе 1С наиболее эффективным выбором является использование Поля HTML-документа. Оно полностью решает проблему с динамической подменой API-ключей Google Карт, гарантирует стабильность работы приложения при любых обновлениях ОС и избавляет вас от необходимости сложной поддержки сотен уникальных сборок под каждого клиента.