Экспортируем иконки из Figma в проект одним кликом: история одной автоматизации

Абсолютно стандартное начало: в Figma размещался набор из примерно тысячи иконок, которые успешно перенесли в проект. Все собрали, потестили и зарелизили. Про автоматизацию никто не думал, поскольку задача казалась «одноразовой». Ну, а в случае последующих обновлений или дополнений каких-то элементов ручной труд должен был занять несколько минут. Что тут может пойти не так?

Далее рассказ про знакомый всем «человеческий фактор», плюс краткий гайд по автоматизированному экспорту картинок из Figma в рабочий проект.

40c84fe7b72d92cca087d11ed617ff6c.png

Итак, дано: приложения под iOS и Android с большим набором иконок, который постоянно обновляется и дополняется стараниями нашей команды дизайнеров. Выглядел этот набор примерно так:

Так выглядит часть нашего набора иконок в Figma

Так выглядит часть нашего набора иконок в Figma

Частота внесения изменений небольшая — примерно пару раз в месяц что-то там менялось. Вроде бы ничего особенного, но в какой-то момент проблемы стали накапливаться.

Проблема №1 — расплодившиеся дубли

По мере расширения набора функций у приложения требовались новые иконки. Разработчик, который реализовывал ту или иную фичу, в какой-то момент обнаруживал, что нужные иконки в интерфейсе не появлялись. Он залезал в Фигму, пролистывал таблицу, находил там нужную иконку, копировал её себе, затем переводил из формата SVG в VectorDrawable, задавал имя файла и закидывал в проект.

В этот момент другой разработчик, реализующий другую функцию, также обнаруживал отсутствие иконки и повторял все вышеописанные действия. Разумеется, есть прописанные правила именования файлов, которым все следуют, но, когда у тебя их тысяча, да ещё в разных форматах и размерах, периодически что-то идёт не так.  

Проблема №2 — иконки оказывались не того формата и размера

В Figma иконки хранились как компоненты. Но обязательно находился тот, кто по ошибке раскрывал компонент и обнаруживал внутри поле Icon. Затем загружал себе этот самый Icon, который по размеру немного отличался от размера компонента. Если не присматриваться, на первый взгляд всё было нормально. Однако в отдельных местах интерфейс начинал «плыть». И это не всегда удавалось заметить сразу.

Это сам компонент (иконка), который надо загрузить

Это сам компонент (иконка), который надо загрузить

Но некоторые кликали на поле Icon и загружали себе данные из него. Размеры оказывались немного другими

Но некоторые кликали на поле Icon и загружали себе данные из него. Размеры оказывались немного другими

Проблема №3 — когда начинают фиксить в коде

Раз интерфейс «поплыл», а иконка была загружена правильная, и в других местах с ней все было как бы нормально, разработчик принимал решение поджать её в коде в конкретном месте, где возникала проблема.

Это копилось ровно до того момента, пока не начиналось ревью. А на нём всплывало всё и сразу. И кто-то потом сидел и распутывал весь клубок, удивляясь, как же коллеги могли нагородить такого. Поэтому настало время всё сделать по-человечески — автоматизировать.

От полного хаоса к нажатию одной кнопки

Автоматизация должна была решить сразу несколько задач: создать единую систему имён файлов, выгружать и конвертировать в нужный формат полный набор иконок (VectorDrawable для Android и PDF для iOS), затем закидывать их в проект, заменяя существующие и удаляя ненужные. Осталось только написать нужный скрипт.

Для начала предстояло выбрать язык. После обсуждения доступного инструментария остановились на следующих вариантах:

— написать скрипт на Bash;

— каждая команда пишет скрипт для своей ОС;

— кроссплатформенное решение на Kotlin.

Первый вариант отбросили, поскольку Bash это дополнительный язык, который нужно знать, чтобы поддерживать решение. Писать свой скрипт под каждую платформу — это умножать разработку на два. А вот вариант на Kotlin нам показался перспективным, поскольку Kotlin — родной язык для Android-разработчиков, вдобавок он имеет много сходств со Swift, который используют iOS-разработчики.

Так сложилось, что мой опыт разработки был связан с UI-kit, поэтому задачка попала ко мне. 

Было два варианта экспорта, и я выбрал не тот

Потратив немного времени на изучения Figma API, кристаллизовались два пути, которыми можно было экспортировать данные для дальнейшей обработки. Первый — выгрузить всю иерархию элементов файла, распарсить и получить нужные данные. Второй — работать с компонентами из файла напрямую.

