Введение
После того, как кросс-энд технология Flutter была запущена, она завоевала хорошую репутацию в отрасли.Его преимущества в «многоконечной согласованности» и «производительности рендеринга» затрудняют сравнение других кросс-энд решений. Хотя кривая роста Flutter и перспективы на будущее выглядят хорошо, нельзя отрицать, что Flutter все еще находится на стадии разработки, и многие крупные интернет-компании не могут беспрепятственно получить доступ ко всей линейке приложений, и главная проблема заключается в размере пакета и динамизация.
Динамизация представляет собой более короткий путь онлайн-запроса, а это означает, что размер исходного пакета значительно сжат, тем самым увеличивая намерения пользователей загрузить, а также представляет собой более полную систему обслуживания качества онлайн. Когда мы понимаем эти значения, нам нетрудно понять, что, когда применение и адаптация Flutter приближаются к совершенству, динамизм, естественно, станет неизбежной темой. Зрелые технологии, такие как RN и Weex, даже заставляют людей думать, что динамизм является стандартом межсетевых технологий.
Команда Meituan Food Delivery MTFlutter исследует динамизм с сентября 2019 года и теперь запущена в нескольких бизнес-модулях с внутренним кодом проекта «Flap».
2. Особенности и преимущества Flap
Flap изначально разрабатывался как комплексное, а не переходное решение. Команда проекта подумала о наиболее болезненных моментах и перечислила их один за другим, а затем сделала конкретные выборки в соответствии с целями. На ранней стадии, только чем полнее будут рассмотрены потребности, тем яснее будет последующая архитектура и исследования и разработки. В процессе исследований и разработок команда должна придерживаться конечной цели, придерживаться первоначального намерения, продолжать преодолевать трудности и достигать целей, поставленных в прошлом.
2.1 Основные цели
- Универсальность, поддерживающая способность Flutter поддерживать несколько платформ без различий между платформами.
- Низкая стоимость, динамическое согласование с экологией Flutter и традиционными привычками разработки, а также возможность преобразования существующих страниц Flutter по низкой цене.
- Применимость во избежание дефектов, таких как негабаритные и нестабильные пакеты, которые не подходят для приложений.
- Высокая производительность при сохранении отличной производительности рендеринга Flutter.
2.2 Динамический выбор
а. Замена продукта
Первое рассмотрение в выборе - замена выданного продукта. Чиновник также запустил код Push Chush, который может даже поддерживать дифференциальную загрузку Diff, но он был остановлен в апреле 2019 года. Вот цитата из официального заявленияFlutter/issues/14330:
To comply with our understanding of store policies on Android and iOS, any solution would be limited to JIT code on Android and interpreted code on iOS. We are not confident that the performance characteristics of such a solution on iOS would reach the quality that we demand of our product. (In other words, "it would be too slow".)
There are some serious security concerns. Since these patches would essentially allow arbitrary code execution, they would be extremely attractive malware vectors. We could mitigate this by requiring that patches be signed using the same key as the original package, but this is error prone and any mistake would have serious consequences. This is, fundamentally, the same problem that has plagued platforms that allow execution of code from third-party sources. This problem could be mitigated by integrating with a platform update mechanism, but this defeats the purpose of an out-of-band patching mechanism.
Короче говоря, чиновник не уверен в динамических характеристиках и опасается безопасности. Ранее ограничения официального решения также были весьма очевидны. Например, он не подходит для поддержки гибридных приложений Native-Flutter и не может выполнять операции бизнес-настройки, такие как оттенки серого, поэтому он не может соответствовать основным целям универсальности и высокой производительности.
б. AOT с JIT
Flutter создает продукты, скомпилированные с помощью AOT, в режиме Release, для iOS используется сборка AOT, а для Android по умолчанию используется AOTBlob. В то же время Flutter также поддерживаетJIT Releaseрежим, который может динамически загружать моментальный снимок ядра или моментальный снимок App-JIT. Динамические возможности могут быть достигнуты, если JIT поддерживается в AOT. Но проблема в том, что виртуальная машина Dart, от которой зависит AOT, — это не то же самое, что JIT. environment) ); JIT Release не поддерживает устройства iOS, а построенное приложение нельзя опубликовать в AppStore.
Для реализации этого решения необходимо выделить независимую компиляцию DartVM, а затем импортировать проект в виде динамической библиотеки. В ходе предварительных тестов было обнаружено, что размер пакета будет увеличен на 20+ МБ, что превышает сумму предыдущих оптимизаций размера пакета Flutter, выполненных MTF Flutter. Это еще больше делает размер пакета Flutter огромным препятствием для продвижения и доступа к бизнес-стороне, что не соответствует нашим требованиям применимости.
c. Динамический производственный DSL
Сама нативная сторона имеет динамическую среду выполнения JS.Используя эту среду выполнения, он может динамически генерировать DSL, содержащий страницы и привязки логических событий, а затем анализировать его на страницы или компоненты Flutter, которые также могут выполнять динамические требования. Техническая идея близка к RN, но отличие заключается в использовании движка рендеринга Flutter и фреймворка. Этот метод, при котором сначала выполняется код, а затем получается DSL, для краткости называется динамическим производственным DSL.
Эта схема вполне может поддерживать логику в динамике, но и недостатки очевидны. Первое, что нужно сделать, это настроить структуру Flutter, объем разработки на стороне JS огромен, а опыт разработки поврежден. Кроме того, зависимость от JS велика, а сам построенный JS-фреймворк имеет определенные накладные расходы на интерпретацию и выполнение, а для логики страницы и событий частая межплатформенная связь между Flutter и JS также будет генерировать определенные накладные расходы. Это не соответствует высоким требованиям к производительности команды MTFlutter. Более того, это решение не соответствует привычкам разработки разработчиков.При замене Dart на JS существующие инструменты разработки Flutter нельзя использовать напрямую, что противоречит требованиям низкой стоимости.
г. Статическая производственная DSL
Как упоминалось ранее, «средство выполнения кода и последующего получения DSL называется динамическим производственным DSL», тогда код не выполняет DSL прямого преобразования, который называется схемой статического производственного DSL.
Особенность статического производства состоит в том, чтобы сгладить различия платформ, потому что входные данные являются исходным кодом Dart и не имеют ничего общего с платформой, напрямую преобразовать полную информацию в исходном коде Dart в DSL через слой преобразователей, а затем через статическое отображение Среда поддержки Native и Dart и базовой логики, позволяющая выполнять рендеринг и взаимодействовать в чистой среде Dart.
Что касается конкретной реализации, вы можете использовать библиотеку анализа Analyzer, официально предоставленную Dart-lang (этот инструмент используется в Dartfmt, Dart Doc и Dart Analyzer Server) для создания DSL. Библиотека предоставляет набор API для анализа исходного кода Dart и создания объектов AST в соответствии с гранулярностью файлов. Объект AST содержит всю информацию о файле Dart в аккуратной структуре данных, которую можно использовать для простого создания требуемого DSL.Весь этот анализ + процесс преобразования выполняется в автономном режиме.. Затем DSL-JSON выдается в виде Zip, и AOT-сторона Flutter использует его в качестве источника данных для завершения рендеринга и взаимодействия всего проекта Flutter.
Это решение может поддерживать опыт разработки Flutter / Dart, и нет разницы в платформе.Динамическая логика опирается на статическое сопоставление и поддержку базовой логики вместо JScore, что эффективно позволяет избежать накладных расходов на производительность. Подводя итог, статическая производственная DSL, наконец, стала решением для выбора команды MTFlutter.
2.3 Архитектура проекта
Как показано на рис. 1, три светло-зеленые части — это этапные продукты этапа, которые играют роль в связывании предыдущего и следующего. Принимая зеленую часть за границу, общая структура естественным образом делится на три области:
- Первая часть нижнего уровня — это расширение возможностей этапа разработки, а продукт — правильный и стандартизированный исходный код Dart (который также соответствует спецификации Flap).
- Вторая часть — конвертер DSL, продукт представляет собой DSL в формате JSON, который используется для стандартизированного описания иерархии и логики страниц.
- Третья часть верхнего уровня — это среда выполнения, которая подготавливает все необходимые символы для построения объектов и логики Dart, а продукт представляет собой динамическое приложение или динамический модуль.
3. Принципы и проблемы Flap
Основные модули на рис. 1 — это часть преобразователя и часть среды выполнения, а принципы и частичные реализации этих двух частей будут представлены далее.
3.1 Принцип работы преобразователя
AST & DSL
AST означает абстрактное синтаксическое дерево. AST Dart похож на базовые концепции AST в других языках. Все токены определены в package:front_end/src/scanner/token.dart, а AST также получен с помощью лексического анализа, синтаксического анализа и иерархического вложения. Объект ASTNode является базовой структурой данных для хранения важной информации в модуле компиляции, а производные классы в основном делятся на объявления, выражения, литералы и операторы.
DSL означает доменный язык. Представляет язык программирования или язык спецификаций, специализированный для конкретной предметной области. По сравнению с естественными языками языки программирования негибки, а их синтаксис и семантическое оформление часто зависят от среды его выполнения и конкретного назначения. В прошлом люди всегда изобретали новые языки программирования, а в последние годы новые языки становятся все более и более похожими, поэтому DSL также стали популярными.
Что такое DSL Flap? Для разработчиков этот DSL — это Dart Code. Для машин или приложений DSL — это JSON.
Как упоминалось в предыдущем техническом отборе:
Dart-lang официально предоставляет библиотеку анализа Analyzer. Официальные возможности Analyzer можно использовать напрямую. Библиотека предоставляет набор API-интерфейсов для анализа исходного кода Dart и создания объектов AST в соответствии с гранулярностью файла. Структура данных содержит входные данные. Все информация о файлах Dart.
Обоснованием нашего DSL является описание данных в AST с некоторыми дополнительными операциями.
Потому что AST, запускаемый Analyzer API, также называется CompilationUnit, который на самом деле является единицей компиляции, и в нем есть много атрибутов, связанных с компиляцией, таких как lineInfo, beginToken и т. д. Но использование DSL не зависит от компиляции, поэтому многие ненужные свойства обрезаются или игнорируются.
Основные классы (identifier, statementImpl, literal, methodInvocation и т. д.) распределяются по входу преобразователя, структура данных каждого основного класса передается с помощью модели промежуточной структуры Dart, а затем для подразделенных типов в основном классе (IfStatement , AssignmentStatement, DoStatement, SwitchStatement и т. д.) с достаточно детализированным интерфейсом преобразования, принимающим структуры AST в качестве входных данных и узлы Map в качестве выходных данных. Наконец, 10 стандартных структур Map (класс, метод, переменная, stmt и т. д.) определены и усовершенствованы для переноса всех типов.
Например
Простой узел Widget конвертируется для получения такого DSL-JSON, и вы можете видеть, что читаемость DSL в порядке (продукт представляет собой двоичный файл, сжатый в одну строку и зашифрованный по умолчанию, вот Формат после расшифровки и отображается разрыв строки). При преобразовании мы будем различать обычные строки, ссылки на имена переменных, системные перечисления и другие типы и выражать их разными символами.
о логике
На простом примере из четырех операций видно, что наш DSL может автоматически следовать правилу «умножение должно быть вычислено первым» Загадка в том, что Анализатор помогает нам судить о приоритете этой операции. , мы не будем делать процесс анализа на основе статического кода.
О синтаксическом сахаре
Синтаксический сахар, как правило, имеет четкий стиль и другую структуру, но в AST все еще очень честно, какая структура должна быть какой структурой. Поэтому синтаксический сахар следует развернуть в обычную структуру на стороне конвертера и затем преобразовать в DSL, вместо того, чтобы задавать специальный DSL для специального формата и передавать его на разбор рантайму.
Вот лишь несколько простых примеров, которые являются лишь фрагментом системы DSL.На самом деле, при реализации проекта существует гораздо более сложная логика, похожая на операцию set в циклическом цикле или добавление множественной тринокулярной логики в цикле. асинхронный обратный вызов и т.д. Из-за нехватки места и сопутствующих бизнес-кодов мы не будем подробно вводить его здесь.Принцип тот же.Некоторая специальная обработка добавляется в процессе описания AST, и, наконец, узел Map продукта конвертации будет преобразован в соответствии с исходный AST, иерархическая структура собирается, а затем конвертируется в JSON через JSONEncode.
Сторона преобразователя может полностью описать всю информацию файла Dart, как показано на рисунке 6. Стоит отметить, что разные узлы также могут иметь произвольную структуру, Аргументом в методе может быть глобальная переменная, а правая часть условного выражения может быть методом. Для преобразования этой же структуры, даже если она появляется в разных позициях, следует использовать набор логики обработки, поэтому преобразователь разработан с итерацией в качестве основной и рекурсией в небольшом диапазоне.
Разделите детализированные интерфейсы преобразования на разные файлы (statement_factory, class_factory, function_factory) в соответствии с конкретными категориями, ожидая разбора вызова производственной шины. В реальной работе вызовы между различными классами аналогичны сетке, поэтому все вызовы должны быть статическими и изолированными внутри, без ссылок или изменения внешних переменных, чтобы не было побочных эффектов.
Преобразователь DSL — это программа командной строки, поэтому ее можно легко развернуть на автоматизированных машинах. После того, как новый код будет объединен с транком, последующая логика генерации и распространения пакетов может управляться с использованием различных систем публикации с графическим интерфейсом.
3.2 Принципы выполнения
Prepare & Running
Операции, связанные с выполнением, выполняются внутри приложения, включая инициализацию, получение DSL, синтаксический анализ и использование. Короче говоря, его можно разделить на два этапа: подготовка и выполнение. Подготовка заключается в подготовке символов, необходимых для различных сред выполнения, включая символы системных классов и пользовательские символы, символы свойств и символы методов (упомянутые здесь символы на самом деле являются объектами в Dart). Только после завершения фазы «Подготовка» можно выполнять последующие операции, связанные с «Выполнением», в частности создание страниц, привязку событий и нормальную работу взаимодействия и логики.
Универсальный метод Function.apply()
Flutter ожидает, что онлайн-продукт будет «полным представлением» после компиляции, и не поддерживает Dart:Mirror, чтобы избежать создания слишком больших пакетов. «Приложения Flutter предварительно скомпилированы для производства, а размер двоичного файла всегда является проблемой для мобильных приложений, мы отключили dart:mirrors.» Итак, исходя из этой предпосылки, как преобразовать внешние символы во внутренние символы? Объект Function() предоставляет такой всеобъемлющий метод.
// function.dart
external static apply(Function function, List positionalArguments,
[Map<Symbol, dynamic> namedArguments]);
Первый параметр — это тип функции, а последние два параметра — это параметры, требуемые функцией (позиционные параметры и именованные параметры, оба из которых могут быть получены в DSL), поэтому, пока функция может быть получена, она может вызывать его в любое время.
Если эта функция является функцией-конструктором, возвращаемое значение представляет собой сконструированный тип объекта.
Proxy-Mirror
После DSL можно получить только идентификацию строки, поэтому необходимо установить отношение отображения между строкой и функцией.Учитывая имя класса и имя метода, структура данных должна быть {String:{String:Function}}, через два строковых ключа className и functionName. Можно получить однозначное соответствие Function(). Ниже приведен фрагмент кода метода класса (метода построения) системного класса:
{
'EdgeInsets':
{
'fromLTRB': (left, top, right, bottom) => EdgeInsets.fromLTRB(left, top, right, bottom),
// ...other function
},
// ...other class
};
Затем для метода экземпляра, геттера и сеттера системного класса необходимо передать извне еще один параметр экземпляра, и экземпляр передается после внешнего создания функции конструктора класса.
// instance method
"inflateSize": (instance, size) => instance.inflateSize(size),
// getter
"horizontal": (instance) => instance.horizontal,
// setter
"last": (List instance, dynamic value) => instance.last = value,
Custom Class's meta
Для пользовательских классов нам необходимо создать имитируемую систему метаклассов для хранения всей символической информации и преобразования всех узлов JSON в обрабатываемые объекты во время синтаксического анализа. Все объявления свойств построены как тип FlapVariable, а все объявления методов построены как тип FlapFunction.
Как показано на рисунке 8, родительский класс и метакласс также имеют соответствующие указатели, переменные-члены родительского класса также будут заполнены дочерним классом, а свойства, связанные с классом, вводятся в тип производного класса через миксин. например, FlapState, наследуемый от состояния, который может либо оставить отверстие в цепочке вызовов для методов жизненного цикла системного класса, либо использовать внедренные свойства класса среды выполнения.
Evaluate
Например, в следующем примере кода после выдачи узла JSON оператора if после прохождения через синтаксический анализатор будет получен объект IfStatement.Этот тип объекта имеет характеристику, состоящую в том, что он содержит несколько свойств и оценивает метод ввода во время выполнения. (Область охвата). Этот метод находится в абстрактном классе Оценочный класс. Все классы операторов и выражений будут наследоваться от него и автоматически получат метод оценки. Атрибутная часть передается через параметры конструктора после синтаксического анализа в объект Dart в процессе синтаксического анализа.
class IfStatement extends Statement {
dynamic condition = undefined;
Body thenBody;
Body elseBody;
IfStatement(this.condition, this.thenBody, [this.elseBody]);
// 简化版代码
ProcessResult evaluate(Scope scope) {
bool conditionValue = condition.evaluate(scope)
if (conditionValue){
return thenBody(Scope);
}else{
return elseBody(Scope);
}
}
}
Объект условия и объект оператора в атрибуте не будут инициированы во время процесса синтаксического анализа.Настоящий триггер — это когда метод вызывается из метода входа, оцениваемого во время выполнения, а затем область действия определяет, является ли условие истинным или ложным. а затем вызовите другие объекты Dart, которые необходимо оценить, как показано на рисунке 9 ниже:
После стекирования выражений реализуется оператор, тело реализуется через стек оператора, и добавляются формальные параметры и возвращаемое значение, что составляет пользовательский метод FlapFunction в нашей среде выполнения. Здесь используется концепция функции имитации.FlapFunction необходимо реализовать метод вызова, чтобы он действительно соответствовал стилю Function при внешнем вызове.
Когда динамическая страница запущена, Flap поддерживает систему областей видимости. Структура Scope эквивалентна двусвязному списку, и каждая Scope имеет два указателя, внешний и внутренний. Внешняя часть глобальной области равна нулю, а внутренняя — области класса; внутренняя область видимости класса — это локальная область; внутренняя область локальной области может быть нулевой или может быть локальной областью; в зависимости от того, какая область следует за внешней Посмотрите вверх, и вы обязательно найдете глобальный охват.
Scope
Scope на самом деле действует как контекст контекста при выполнении логики, потому что каждому методу или выражению требуется входной параметр Scope при его оценке.Этот Scope передается извне, и после выполнения этой строки объектов оператора Scope будет также передается в качестве аргумента следующей строке операторов. Например, первая строка оператора объявляет переменную «код», а вторая строка оператора изменяет «код», вам нужно сначала извлечь значение этого «кода» из области видимости по ссылке, а не только вы вынимаете объявленное значение из атрибутов Scope, вы также можете вынимать объявленный метод и вызывать метод внутри метода. Это также объясняет, почему мы можем обрабатывать логику в пользовательских методах.
На рис. 10 показаны два сценария Scope в действии. Левая половина - нажать кнопку, чтобы вызвать обратный вызов onTap. Вам нужно найти метод подтверждения. В это время вы сначала будете искать его в списке методов в локальной области. Если вы его не найдете, вы перейдет на внешний уровень для поиска области класса.В это время метод найден.реализация.
В правой половине показано, как конструируется Scope, который необходимо передать при выполнении тела метода. Сначала получить глобальные переменные и глобальные атрибуты из базы символов, чтобы сформировать глобальную область видимости, затем вынести атрибуты и методы из таких метаклассов, чтобы сформировать область видимости класса, а затем построить локальную область видимости, конечно, параметры также будут помещены в локальная область. Таким образом, создается полная область видимости и передается в метод оценки тела для поддержки последующего выполнения логики.
3.3 Возникшие проблемы
Большая работа требует длительного терпения
Прежде всего, объясните, что большая рабочая нагрузка здесь не относится к большой рабочей нагрузке ручной работы, такой как отображение системных методов, Все они генерируются автоматически и по запросу (упоминается в экологическом разделе). То, что мы подразумеваем под большой рабочей нагрузкой, в основном относится к разработке конвертеров, разработке во время выполнения и экологическому построению и т. Д. Нам нужно максимально удовлетворить весь синтаксис Dart, чтобы можно было конвертировать бизнес-коды с низкими затратами, и существует множество скриптов. , с поддержкой инструмента.
Проект сложный, и необходимо разработать разумную архитектуру для поддержки расширения.
При подмодульной разработке проекта каждый модуль (парсер, промежуточный, исполняющий и т. д.) строго соблюдает принцип единой ответственности и принцип наименьшего знания, что минимизирует связь между модулями, а связь между модулями осуществляется некоторыми стандартными структурами данных (картой или структурой, унаследованной от ASTNode). Это делает возможным, что любой крупный рефакторинг любого модуля не повлияет на другие модули.Одностороннее покрытие нескольких классов в базовом ядре близко к 100%, а за оптимизацию отвечает выделенный человек. А абстрактные классы, интерфейсные классы, миксин-классы и т.п. можно использовать везде в проекте, что делает читаемость проекта не обратно пропорционально возрастающей сложности поддерживаемых возможностей, а код не станет "отвратительным", при этом Он аккуратно расширен, и файлов много, но они не загромождены.
Есть много неизлечимых болезней, и сохраняйте достаточную уверенность в проблеме
Иногда бывают ситуации, например, когда область действия перезаписывается при вызове конструктора статическим методом, внешний оператор также останавливается после внутреннего продолжения, когда оператор цикла вложен, функция также будет выполняться после функции метода. указывается ссылка на параметр и т. д. Исправление ошибок – важная часть разработки. Иногда добавление if else и использование простого способа может решить проблему быстро, но мы этого делать не будем. Удовольствие от исследования элегантного правильного пути является важной частью процесса разработки.
По сравнению с «душевной» пыткой этого кода перед сном каждую ночь после неаккуратной работы, мы охотнее тратим больше времени на размышления о написании кода столь же «гладкого», как упаковка хоста Mac pro. Такая рабочая атмосфера культивирует уверенность каждого студента в том, что если это проблема, которая должна возникнуть, ее можно решить элегантно.
4. Экологическая поддержка
Хотя дизайн-концепция Flap дает ему определенные преимущества в эффективности разработки и эффективности исполнения, этого недостаточно для его быстрого продвижения в бизнесе. Поэтому мы создали полную экосистему Flap, охватывающую все этапы разработки, выпуска, тестирования, эксплуатации и обслуживания.
Как показано на рисунке 11, характеристики экологии Flap можно выразить четырьмя словами: стабильный, быстрый, точный и безжалостный.
4.1 Стабильный
Стабильный означает надежную систему управления качеством. У нас есть соответствующие стратегии для ① разработки IDE, ② этапа тестирования, ③ онлайн-мониторинга, ④ аварийного восстановления. Среди них ② и ③ в основном аналогичны PR-инспекции Native, QA, журналу, отчету и т. д., поэтому я не буду здесь вдаваться в подробности, я в основном упомяну ① и ④ ниже.
Плагин обнаружения синтаксиса IDE
Значение этой функции заключается в том, чтобы как можно скорее выявить неподдерживаемый синтаксис в виде ошибок компиляции, чтобы учащиеся могли вовремя обнаружить и изменить их в течение периода разработки. Представьте, что когда вы закончили писать код, Code Review ускользнул от глаз ваших одноклассников, а тест Dart на PR тоже пройден, и вы с радостью ушли с работы. неправильно, и некоторые грамматики не флап.Поддержка, нужно переделывать, чтобы внести изменения, в это время ваше сердце будет "скакать".
Поэтому мы заранее раскрываем этот временно неподдерживаемый синтаксис и рекомендуем, какой метод использовать вместо него, что может эффективно уменьшить количество переделок и получить код, соответствующий спецификациям Dart и Flap. Эти же правила обнаружения линта настраиваются и на этапе PR, если возникнет ситуация, когда правила плагина вовремя не обновятся, то они также будут заблокированы на этапе PR.
Однако существует очень мало грамматик, которые в настоящее время не поддерживает Flap.В настоящее время в основном существуют такие сценарии, как await, as и более 2 withs.Теория await и множественных withs также может поддерживаться, но проект будет иметь больший рефакторинг.Обработка его отдельно от нескольких мест не способствует последующему обслуживанию.Учитывая, что await можно заменить на future.then, этот синтаксис запрещен. Для особенностей миксина сама сторона Dart представляет собой отношения перестановки и комбинации. Более 2 с будет генерировать несколько производных классов, а динамическая реализация аналогична, поэтому чтобы не усложнять простую задачу, мы также отключаем метод записи более 2 с, и есть некоторые ограничения на метод записи, такие как так как импорт не использует полный путь также сообщит об ошибке.
В настоящее время динамизация Flap в разработке имеет общий бизнес-код с AOT.Чтобы правила Flap не влияли на страницы, которые не были динамически покрыты в проекте, и не допускали полноэкранной ошибки, мы используем аннотацию @Flap, чтобы откройте текущий переключатель A для определения спецификации Flap страницы. Это также очень понятно. Если на этой странице нет @Flap, это должен быть модуль AOT, но это все еще правило обнаружения Dart по умолчанию. После добавления @Flap('pageID') это означает, что эта страница будет быть динамически опубликованным, поэтому он будет автоматически включать правила обнаружения закрылков.
Понижение аварийного восстановления
Flap подключен к DD, единой динамической платформе публикации в Meituan, и использует возможности платформы DD для реализации детального контроля правил распространения, таких как версия приложения, тип платформы, UUID и версия Flutter SDK. Деловая сторона может выбрать различные схемы выпуска серой политики в соответствии с реальной ситуацией.Если происходит серьезная аномалия, Flap также поддерживает операцию изъятия пакета.
После того, как определенная страница помечена для поддержки динамизации, она будет продолжать выполнять компиляцию AOT и переход между двумя версиями. Нажатие на главную страницу для перехода на страницу AOT или страницу с заглушкой полностью контролируется параметрами в URL-адресе. не полностью контролируется Облако сначала отправляет URL-адрес по умолчанию в коде. Если его необходимо изменить на платформе конфигурации, отправленная информация о конфигурации приведет к замене URL-адреса на стороне маршрутизации. Даже если платформа конфигурации зависнет, в лучшем случае будет потеряна возможность замены URL вместо невозможности перехода на целевую страницу.
Существует также более острая функция для Flap.Во время переходного периода (когда Flap находится в сети и код AOT не был удален), как только во Flap возникает исключение Dart, когда пользователь выходит со страницы и входит снова, он автоматически войдет страницу Flutter AOT под идентификатором страницы. Минимизируйте неудобства для пользователей.
4.2 Быстро
Быстро, что означает быстрый выпуск, быстрое обновление. Динамическое преобразование Flap позволяет приложению иметь возможность динамического выпуска минутного уровня.Чтобы реализовать эту возможность более всесторонне, процесс бизнес-итерации на стороне клиента также был соответствующим образом скорректирован.
Когда бизнес-пакет выпущен, и когда приложение запущено, основной проблемой, с которой сталкивается Flap, становится баланс между гибкостью и качеством, то есть как обеспечить, чтобы динамический код мог вступить в силу как можно быстрее, и в то же время обеспечить производительность и стабильность загрузки.
Для этой проблемы решение Flap состоит в том, чтобы объединить кеш L2 и обновление в реальном времени.Онлайн-среда использует память + дисковый кеш L2.После входа на страницу пакет обновления предварительно загружается, чтобы сбалансировать производительность загрузки и обновление в реальном времени. . В автономной среде принудительно загружаются удаленные пакеты, чтобы обеспечить быструю доставку тестового кода.
Благодаря этому механизму Flap может достичь эффективности онлайн-доступа, близкой к Интернету: приложение инициирует запрос на обновление при запуске и при входе в конкретный бизнес. пользователь в следующий раз. достичь пользователей. Что касается производительности загрузки, время загрузки страницы при поддержке вторичного кеша составляет всего несколько десятков миллисекунд, а время удаленной загрузки составляет всего около 1 секунды.
4.3 Стандарт
Мелкозернистая динамизация
Точный, который относится к тому, где играть, он может быть динамическим на уровне страницы или динамическим на детальном уровне на уровне локального виджета. Фактически, в мире Flutter сама «страница» также является виджетом.В реальной разработке бизнес-стороне нужно только добавить строку аннотации, чтобы реализовать динамизацию соответствующего виджета или страницы.
@Flap('close_protect')
class CloseProtectWidget extends StatelessWidget {
// ...Widget 的 UI 和逻辑实现
}
Когда Flap упакован и выпущен, механизм синтаксического анализа запустится с виджетом, отмеченным аннотациями, рекурсивно проанализирует все зависимые файлы, преобразует их в соответствующий DSL и упакует. Когда приложение работает в сети, каждая динамическая страница или компонент будут восстановлены в соответствующий пользовательский интерфейс через FlapWidgetContainer в соответствии с аннотированным FlapId.
При фактическом вызове вам нужно только передать FlapId, отмеченный в аннотации, чтобы реализовать загрузку и визуализацию динамической области или страницы.
// 局部 Widget 级别的动态化,通过 FlapWidgetContainer 加载
Column(
children: <Widget>[
MyAOTWidget(), // 原生 Flutter AOT Widget
FlapWidgetContainer(widgetId: 'kangaroo_card'), // Flap widget
],
);
// 页面级别的动态化,通过 MTFlutterRoute 路由跳转:
RouteUtils.open('scheme://host/mtf?mtf_page=flap&flap_id=close_protect');
Возможность точной отладки
Добавьте аннотацию @Flap('pageId') на этапе отладки, и он автоматически попытается переключиться на DSL. Если страница очень самодостаточна и синтаксис не слишком причудлив, вы сможете сразу увидеть завершение преобразования. Это означает, что синтаксис, используемый на этой странице, поддерживает как Dart, так и Flap без каких-либо изменений. В случае ошибки точное местоположение ошибки будет распечатано под терминалом. До того, как эта функция была поддержана, это был в основном некий метод «свернуть, как только он рухнул» для системного класса, и разработчики могли искать в стеке только на основе собственного опыта. Текущие возможности точной отладки обеспечивают всесторонний охват трех этапов преобразователя, синтаксического анализатора среды выполнения и оценки времени выполнения.
Информация о местоположении ошибки на этапе преобразователя может быть получена непосредственно в Exception. Lineinfo объекта AST, а затем может быть получена информация о номере столбца и номере строки. Расположение ошибок в парсере и фазах оценки реализуется слой за слоем в соответствии с trycatch основного метода и настройкой общего типа исключения. Поскольку DSL-JSON будет сжат и может быть отформатирован, номер строки и номер столбца не имеют значения, поэтому все ошибки, сообщаемые на этапе выполнения, соответствуют методу в классе.
4.4 Безжалостный
Безжалостный, все виды автоматической генерации, фактические шаги преобразования просты и грубы. Flap обеспечивает удобную автоматизированную поддержку инструментов на протяжении всего итеративного процесса.
импорт загружается автоматически
Операция преобразования старой AOT-страницы Flutter в Flap-страницу на основе Flap проста и груба.С аннотациями одна строка терминальных команд может быть «челночной». Но бизнес-страница часто делится на несколько файлов для разумного дизайна, Если файлов 10, нужно ли повторять такую работу 10 раз? ответ отрицательный. Flap будет выполнять рекурсивную загрузку импорта, будь то на стороне преобразователя DSL или при загрузке DSL во время выполнения.
Плагин определения языка IDE имеет ограничение: при импорте должен использоваться полный путь к пакету, и он не может импортировать только имя класса. Поскольку местоположение, в которое необходимо импортировать несколько файлов, рассчитывается на основе относительного пути, перехваченного полным путем.
Прокси-зеркало генерируется по запросу
Как упоминалось ранее, Proxy-Mirror — это мост между внешними символами и внутренними символами.Так какие классы или методы в конкретных файлах Dart нуждаются во встроенном Proxy, а какие нет? Границей этого разделения является то, можно ли увидеть объявление этого класса или метода в преобразованном коде. Объявления системного метода точно нет в бизнес-файле, поэтому требуется Proxy. Декларация бизнес-модели находится в файле «Мой бизнес», поэтому прокси не требуется. В коде используется официальный Pub или Pub других бизнес-линий, например метод в Pub of Meituan Finance, который объявляет, что его нет в файле «Мой бизнес», поэтому требуется прокси.
На ранней стадии динамической миграции Flutter AOT проблема, часто требующая ручного вмешательства, заключается в следующем: отсутствие Proxy-Mirror в проекте будет прерывать работу конвертера, и его нужно дополнять вручную, а затем продолжать конвертацию.
Для такого рода проблем будет разработан прокси-сервер для автоматического создания инструментов по запросу.Основной принцип заключается в том, что на этапе предварительного преобразования сначала сканируйте дерево AST кода, выравнивайте уровень, чтобы получить значение, обернутое идентификатором. узла во всех структурах проекта и выполнить ряд правил суждения. , а затем на основеreflectableФункция реализует автоматическую генерацию Proxy.
Освободить ссылку «единого окна»
После непрерывной доработки и упрощения разработчики теперь могут сосредоточиться на этапе разработки.После того, как код будет интегрирован в магистраль, появится полная инженерная версия Flap и система хостинга, чтобы помочь разработчикам в последующей упаковке, выпуске, эксплуатации и обслуживании. Вся описанная выше детальная работа будет автоматизирована этими инструментами для удобной публикации. Flap также подключается к общим инструментам эксплуатации и обслуживания в группе на уровне маршрутизации, и разработчики могут отслеживать базовые показатели, такие как время загрузки, FPS и частота исключений, без каких-либо дополнительных операций. Для таких индикаторов, как колебания и аномальные увеличения, элементы сигналов тревоги также будут автоматически зарегистрированы и связаны с текущим пакером.
5. Практический опыт ведения бизнеса
Бизнес-лендинг — это только одна из наших целей.Что еще более важно, в процессе деловой практики мы находим проблемы с фреймворком, улучшаем поддержку различных грамматических особенностей, улучшаем совместимость в сложных смешанных сценариях и даем обратную связь, чтобы способствовать улучшению фреймворка. Постоянно совершенствуя рабочий процесс, обдумывайте и внедряйте лучшие практики, а также постепенно обобщайте разумный план отладки, этапы работы и методы совместной работы, а также постоянно повышайте эффективность и опыт разработки. Улучшите динамическую инфраструктуру и построение цепочки инструментов, завершите автоматизацию и разработку динамических процессов и еще больше сократите затраты на преобразование и разработку.
5.1 Сценарий применения
Для практики Flap в бизнесе в основном есть два сценария применения.
Сценарий 1. Исходную страницу Flutter необходимо преобразовать в динамическую страницу
Представьте, как должен выглядеть хороший динамический фреймворк в идеальном состоянии? Динамическая структура переписывает оригинальный Flutter в динамическую страницу? Просто добавьте аннотацию @Flap. Затем вы можете отправить код и автоматически получить набор инструментов.
В настоящее время, хотя и не в идеальном состоянии, мы также бесконечно близки, и, конечно, нам все еще нужно просто локально отлаживать. По сути, необходимо изменить такие шаги, как маршрутизация URL-адресов и фиктивная среда.Мы предоставили проект отладки шаблона, который поддерживает сравнение разницы между AOT и динамической операцией одним щелчком мыши, как показано на рисунке 18. По сути, это добавление аннотаций.Плагин IDE сообщит, какой синтаксис не поддерживается.Вам нужно изменить способ написания, затем запустить его, а затем отправить код.
Сценарий 2. Разработка новых страниц напрямую с использованием стека технологий Flap
Переработка сцены явно проще первой, потому что нет исторического багажа. Представьте, что должен делать хороший динамический фреймворк? Это использование той же среды IDE и того же режима разработки, что и разработка Flutter AOT, то есть IDE сообщит о еще нескольких синтаксических ошибках, и вам может быть напрямую предложено изменить метод записи во время разработки. Добавьте комментарии после написания, а затем отправьте код.
5.2 Практический опыт
В настоящее время наша команда реализовала динамические возможности Flutter в некоторых бизнес-сценариях.Конечно, в отрасли будут похожие или разные динамические решения. Независимо от самого плана, этапы реализации в основном одинаковы, и мы также обобщили некоторый опыт.
Обойти проблему и задокументировать ее
Возможности любого фреймворка на первых порах не идеальны, и будут проблемы. Студенты, изучающие бизнес, сталкиваются с относительно простыми проблемами, такими как отсутствие прокси-классов, которые можно решить напрямую.Глубокие проблемы в среде выполнения, некоторые синтаксические исключения в сложных сценариях наложения и т. д., как правило, сначала пытаются обойти их с помощью других синтаксисов. документ, а затем синхронизируйте его с товарищами по команде Flap, чтобы решить его.
Регулярно дополняйте правила для плагинов IDE
Добавляйте неподдерживаемые грамматики, ключевые слова и т. д. в правила подключаемых модулей IDE и предоставляйте альтернативы связанным грамматикам. Правила также будут регулярно дополнять и удалять их.
Знайте свои ресурсы заранее
Включая подтверждение ритма запуска Android, ритма тестирования QA и коэффициента охвата известной динамики PM.
Ужесточить управление ключевыми разрешениями
По сравнению с онлайн-СОП и часто задаваемыми вопросами, такими как разрешения сортировки, оттенки серого, переход на более раннюю версию, аварийное восстановление и т. д., пусть каждый учится работать и напрямую назначает 2–3 суперадминистраторов. Это кажется более надежным. «Лучше контролировать.
5.3 Результаты посадки
Бизнес-приложение охватывает несколько страниц, включая страницу первого уровня приложения. Сцена является динамической как на страницах, так и на частях, и выдержала проверку трафика страниц первого и второго уровня.
На рисунке 21 показаны мозаики с участием PV.Команда Flap насчитала 11 показателей, включая FPS, время загрузки, время загрузки бандла и время рендеринга.Видно, что средний FPS выше 58, а время рендеринга зависит от сложности на странице. Разница составляет от 7 до 96 мс.
В целом производительность каждого индикатора близка к собственной производительности Flutter. И данные на рисунке еще есть место для улучшения.На текущее среднее значение также влияет локальное плохое значение.В будущем будет использоваться иерархическая схема оптимизации в соответствии с различными квантилями TP.
6. Резюме и перспективы
Благодаря идее статической интерпретации и эксплуатации DSL+Runtime, мы реализовали динамическое решение Flutter, которое объединяет динамическое распределение и интерпретацию логических страниц, и построили набор экосистемы Flap, охватывающий разработку, выпуск, тестирование и эксплуатацию. и обслуживание. . В настоящее время Flap был реализован в нескольких бизнес-сценариях Meituan, что значительно сокращает требуемый путь выпуска и расширяет возможности устранения онлайн-проблем. Появление Flap в определенной степени компенсировало два недостатка динамики Flutter и размера упаковки, а также способствовало развитию экологии Flutter. Кроме того, несколько технических команд проявили большой интерес к Flap, и в настоящее время также осуществляется доступ Flap и совместное строительство в других сценариях.
В будущем мы и дальше будем улучшать возможности поддержки сложной грамматики и экологически безопасное построение, снижать стоимость разработки и преобразования Flap, улучшать опыт разработки, стремиться охватить больше бизнес-сценариев и активно изучать возможности совместного построения с деловыми сторонами. Затем, основываясь на интеграции большого внешнего интерфейса, изучите возможность открытия других технологических стеков и сглаживания различий между терминалами на основе Flap DSL.
использованная литература
- [1] Гилад Брача, Язык программирования Dart [M], Addison-Wesley Professional, 2015 г.
- [2] Code Push/Hot Update
- [3] Analyzer 0.39.10
- [4] Extension API
- [5] Технология ядра Flutter и реальный бой
- [6] App Store Review Guidelines
об авторе
- Шан Сянь, присоединившийся к Meituan в 2015 году, является техническим экспертом платформы Daojia R&D.
- Ян Чао, присоединившийся к Meituan в 2016 году, является старшим инженером на платформе исследований и разработок Daojia.
- Сун Тао, который присоединился к Meituan в 2018 году, является старшим инженером на платформе исследований и разработок Daojia.
Предложения о работе
Meituan Food Delivery уже давно набирает старших/старших инженеров и технических экспертов для Android, iOS, FE Добро пожаловать в семейство приложений для доставки еды. Заинтересованные студенты могут направить свои резюме по адресу:tech@meituan.com(Укажите в теме письма: Техническая команда по доставке еды Meituan)
Чтобы прочитать больше технических статей, отсканируйте код, чтобы подписаться на общедоступную учетную запись WeChat — техническая команда Meituan!