Generieren von Multi-Brand-Multi-Plattform-Symbolen mit Sketch und einem Node.js-Skript - Teil 2



Dies ist der zweite Teil eines Beitrags über die Erstellung einer Pipeline, die eine Skizzendatei aufnehmen und alle in der Datei enthaltenen Symbole in verschiedenen Formaten für verschiedene Plattformen exportieren kann, wobei AB die Möglichkeit bietet, jedes Symbol zu testen.

Den ersten Teil des Beitrags können Sie hier lesen.



Die Skizzendateien mit allen gesammelten, gestalteten und ordnungsgemäß benannten Symbolen waren fertig. Jetzt war es Zeit, den Code zu schreiben.

Es genügt zu sagen, dass der Prozess ein Versuch und Irrtum war: Nach dem wichtigen anfänglichen Code-Kern, der von meinem Teamleiter Nikhil Verma (der die Skriptgrundlagen legte) entwickelt wurde, durchlief ich einen inkrementellen Prozess, der mindestens drei Phasen des Refactorings erforderte und einige Überarbeitungen. Aus diesem Grund werde ich nicht zu sehr auf die Entwicklung des Skripts eingehen, sondern mich darauf konzentrieren, wie das Skript heute in seiner endgültigen Form funktioniert.

Das Build-Skript


Das in Node.js geschriebene Build-Skript ist in seinem Ablauf relativ einfach: Nach dem Importieren der Abhängigkeiten wurde die Liste der zu verarbeitenden Skizzendateien deklariert (als Liste der Marken und für jede Marke eine Liste der Dateien für diese Marke) und Wenn überprüft wurde, ob Sketch auf dem Client installiert ist, durchläuft das Skript das Markenarray und führt für jede dieser Marken die folgenden Schritte nacheinander aus:

  1. Holen Sie sich die Design-Token für die Marke (wir brauchen die Farbwerte)
  2. Klonen Sie die mit der Marke verknüpften Skizzendateien, entpacken Sie sie, um die internen JSON-Dateien verfügbar zu machen, und bearbeiten Sie einige der internen Werte dieser JSON-Dateien (dazu später mehr).
  3. Lesen Sie die relevanten Metadaten aus den Sketch JSON-Dateien ( document.json , meta.json und pages / pageUniqueID.json ). Insbesondere benötigen wir die Liste der freigegebenen Stile und die Liste der in den Dateien enthaltenen Assets / Symbole
  4. Nach einigen weiteren Manipulationen der Sketch JSON-Dateien komprimieren Sie sie zurück und exportieren und generieren Sie mithilfe der (geklonten und aktualisierten) Sketch-Dateien die endgültigen Ausgabedateien für die drei Plattformen (iOS, Android, Mobile Web).

Sie können die relevanten Teile des Haupt-Build-Skripts hier anzeigen:

// ... modules imports here const SKETCH_FILES = { badoo: ['icons_common'], blendr: ['icons_common', 'icons_blendr'], fiesta: ['icons_common', 'icons_fiesta'], hotornot: ['icons_common', 'icons_hotornot'], }; const SKETCH_FOLDER_PATH = path.resolve(__dirname, '../src/'); const SKETCH_TEMP_PATH = path.resolve(SKETCH_FOLDER_PATH, 'tmp'); const DESTINATION_PATH = path.resolve(__dirname, '../dist'); console.log('Build started...'); if (sketchtool.check()) { console.log(`Processing Sketch file via ${sketchtool.version()}`); build(); } else { console.info('You need Sketch installed to run this script'); process.exit(1); } // ---------------------------------------- function build() { // be sure to start with a blank slate del.sync([SKETCH_TEMP_PATH, DESTINATION_PATH]); // process all the brands declared in the list of Sketch files Object.keys(SKETCH_FILES).forEach(async (brand) => { // get the design tokens for the brand const brandTokens = getDesignTokens(brand); // prepare the Sketch files (unzipped) and get a list of them const sketchUnzipFolders = await prepareSketchFiles({ brand, sketchFileNames: SKETCH_FILES[brand], sketchFolder: SKETCH_FOLDER_PATH, sketchTempFolder: SKETCH_TEMP_PATH }); // get the Sketch metadata const sketchMetadata = getSketchMetadata(sketchUnzipFolders); const sketchDataSharedStyles = sketchMetadata.sharedStyles; const sketchDataAssets = sketchMetadata.assetsMetadata; generateAssetsPDF({ platform: 'ios', brand, brandTokens, sketchDataSharedStyles, sketchDataAssets }); generateAssetsSVGDynamicMobileWeb({ platform: 'mw', brand, brandTokens, sketchDataSharedStyles, sketchDataAssets }); generateAssetsVectorDrawableDynamicAndroid({ platform: 'android', brand, brandTokens, sketchDataSharedStyles, sketchDataAssets }); }); } 

Tatsächlich ist der gesamte Pipeline-Code viel komplexer als dieser, und die Komplexität liegt in den Funktionen prepareSketchFiles , getSketchMetadata und generateAssets [format] [platform] . Ich werde versuchen, sie weiter unten näher zu erläutern.

Vorbereiten der Skizzendateien


Der erste Schritt im Erstellungsprozess ist die Vorbereitung der Skizzendateien, damit sie später für den Export der Assets für die verschiedenen Plattformen verwendet werden können.

Die mit der Marke verknüpften Dateien - für Blendr beispielsweise die Dateien icons_common.sketch und icons_blendr.sketch - werden zunächst in einen temporären Ordner (genauer gesagt in einen Unterordner, der nach der Marke benannt ist, die verarbeitet wird) geklont und entpackt.

Anschließend werden die internen JSON-Dateien zu einem Präfix verarbeitet, das den Assets hinzugefügt wird, die AB-Tests unterzogen werden sollen, sodass sie beim Export in einem Unterordner mit einem vordefinierten Namen (dem eindeutigen Namen des Experiments) gespeichert werden. Um zu verstehen, welche Assets getestet werden sollen, überprüfen wir einfach, ob dem Namen der Seite, auf der sie in Sketch gespeichert sind, "XP_" vorangestellt ist.


Ein Vergleich der Ebenennamen in den Skizzendateien vor und nach dem Update.

Im obigen Beispiel werden die Assets beim Export im Unterordner "this__is_an_experiment" mit dem Dateinamen "icon-name [variantenname] .ext" gespeichert .

Lesen der Skizzenmetadaten


Der zweite wichtige Schritt in diesem Prozess besteht darin, alle relevanten Metadaten aus den Skizzendateien zu holen, insbesondere aus ihren internen JSON-Dateien. Wie oben erläutert, sind diese Dateien die beiden Hauptdateien ( document.json und meta.json ) und die Seitendateien ( pages / pageUniqueId.json ).

Die Datei document.json wird verwendet, um die Liste der freigegebenen Stile abzurufen , die unter der Objekteigenschaft layerStyles angezeigt werden:

 { "_class": "document", "do_objectID": "45D2DA82-B3F4-49D1-A886-9530678D71DC", "colorSpace": 1, ... "layerStyles": { "_class": "sharedStyleContainer", "objects": [ { "_class": "sharedStyle", "do_objectID": "9BC39AAD-CDE6-4698-8EA5-689C3C942DB4", "name": "features/feature-like", "value": { "_class": "style", "fills": [ { "_class": "fill", "isEnabled": true, "color": { "_class": "color", "alpha": 1, "blue": 0.10588235408067703, "green": 0.4000000059604645, "red": 1 }, "fillType": 0, "noiseIndex": 0, "noiseIntensity": 0, "patternFillType": 1, "patternTileScale": 1 } ], "blur": {...}, "startMarkerType": 0, "endMarkerType": 0, "miterLimit": 10, "windingRule": 1 } }, ... 

Für jeden Stil speichern wir einige grundlegende Informationen in einem Schlüsselwertobjekt. Dies wird später verwendet, wenn wir den Namen eines Stils basierend auf seiner eindeutigen ID abrufen müssen (in Sketch die Eigenschaft do_objectID ):

 const parsedSharedStyles = {}; parsedDocument.layerStyles.objects.forEach((object) => { parsedSharedStyles[object.do_objectID] = { name: object.name, isFill: _.get(object, 'value.fills[0].color') !== undefined, isBorder: _.get(object, 'value.borders[0].color') !== undefined, }; }); 


Zu diesem Zeitpunkt verschieben wir die Datei meta.json , um die Liste der Seiten abzurufen. Insbesondere benötigen wir deren eindeutige ID und Namen :

 { "commit": "623a23f2c4848acdbb1a38c2689e571eb73eb823", "pagesAndArtboards": { "EE6BE8D9-9FAD-4976-B0D8-AB33D2B5DBB7": { "name": "Icons", "artboards": { "3275987C-CE1B-4369-B789-06366EDA4C98": { "name": "badge-feature-like" }, "C6992142-8439-45E7-A346-FC35FA01440F": { "name": "badge-feature-crush" }, ... "7F58A1C4-D624-40E3-A8C6-6AF15FD0C32D": { "name": "tabbar-livestream" } ... } }, "ACF82F4E-4B92-4BE1-A31C-DDEB2E54D761": { "name": "XP_this__is_an_experiment", "artboards": { "31A812E8-D960-499F-A10F-C2006DDAEB65": { "name": "this__is_an_experiment/tabbar-livestream[variant1]" }, "20F03053-ED77-486B-9770-32E6BA73A0B8": { "name": "this__is_an_experiment/tabbar-livestream[variant2]" }, "801E65A4-3CC6-411B-B097-B1DBD33EC6CC": { "name": "this__is_an_experiment/tabbar-livestream[control]" } } }, 

Dann lesen wir für jede Seite die entsprechende JSON-Datei unter dem Seitenordner (wie bereits gesagt, der Dateiname lautet [pageUniqueId] .json ) und gehen die auf dieser Seite enthaltenen Assets durch (sie werden als Ebenen angezeigt ). Auf diese Weise erhalten wir für jedes Symbol seinen Namen, seine Breite / Höhe, die Sketch-Metadaten für dieses Ebenensymbol und, falls es sich auf einer Experimentierseite befindet, den Namen des betreffenden AB-Tests und den Namen der Variante für dieses Symbol.

Hinweis : Das Objekt "page.json" ist sehr komplex, daher werde ich hier nicht darauf eingehen. Wenn Sie neugierig sind und sehen möchten, wie es aussieht, empfehle ich Ihnen, eine neue, leere Skizzendatei zu erstellen, Inhalte hinzuzufügen und zu speichern. Benennen Sie dann die Erweiterung in zip um, entpacken Sie sie und sehen Sie sich eine der Dateien an, die im Ordner "pages" angezeigt werden.

Während der Verarbeitung der Zeichenflächen erstellen wir auch eine Liste von Experimenten (mit den entsprechenden Elementen), anhand derer später bestimmt wird, welche Symboloptionen und für welches Experiment verwendet werden, wobei der Name der Symboloptionen dem Objekt "Symbolbasis" zugeordnet wird.

Für jede verarbeitete Skizzendatei , die der Marke zugeordnet ist, erstellen wir ein AssetsMetadata- Objekt, das folgendermaßen aussieht:

 { "navigation-bar-edit": { "do_objectID": "86321895-37CE-4B3B-9AA6-6838BEDB0977", ...sketch_artboard_properties, "name": "navigation-bar-edit", "assetname": "navigation-bar-edit", "source": "icons_common", "width": 48, "height": 48 "layers": [ { "do_objectID": "A15FA03C-DEA6-4732-9F85-CA0412A57DF4", "name": "Path", ...sketch_layer_properties, "sharedStyleID": "6A3C0FEE-C8A3-4629-AC48-4FC6005796F5", "style": { ... "fills": [ { "_class": "fill", "isEnabled": true, "color": { "_class": "color", "alpha": 1, "blue": 0.8784313725490196, "green": 0.8784313725490196, "red": 0.8784313725490196 }, } ], "miterLimit": 10, "startMarkerType": 0, "windingRule": 1 }, }, ], ... }, "experiment-name/navigation-bar-edit[variant]": { "do_objectID": "00C0A829-D8ED-4E62-8346-E7EFBC04A7C7", ...sketch_artboard_properties, "name": "experiment-name/navigation-bar-edit[variant]", "assetname": "navigation-bar-edit", "source": "icons_common", "width": 48, "height": 48 ... 

Wie Sie sehen können, kann das gleiche "Symbol" (in diesem Fall die Bearbeitung der Navigationsleiste ) experimentell mit mehreren "Assets" verknüpft sein. Das gleiche Symbol kann jedoch mit demselben Namen in einer zweiten Skizzendatei angezeigt werden, die der Marke zugeordnet ist. Dies ist sehr nützlich: Es ist der Trick, den wir verwendet haben, um einen gemeinsamen Satz von Symbolen zu kompilieren und dann abhängig von der Marke.

Aus diesem Grund haben wir die mit der jeweiligen Marke verknüpften Skizzendateien als Array deklariert:

 const SKETCH_FILES = { badoo: ['icons_common'], blendr: ['icons_common', 'icons_blendr'], fiesta: ['icons_common', 'icons_fiesta'], hotornot: ['icons_common', 'icons_hotornot'], }; 

Denn in diesem Fall ist die Reihenfolge wichtig. Tatsächlich geben wir in der vom Erstellungsskript aufgerufenen Funktion getSketchMetadata die AssetsMetadata- Objekte (eines pro Datei) nicht als Liste zurück, sondern führen eine gründliche Zusammenführung jedes Objekts in das andere durch Gibt ein einzelnes zusammengeführtes AssetsMetadata- Objekt zurück.

Dies ist nichts anderes als die "logische" Zusammenführung der Skizzendateien und ihrer Assets zu einer einzigen Datei. Aber die Logik ist nicht so einfach, wie es aussieht. Hier ist das Schema, das wir erstellen mussten, um herauszufinden, was passiert, wenn Symbole mit demselben Namen (möglicherweise unter AB-Test) in verschiedenen Dateien vorhanden sind, die derselben Marke zugeordnet sind:


Das logische Schema, wie das "Überschreiben" desselben Symbols funktioniert, zwischen einer gemeinsamen Gruppe von Symbolen und Symbolen, die speziell für White-Labels entwickelt wurden (auch unter Berücksichtigung des AB-Tests).

Generieren der endgültigen Dateien in verschiedenen Formaten für verschiedene Plattformen


Der letzte Schritt des Prozesses ist die eigentliche Generierung der Symboldateien mit unterschiedlichen Formaten für die verschiedenen Plattformen (PDF für iOS, SVG / JSX für Web und VectorDrawable für Android).

Wie Sie an der Anzahl der Parameter sehen können, die an die Funktionen generateAssets [Format] [Plattform] übergeben wurden, ist dies der komplexeste Teil der Pipeline. Hier beginnt der Prozess, sich für die verschiedenen Plattformen zu teilen und auseinander zu gehen. Im Folgenden sehen Sie den vollständigen logischen Ablauf des Skripts und wie sich der Teil, der sich auf die Generierung der Assets bezieht, in drei ähnliche, aber nicht identische Abläufe aufteilt:



Um die endgültigen Assets mit den richtigen Farben zu generieren, die der zu verarbeitenden Marke zugeordnet sind, müssen wir eine weitere Reihe von Manipulationen an den Sketch JSON-Dateien vornehmen: Wir durchlaufen iterativ jede Ebene, auf die ein gemeinsamer Stil angewendet wurde, und ersetzen die Farbwerte mit den Farben aus den Design-Token für die Marke.

Für die Android-Generation ist eine zusätzliche Manipulation erforderlich (dazu später mehr): Wir ändern die Füllregeleigenschaft jeder Ebene von gerade-ungerade auf ungleich Null (dies wird durch die Eigenschaft "windingRule" im JSON-Objekt gesteuert, wobei " 1 "bedeutet" gerade-ungerade "und" 0 "bedeutet" nicht Null ").

Nach Abschluss dieser Manipulationen komprimieren wir die Sketch-JSON-Dateien wieder in eine Standard-Sketch-Datei, damit sie verarbeitet werden können, um die Assets mit den aktualisierten Eigenschaften zu exportieren (die geklonten und aktualisierten Dateien sind absolut normale Sketch-Dateien: Sie können in Sketch geöffnet werden , angezeigt, bearbeitet, gespeichert usw.).

Zu diesem Zeitpunkt können wir sketchtool ( in einem Node Wrapper ) verwenden, um automatisch alle Assets in bestimmten Formaten für bestimmte Plattformen zu exportieren. Für jede Datei, die einer Marke zugeordnet ist (genauer gesagt, ihre geklonte und aktualisierte Version), führen wir diesen Befehl aus:

 sketchtool.run(`export slices ${cloneSketchFile} --formats=svg <i>--scales=1 </i>--output=${destinationFolder} --overwriting`); 

Wie Sie vielleicht erraten haben, exportiert dieser Befehl die Assets in einem bestimmten Format unter Anwendung einer optionalen Skalierung (im Moment behalten wir immer die ursprüngliche Skalierung bei) in einen Zielordner. Die Option --overwriting ist hier von entscheidender Bedeutung: Auf die gleiche Weise, wie wir eine "Deep Merge" der AssetsMetadata-Objekte durchführen (was einer "logischen Zusammenführung" der Skizzendateien entspricht), erfolgt dies beim Exportieren aus mehreren Dateien in der gleiche Ordner (eindeutig pro Marke / Plattform). Dies bedeutet, dass ein Asset, das durch seinen Layernamen identifiziert wurde und bereits in einer vorherigen Skizzendatei vorhanden war, durch den folgenden Export überschrieben wird. Dies ist wiederum nichts anderes als eine "Zusammenführungs" -Operation.

In diesem Fall haben wir jedoch möglicherweise einige Assets, die "Geister" sind. Dies geschieht, wenn ein Symbol in einer Datei AB-getestet, in einer nachfolgenden Datei jedoch überschrieben wird. In solchen Fällen werden die Variantendateien in den Zielordner exportiert, auf den im AssetsMetadata- Objekt als Asset (mit seinem Schlüssel und seinen Eigenschaften) verwiesen wird , das jedoch keinem "Basis" -Asset zugeordnet ist (aufgrund der tiefen Zusammenführung der AssetsMetadata- Objekte). Diese Dateien werden in einem späteren Schritt vor Abschluss des Vorgangs entfernt.



Wie oben erwähnt, benötigen wir unterschiedliche Endformate für unterschiedliche Plattformen. Für iOS möchten wir PDF-Dateien und können diese direkt mit dem Befehl sketchtool exportieren . Für Mobile Web möchten wir JSX-Dateien und für Android VectorDrawable-Dateien. Aus diesem Grund exportieren wir die Assets im SVG-Format in einen Zwischenordner und unterziehen sie dann einer weiteren Verarbeitung.

PDF-Dateien für iOS


Seltsamerweise ist PDF das (einzige?) Format, das von Xcode und OS / iOS zum Importieren und Rendern von Vektor-Assets unterstützt wird ( hier eine kurze Erläuterung der technischen Gründe für diese Auswahl von Apple).

Da wir über Sketchtool direkt in PDF exportieren können, sind für diese Plattform keine zusätzlichen Schritte erforderlich: Wir speichern die Dateien einfach direkt im Zielordner, und das war's.

Reagieren / JSX-Dateien für das Web


Im Fall von Web verwenden wir eine Knotenbibliothek namens svgr , die einfache SVG-Dateien in React-Komponenten konvertiert. Aber wir wollen etwas noch Stärkeres tun: Wir wollen das Symbol zur Laufzeit "dynamisch malen", wobei die Farben von den Design-Token stammen. Aus diesem Grund ersetzen wir kurz vor der Konvertierung in der SVG die Füllwerte der Pfade, auf die ursprünglich ein gemeinsamer Stil angewendet wurde, durch den entsprechenden Tokenwert, der diesem Stil zugeordnet ist.

Wenn dies also die aus sketch exportierte Datei badge-feature-like.svg ist :

 <?xml version="1.0" encoding="UTF-8"?> <svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>" xmlns:xlink="<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>"> <!-- Generator: sketchtool 52.2 (67145) - <a href="http://www.bohemiancoding.com/sketch">http://www.bohemiancoding.com/sketch</a> --> <title>badge-feature-like</title> <desc>Created with sketchtool.</desc> <g id="Icons" fill="none" fill-rule="evenodd"> <g id="badge-feature-like"> <circle id="circle" fill="#E71032" cx="64" cy="64" r="64"> <path id="Shape" fill="#FFFFFF" d="M80.4061668,..."></path> </g> </g> </svg> 

Das endgültige Asset / Symbol von badge-feature-like.js sieht folgendermaßen aus:

 /* This file is generated automatically - DO NOT EDIT */ /* eslint-disable max-lines,max-len,camelcase */ const React = require('react'); module.exports = function badge_feature_like({ tokens }) { return ( <svg data-origin="pipeline" viewBox="0 0 128 128"> <g fill="none" fillRule="evenodd"> <circle fill={tokens.TOKEN_COLOR_FEATURE_LIKED_YOU} cx={64} cy={64} r={64} /> <path fill="#FFF" d="M80.4061668,..." /> </g> </svg> ); }; 

Wie Sie sehen können, haben wir den statischen Wert für die Füllfarbe des Kreises durch einen dynamischen Wert ersetzt, der seinen Wert aus den Entwurfstoken bezieht (diese werden der Komponente React <Icon /> über die Kontext-API zur Verfügung gestellt). aber das ist eine andere Geschichte).

Diese Ersetzung wird durch die Sketch-Metadaten für das im Assets-Metadatenobjekt gespeicherte Asset ermöglicht: Durch rekursives Durchlaufen der Layer des Assets kann ein DOM-Selektor erstellt werden (im obigen Fall wäre dies #Icons # badge-feature-). wie #circle ) und verwenden Sie es, um den Knoten im SVG-Baum zu finden und den Wert seines Füllattributs zu ersetzen (für diese Operation verwenden wir die Cheerio- Bibliothek).

VectorDrawable-Dateien für Android


Android unterstützt Vektorgrafiken mit seinem benutzerdefinierten Vektorformat namens VectorDrawable . Normalerweise wird die Konvertierung von SVG zu VectorDrawable von den Entwicklern direkt in Android Studio durchgeführt . Aber hier wollten wir den gesamten Prozess automatisieren, also mussten wir einen Weg finden, sie per Code zu konvertieren.

Nachdem wir uns verschiedene Bibliotheken und Tools angesehen hatten, entschieden wir uns für eine Bibliothek namens svg2vectordrawable . Es wird nicht nur aktiv gewartet (zumindest besser als die anderen, die wir gefunden haben), sondern es ist auch vollständiger.

Tatsache ist, dass VectorDrawable nicht mit SVG übereinstimmt: Einige der erweiterten Funktionen von SVG (z. B. radiale Farbverläufe, komplexe Masken usw.) werden nicht unterstützt , und einige von ihnen wurden erst kürzlich unterstützt (mit Android API 24 und höher). Ein Nachteil davon ist, dass in Android vor 24 die "gerade-ungerade" Füllregel nicht unterstützt wird . Aber bei Badoo müssen wir Android 5 und höher unterstützen. Aus diesem Grund müssen wir, wie oben erläutert, für Android jeden Pfad in den Skizzendateien in eine Füllung ungleich Null konvertieren.

Möglicherweise könnten die Designer dies manuell tun:



Dies kann jedoch leicht übersehen werden und ist daher anfällig für menschliches Versagen.

Aus diesem Grund haben wir einen zusätzlichen Schritt in unserem Prozess für Android hinzugefügt, in dem wir alle Pfade im Sketch JSON automatisch in einen Wert ungleich Null konvertieren. Dies bedeutet, dass die Symbole beim Exportieren in SVG bereits in diesem Format vorliegen und jedes generierte VectorDrawable auch mit Android 5-Geräten kompatibel ist.

Die endgültige Datei badge-feature-like.xml sieht in diesem Fall folgendermaßen aus:

 <!-- This file is generated automatically - DO NOT EDIT --> <vector xmlns:android="<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>" android:width="128dp" android:height="128dp" android:viewportWidth="128" android:viewportHeight="128"> <path android:fillColor="?color_feature_liked_you" android:pathData="M64 1a63 63 0 1 0 0 126A63 63 0 1 0 64 1z" /> <path android:fillColor="#FFFFFF" android:pathData="M80.406 ..." /> </vector> 

Wie Sie sehen können, fügen wir auch in den VectorDrawable-Dateien Variablennamen für die Füllfarben ein , die den Designtoken über benutzerdefinierte Stile in den Android-Anwendungen zugeordnet sind.

So sieht VectorDrawable nach dem Import in Android Studio aus:


Ein Beispiel für ein in Android Studio importiertes VectorDrawable-Symbol

Eines ist in diesem Fall zu beachten: Android Studio hat eine sehr strenge und vorgeschriebene Art der Organisation der Assets: kein verschachtelter Ordner und alle Namen in Kleinbuchstaben! Dies bedeutete, dass wir ein etwas anderes Format für die Namen ihrer Symbole entwickeln mussten: Im Fall eines zu testenden Assets lautet sein Name so etwas wie ic_icon-name__experiment-name__variant-name .

JSON-Wörterbuch als Assets-Bibliothek


Sobald die Asset-Dateien in ihrem endgültigen Format gespeichert sind, müssen Sie als letztes alle während des Erstellungsprozesses gesammelten Metainformationen speichern und in einem "Wörterbuch" speichern, damit sie später verfügbar gemacht werden können wenn die Assets von der Codebasis der verschiedenen Plattformen importiert und verwendet werden.

Nachdem wir die flache Liste der Symbole aus dem AssetsMetadata- Objekt extrahiert haben, durchlaufen wir sie und überprüfen sie für jedes Element:

  • Wenn es sich um ein normales Asset handelt (z. B. Tabbar-Livestream ), und wenn dies der Fall ist, behalten wir es einfach bei.
  • Wenn es sich um eine Variante in einem AB-Test handelt (z. B. Experiment / Tabbar-Livestream [Variante] ), ordnen wir den Namen, den Pfad, den AB-Test und die Variantennamen den Eigenschaftsabtests des "Basis" -Assets zu (in diesem Fall tabbar-). Livestream ), und dann entfernen wir den Varianteneintrag aus der Liste / dem Objekt (nur die "Basis" zählt);
  • Wenn es sich um eine "Ghost" -Variante handelt, löschen wir die Datei und entfernen den Eintrag aus der Liste / dem Objekt.

Sobald die Schleife abgeschlossen ist, enthält das Wörterbuch die Liste aller und nur der "Basis" -Symbole (und ihrer AB-Tests, falls experimentiert). Für jedes dieser Elemente enthält es seinen Namen, seine Größe, seinen Pfad und, falls sich ein Symbol im AB-Test befindet, die Informationen zu den verschiedenen Optionen des Assets.

Dieses Wörterbuch wird dann im JSON-Format im Zielordner für die Marke und die Plattform gespeichert. Hier ist zum Beispiel die Datei resources.json , die für die Anwendung "Blendr" im "mobilen Web" generiert wurde:

 { "platform": "mw", "brand": "blendr", "assets": { "badge-feature-like": { "assetname": "badge-feature-like", "path": "assets/badge-feature-like.jsx", "width": 64, "height": 64, "source": "icons_common" }, "navigation-bar-edit": { "assetname": "navigation-bar-edit", "path": "assets/navigation-bar-edit.jsx", "width": 48, "height": 48, "source": "icons_common" }, "tabbar-livestream": { "assetname": "tabbar-livestream", "path": "assets/tabbar-livestream.jsx", "width": 128, "height": 128, "source": "icons_blendr", "abtest": { "this__is_an_experiment": { "control": "assets/this__is_an_experiment/tabbar-livestream__control.jsx", "variant1": "assets/this__is_an_experiment/tabbar-livestream__variant1.jsx", "variant2": "assets/this__is_an_experiment/tabbar-livestream__variant2.jsx" }, "a_second-experiment": { "control": "assets/a_second-experiment/tabbar-livestream__control.jsx", "variantA": "assets/a_second-experiment/tabbar-livestream__variantA.jsx" } } }, ... } } 

Der allerletzte Schritt besteht darin, alle Assets- Ordner in zu komprimieren. Zip- Dateien, damit sie einfacher heruntergeladen werden können.

Das Endergebnis


Der oben beschriebene Prozess - vom anfänglichen Klonen und Bearbeiten der Skizzendateien über den Export (und die Konvertierung) der Assets in dem für jede unterstützte Plattform gewünschten Format bis zur Speicherung der gesammelten Metainformationen in einer Asset-Bibliothek - ist wird für jede im Build-Skript deklarierte Marke wiederholt.

Unten sehen Sie einen Screenshot, wie die Struktur der Ordner src und dist nach Abschluss des Erstellungsprozesses aussieht:


Struktur der Ordner "src" und "dist" nach Abschluss des Erstellungsprozesses.

Zu diesem Zeitpunkt ist es mit einem einfachen Befehl möglich, alle Ressourcen (JSON-Dateien, ZIP-Dateien und Assets-Dateien) in ein Remote-Repository hochzuladen und für alle verschiedenen Plattformen verfügbar zu machen, um sie in ihren Codebasen herunterzuladen und zu verwenden.

(Wie die tatsächlichen Plattformen die Assets abrufen und verarbeiten - über benutzerdefinierte Skripte, die zu diesem Zweck ad-hoc erstellt wurden -, geht über den Rahmen dieses Artikels hinaus. Dies wird jedoch wahrscheinlich sehr bald in anderen speziellen Blog-Posts von einem der Autoren behandelt andere Entwickler, die mit mir an diesem Projekt gearbeitet haben).

Schlussfolgerungen (und dabei gewonnene Erkenntnisse)


Ich habe Sketch immer geliebt. Seit Jahren ist es das "De-facto" -Tool der Wahl für das Web- und App-Design (und die Entwicklung). Daher war ich sehr interessiert und neugierig, mögliche Integrationen wie HTML-Sketchapp oder ähnliche Tools zu untersuchen, die wir in unseren Workflows und Pipelines verwenden konnten.

Dieser (ideale) Fluss war für mich ( und viele andere ) immer der heilige Gral :



Skizze als Entwurfswerkzeug kann als mögliches "Ziel" der Codebasis vorgestellt werden.

Aber ich muss zugeben, dass ich mich kürzlich gefragt habe, ob Sketch immer noch das richtige Werkzeug ist, insbesondere im Kontext eines Design-Systems. Also begann ich, neue Tools wie Figma mit seinen offenen APIs und Framer X mit seiner unglaublichen Integration in React zu erkunden, da ich keine gleichwertigen Bemühungen von Sketch sah, auf die Integration mit Code (welcher Code auch immer) hinzuarbeiten .

Nun, dieses Projekt hat meine Meinung geändert. Nicht ganz, aber definitiv viel.

Vielleicht macht Sketch seine APIs nicht offiziell verfügbar, aber die Art und Weise, wie sie die interne Struktur ihrer Dateien erstellt haben, ist sicherlich eine Art "inoffizielle" API. Sie könnten kryptische Namen verwendet oder die Schlüssel in den JSON-Objekten verschleiert haben. Stattdessen haben sie sich für eine klare, leicht lesbare, für Menschen lesbare, semantische Namenskonvention entschieden. Ich kann nicht denken, dass dies nur ein Zufall ist.

Die Tatsache, dass Skizzendateien manipuliert werden können, hat mir eine Vielzahl möglicher zukünftiger Entwicklungen und Verbesserungen eröffnet. Von Plugins zur Validierung der Benennung, des Stils und der Struktur der Ebenen für die Symbole über mögliche Integrationen in unser Wiki und unsere Designsystemdokumentation (in beide Richtungen) bis hin zur Erstellung von Node-Apps, die in Electron oder Carlo gehostet werden, um viele der Funktionen zu vereinfachen sich wiederholende Aufgaben, die die Designer übernehmen müssen.

Ein unerwarteter Bonus dieses Projekts (zumindest für mich) ist, dass die Skizzendateien mit den "Cosmos-Symbolen" jetzt zu einer "Quelle der Wahrheit" geworden sind, ähnlich wie dies mit dem Cosmos- Designsystem geschehen ist . Wenn ein Symbol nicht vorhanden ist, ist es nicht in der Codebasis vorhanden (oder besser, es sollte nicht vorhanden sein: aber zumindest wissen wir, dass es eine Ausnahme ist). Ich weiß, dass es jetzt ziemlich offensichtlich ist, aber es war nicht vorher, zumindest für mich.

Was als MVP-Projekt begann, tauchte bald (buchstäblich) tief in die Interna von Sketch-Dateien ein, mit der Erkenntnis, dass diese manipuliert werden können. Wir wissen noch nicht, wohin das alles führen wird, aber bisher war es ein Erfolg. Designer, Entwickler, PMs und Stakeholder sind sich einig, dass dies viel manuelle Arbeit für alle erspart und viele potenzielle Fehler verhindert. Es öffnet aber auch die Türen für die Verwendung der bisher unmöglichen Symbole.

Eine letzte Sache: Was ich in diesem langen Beitrag beschrieben habe, ist eine Pipeline, die wir hier erstellt haben, um unsere speziellen Probleme zu lösen, und die daher notwendigerweise für unseren Kontext besonders angepasst ist. Beachten Sie, dass es möglicherweise nicht Ihren geschäftlichen Anforderungen entspricht oder für Ihren Kontext geeignet ist.

Aber was mir wichtig ist und was ich teilen wollte, ist, dass es getan werden kann. Möglicherweise auf unterschiedliche Weise, mit unterschiedlichen Ansätzen und unterschiedlichen Ausgabeformaten, möglicherweise mit geringerer Komplexität (d. H. Möglicherweise benötigen Sie das Multi-Branding und die AB-Tests nicht). Jetzt können Sie den Workflow für die Bereitstellung Ihrer Symbole mit einem benutzerdefinierten Node.js-Skript und einer Skizze automatisieren.

Finden Sie Ihren eigenen Weg, es zu tun. Es macht Spaß (und ist relativ einfach).

Credits


Dieses riesige Projekt wurde in Zusammenarbeit mit Nikhil Verma (Mobile Web) entwickelt, der die erste Version des Build-Skripts erstellt hat, und Artem Rudoi (Android) und Igor Savelev (iOS), der die Skripte entwickelt hat, mit denen die Assets importiert und verwendet werden jeweilige native Plattformen. Vielen Dank, Leute, es war eine tolle Zeit, mit Ihnen an diesem Projekt zu arbeiten und zu beobachten, wie es zum Leben erweckt wird.

Source: https://habr.com/ru/post/de441042/


All Articles