Изначально показалось, что первый способ даст на выходе больше информации, с которой будет удобнее работать. Я создал скрипт, который отлично проработал несколько дней. За это время я успел собрать немного лучей славы от благодарных коллег, но потом случилось то, что когда-то должно было произойти. Дизайнеры в макете Figma в одном месте перегруппировали иконки и что-то переименовали. После чего скрипт перестал нормально работать. По факту изменилась структура данных, а за ней и иерархия файла. Пришлось идти и обновлять скрипт выгрузки.

Решить данную проблему можно двумя способами. Договориться с дизайнерами, чтобы они ничего не меняли в структуре, хранили иконки в нужной иерархии и не нарушали её. Или выгружать иконки как компоненты.

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

В итоге схема стала такой: получаем список компонентов, берём их айдишники, затем получаем список файлов для скачивания и выгружаем, а с помощью системы контроля версий студия подсвечивает нам новые, удаленные и изменившиеся. Далее преобразуем в нужный формат и загружаем в проект.

Краткая пошаговая инструкция по выгрузке данных

У Figma есть подробное описание API. Но для более быстрого ознакомления с ним покажу в общих чертах, как выглядит процесс настройки экспорта.

1. Первым шагом нужно сгенерить access token на сайте figma api. Для этого надо перейти на figma.com/developers/api#authentication и нажать Get personal access token

591b8c1c4a42fadb6e26ced9b4c9e870.png

2. Узнать file id нашего комплекта изображений. Его можно взять из адреса страницы

В данном примере это символьный код Oi7UQTF4GAvdfYtK2FV771MY между слэшами

В данном примере это символьный код Oi7UQTF4GAvdfYtK2FV771MY между слэшами

3. Чтобы получить компоненты, необходимо выполнить запрос GET/v1/files/:file_key/components, где :file_key — ключ из адреса веб-страницы нашей библиотеки изображений в Figma.

В ответ на запрос мы получим данные в следующем формате:

{
  "status": Number,
  "error": Boolean,
  "meta": {
    "components": [
    	{
     	"key": String,
     	"file_key": String,
     	"node_id": String,
     	"thumbnail_url": String,
     	"name": String,
     	"description": String,
     	"updated_at": String,
     	"created_at": String,
     	"user": User,
     	"containing_frame": FrameInfo,
    	},
    	...
    ],
   },
}

Здесь нас интересуют поля в meta.components:

node_id — это id компонента

name — название компонента

containing_frame — информацию о фрейме, в котором лежит иконка

4. Из всей этой информации мы забираем название фрейма. Затем формируем следующий запрос:

 »https://api.figma.com/v1/images/$fileId?ids=$keys&format=$format&use_absolute_bounds=true»

Где fileId — тот же ключ библиотеки с иконками

keys — наши node_id, необходимые для выгрузки

format — тут можно указать svg, pdf, jpg или png

use_absolute_bounds — этот флаг нужен для того, чтобы Figma не обрезала заложенные дизайнерами отступы

В ответ получаем пару «ключ — значение», где ключ — это ID компонента, а значением будет URL самой картинки для выгрузки. Затем по полученным URL выгружаем наши изображения.

Конвертацию из svg в VectorDrawable выполняем с помощью com.android.ide.common.vectordrawable.Svg2Vector из библиотеки com.android.tools.sdk-common. Пример вызова метода конвертации выглядит так: Svg2Vector.parseSvgToXml(Path, OutputStream). Для iOS никаких дополнительных действий делать не нужно, поскольку данные выгружаются в формате pdf, с которыми разработчики работают напрямую.

Что получили в итоге

Во-первых, понимание того, что об автоматизации лучше задумываться как можно раньше и закладывать на неё время. В нашем случае, с учетом изучения API и первоначального прохождения по ложному пути, ушло около пяти рабочих дней. Возможно, оно ещё не компенсировалось экономией времени на разборе хаоса и ручной выгрузке, однако мы получили полный порядок в данных и отсутствие необходимости постоянного выяснения что и почему отображается не так.

Во-вторых, избавление от рутины, которая нагружает голову и не даёт сосредоточиться на более важных вещах. Ведь нажать одну кнопку и через 30 секунд продолжить текущую работу — это не то же самое, что открыть несколько приложений, внимательно смотреть что и откуда брать, во что конвертировать и куда потом положить. Подобные рутинные операции частенько выбивают из потока, что по факту отнимает ещё время, требующееся для возвращения к текущей задаче.

Так что, если у вас возникнет необходимость в экспорте из Figma, можно смело браться за автоматизацию. Ничего сложного в ней нет. Важно лишь помнить, что выгружая иерархию файла для дальнейшей обработки, придётся следить за изначальной целостностью структуры. Или сразу переходить к варианту покомпонентного экспорта.

© Habrahabr.ru