Проект "Unity Proxy"
Продолжаю рассказывать про наши интересные реализованные проекты. В этот раз представляю вашему вниманию проект 2018го года, из категории «самый полный Пэ» — за такое беремся только мы.
Полный Пэ
Такие проекты это причина, по которой я до сих пор беру заказы с открытого рынка — с бирж фриланса, потому что они позволяют просраться даже опытным профессионалам.
Если вы зазвездились и начали считать себя настоящим гением, гуру и профи в одном лице — описываемая жесть отлично поставит вас на место.
Да и вообще подобные проекты неплохо бодрят и не позволяют вконец отупеть от очередного корпоративного формошлепства.
Начнем с описания этого интересного проекта.
У заказчика были два веселых гуся готовых приложения для iOS и Android, созданных на базе Unity, которые с помощью технологий дополненной реальности позволяли встраивать трехмерные объекты в видеопоток с камеры телефона.
В работе эта неведомая хтонь выглядела как-то так:
Все работало бы замечательно и дальше, если бы не родной РКН, который в тот год объявил джихад и кровную месть Телеграму и в попытках его заблокировать порубил половину тогдашнего рунета.
Если кто забыл, в 2018 м постоянно падали банковские приложения, хостинги, онлайн-казиносервисы — пока сотрудники РКН изучали как работают CDN-серверы и геораспределенные зеркала, они раз за разом блочили абсолютно левые сервисы, просто оказавшиеся соседями по провайдеру или подсети.
Замечательное приложение с дополненной реальностью тоже задело банхаммером РКН:
под раздачу попали сервера Vuforia, которые использовались для определения точки привязки объекта в видеопотоке.
Обратите внимание на картинку с текстурой камней в видео выше — это и есть та самая точка привязки, используемая для позиционирования.
Суммируя получалось следующее:
Проект на Unity, который использует Vuforia SDK, из которого собираются два мобильных приложения Android и iOS, которые делают вызовы к удаленному закрытому серверу (точнее к нескольким) для своей работы.
Вся логика взаимодействия с серверами Vuforia является закрытой, реализация частично нативная.
И вот вся эта радость в один момент была заблокирована РКН.
Перенастроить адреса серверов нельзя (они зашиты в библиотеку), сделать эмулятор — времени не хватит.
А задача очень простая (как обычно):
Примерно как у Бетмена, разве что в небо прожектором не светили.
Ну что, взялись бы за такой проект?
Изучение
Первым делом было развернуто тестовое приложение с Vuforia на чистом Android, собрано и развернуто на реальном смартфоне — на эмуляторе оно ввиду своей специфики не работало.
Затем через отладчик началось изучение протокола взаимодействия:
Отладка показала самое важное:
протокол взаимодействия между приложением и серверами Vuforia основан на https и json
А забравшись внутрь нативной части, увидел что используются стандартные системные классы для работы с http-протоколом:
Эти два факта в сумме и дали возможное решение:
программная установка прокси-сервера для системных вызовов ДО начала работы Vuforia.
Технически, примерно такой код надо вызывать до момента запуска Vuforia:
String url = "http://www.google.com/", proxy = "proxy.mydomain.com", port = "8080"; URL server = new URL(url); Properties systemProperties = System.getProperties(); systemProperties.setProperty("http.proxyHost",proxy); systemProperties.setProperty("http.proxyPort",port);
Сказано — сделано, вот так выглядел первый работающий прототип, с проксированием вызовов к серверам Vuforia из тестового приложения на Android:
реализовать подобное для iOS-версии и затем выдать готовое решение уже на Unity.
Плюс реализовать всю обвязку по настройке, чтобы не зашивать адрес прокси в код приложения
Оборудование
Отдельной подставой в тот момент был выход из строя сразу двоих моих рабочих ноутбуков, еще и по серьезным причинам, требующим длительного ремонта.
Пока они были в ремонте, завершать проект пришлось на полных «дровах»:
i5 и 8Гб памяти (всего), на которых помимо основной ОС крутилась виртуальная машина с MacOS, средой разработки XCode, Unity и эмулятором iOS.
Если кто вдруг не знает, то для нормальной разработки под iOS на XCode рекомендуется 32Гб памяти, разумеется на реальном устройстве.
А ведь был еще Android и Unity.
Было весело, зато с тех времен остался вот этот эпичный скриншот, которым я ныне пугаю современных разработчиков:
Как только получилось пропихнуть прокси, была запущена специальная отладочная утилита, позволяющая в реальном времени отслеживать все проходящие через прокси запросы, называется AnyProxy.
Вот так выглядел первый запуск тестового приложения через управляемый прокси:
Тут сразу стало видно проблему:
запросы к домену dp.qcarsdk.com не проходят уже со стороны прокси
Как раз из-за угара РКН в тот год.
Вот так все выглядело целиком в динамике, запущенное тестовое приложение в эмуляторе и отображение запросов прокси:
У AnyProxy была встроенная возможность каскада, когда запрос к прокси отправляется не напрямую а в следующий прокси.
Именно это я и использовал, подключив каскадом локальный прокси, запускаемый Tor Browser.
Чем наконец обеспечил работоспособность (обратите внимание на трехмерный чайник):
Следующим этапом началась разработка модуля для Unity, в рамках которого уже решалась задача с проксированием запросов для iOS версии.
Принцип включения прокси был аналогичен Android-версии:
вызов специального системного метода для установки прокси для всех вызовов HTTP/HTTPS
Unity позволяет добавлять в проект части кода на Objective-C для iOS и Java — для Android, хотя основую логику (включая интерфейс настройки) пришлось писать на C# — основной язык Unity.
Вот так выглядит нативная часть на Objective-C, непосредственно устанавливающая прокси:
extern "C" int DoSetupUpdate(const char* paramHost,const int paramPort) { NSString* proxyHost = CreateNSString(paramHost); NSNumber* proxyPort = [NSNumber numberWithInt: paramPort]; NSLog(@"update proxy for IOS %@ : %@",proxyHost,proxyPort); [LLHTTPProxyURLProtocol setProxyParams: proxyHost pPort:proxyPort]; }
Класс LLHTTPProxyURLProtocol был взят отсюда.
Вот так выглядело связывание с C# (Mono) в Unity:
[DllImport ("__Internal")] private static extern int DoSetupUpdate (string paramHost,int paramPort);
Ну и общая логика установки прокси со стороны модуля Unity:
/// <summary> /// метод обновляет настройки прокси, /// логика работы отличается от начальной установки прокси /// </summary> /// <param name="ps">новые параметры прокси</param> public void Setup(ProxySettings ps) { ps.SaveToPlayerPrefs(); if (Application.platform == RuntimePlatform.Android) { SetupForAndroid (ps); } else if (Application.platform == RuntimePlatform.IPhonePlayer) { try { if (!ps.ProxyEnabled) // если использование прокси-сервера отключено { // сбрасываем настройки прокси ps.ProxyHost = null; ps.ProxyPort = 0; } // эта функция лишь обновит настройку без установки обработчика протокола DoSetupUpdate (ps.ProxyHost, ps.ProxyPort); } catch (Exception e) { // могут быть ошибки сигнатур нативных методов или имен классов Debug.LogError (e.Message); } } else { Environment.SetEnvironmentVariable("HTTP_PROXY", ps.ProxyHost + ":" + ps.ProxyPort, EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("HTTPS_PROXY", ps.ProxyHost + ":" + ps.ProxyPort, EnvironmentVariableTarget.Machine); } }
Вот так готовый модуль для Unity выглядел в работе:
А так выглядела трассировка работы Android-приложения на реальном смартфоне:
Наконец пришло время подключить готовый модуль Unity в реальные приложения заказчика и проверить в работе:
Не забыли мы и про интерфейс для настройки:
Вот так это выглядело непосредственно в среде разработки (в Unity модули умеют сами себя настраивать):
Эпилог
Вот такие дела, сложное предварительное изучение вопроса с отладчиком в руках, прототипирование и сама разработка на трех серьезных языках:
C# (Mono), Java (Android) и Objective-C (iOS).
Теперь представьте, если бы я следуя современным подходам в разработке начал ныть про «специализацию», что «один разработчик не может разбираться сразу во всем» и про прочее современное говно.
Да да, именно там где вы подумали.
За кадром еще осталась настройка PUSH-уведомлений для обновления настроек прокси без пересборки приложений, что было отдельной эпопеей.
На все ушло примерно полтора месяца, но думаю вы уже успели заметить — судя по времени на скриншотах эта работа сильно отличалась от лепки стандартных CRUDов в теплом офисе.
Также из наработок этого замечательного проекта родилась аж целая система управления наборами прокси, но это уже другая история, для другой статьи: