
这是关于创建管道的第二部分,该管道可以获取Sketch文件并针对不同平台以不同格式导出文件中包含的所有图标,并可能由AB测试每个图标。
您可以在
此处阅读帖子的第一部分。

收集了所有图标,样式并正确命名的Sketch文件已准备就绪。 现在该开始编写代码了。
可以说,这个过程是一个反复试验的过程:在重要的初始代码核心(由我的团队负责人
Nikhil Verma (奠定了脚本基础)开发)之后,我经历了一个增量过程,该过程至少需要三个重构阶段以及许多修订。 因此,我不会过多地讨论脚本的开发方式,而是将重点放在最终形式的脚本今天的工作方式上。
构建脚本
用Node.js编写的构建脚本在流程中相对简单:导入依赖项后,声明要处理的Sketch文件列表(作为品牌列表,对于每个品牌来说都是该品牌的文件列表),检查客户端上是否安装了Sketch,脚本在品牌阵列上循环,并且对于其中的每个脚本,它依次执行以下步骤:
- 获取品牌的设计令牌(我们需要颜色值)
- 克隆与品牌相关联的Sketch文件,解压缩它们以显示内部JSON文件,并操纵这些JSON文件的一些内部值(稍后会详细介绍)
- 从Sketch JSON文件( document.json , meta.json和pages / pageUniqueID.json )中读取相关的元数据; 特别是我们需要共享样式的列表以及文件中包含的资产/图标的列表
- 在对Sketch JSON文件进行进一步处理之后,将它们压缩回去,并使用(克隆和更新的)Sketch文件,为三个平台(iOS,Android,Mobile Web)导出并生成最终输出文件
您可以在此处查看主要构建脚本的相关部分:
// ... 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 }); }); }
实际上,整个管道代码要比这复杂得多,而复杂性在于
prepareSketchFiles ,
getSketchMetadata和
generateAssets [format] [platform]函数。 我将在下面尝试更详细地解释它们。
准备草图文件
构建过程的第一步是准备Sketch文件,以便以后可以将其用于导出不同平台的资产。
与品牌相关的文件(例如,对于Blendr,例如,文件
icons_common.sketch和
icons_blendr.sketch )首先克隆到一个临时文件夹(更确切地说,在正在处理的品牌命名的子文件夹中)并解压缩。
然后,内部JSON文件将被处理,并添加到要进行AB测试的资产中的前缀,以便在导出时将它们保存在具有预定义名称(实验的唯一名称)的子文件夹中。 为了了解要测试的资产,我们只需检查在Sketch中存储资产的页面名称是否以
“ XP_”为前缀。
更新前后在Sketch文件中的图层名称的比较。在上面的示例中,导出时,资产将以文件名
“ icon-name [variant-name] .ext”保存在子文件夹
“ this__is_an_experiment”中 。
读取草图元数据
该过程的第二个重要步骤是从Sketch文件中获取所有相关的元数据,特别是从其内部JSON文件中获取。 如上所述,这些文件是两个主要文件(
document.json和
meta.json )和页面文件(
pages / pageUniqueId.json )。
document.json文件用于获取共享样式的列表,该列表显示在
layerStyles对象属性下:
{ "_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 } }, ...
对于每种样式,我们将一些基本信息存储在键值对象中。 每当我们需要根据样式的唯一ID(在Sketch中,
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, }; });
此时,我们继续执行
meta.json文件以获取页面列表,特别是我们需要它们的
唯一ID和
名称 :
{ "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]" } } },
然后,对于每个页面,我们都会读取
pages文件夹下的相应JSON文件(
如前所述 ,文件名是
[pageUniqueId] .json ),然后浏览该页面中包含的资产(它们显示为图层)。 这样,对于每个图标,我们都可以得到其名称,宽度/高度,该图层图标的Sketch元数据,如果在实验页面上,则可以得到相关AB测试的名称以及变体的名称该图标。
注意 :“ page.json”对象非常复杂,因此在此不再赘述。 如果您想知道它的外观,建议您创建一个新的空白Sketch文件,在其中添加一些内容,然后保存; 然后以zip重命名其扩展名,解压缩并查看出现在“页面”文件夹下的文件之一。
在处理画板时,我们还创建了一个实验列表(及其相应的资产),这些列表稍后将用于确定使用了哪些图标选项以及针对哪个实验,将图标选项的名称与“图标库”对象相关联。
对于与该品牌相关联的每个正在处理的Sketch文件,我们产生一个
如下的assetMetadata对象:
{ "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 ...
如您所见,就实验而言,相同的“图标”(在本例中为
Navigation-bar-edit )可以具有多个与之关联的“资产”。 但是,相同的图标可以在与该品牌相关的第二个Sketch文件中以相同的名称出现,这非常有用:这是我们使用的技巧,可以编译一组通用的图标,然后根据不同的图标定义不同的图标变体。品牌。
这就是为什么我们将与每个特定品牌关联的Sketch文件声明为数组的原因:
const SKETCH_FILES = { badoo: ['icons_common'], blendr: ['icons_common', 'icons_blendr'], fiesta: ['icons_common', 'icons_fiesta'], hotornot: ['icons_common', 'icons_hotornot'], };
因为在这种情况下顺序很重要。 实际上,在构建脚本调用的
getSketchMetadata函数中,我们没有将
assetsMetadata对象(每个文件一个)作为列表返回,而是对每个对象进行了深层合并,然后将它们合并到另一个中,然后我们返回单个合并的
assetMetadata对象。
这无非就是将Sketch文件及其资产“逻辑”合并到一个文件中。 但是逻辑实际上并不像看起来那么简单。 这是我们必须创建的模式,以弄清楚在与同一品牌相关联的不同文件中存在具有相同名称(可能经过AB测试)的图标时会发生什么情况:
在一组通用/共享的图标和专为白色标签设计的图标之间,表示相同图标“覆盖”工作原理的逻辑模式(还考虑了AB测试的情况)为不同平台生成不同格式的最终文件
该过程的最后一步是针对不同平台(适用于iOS的PDF,适用于Web的SVG / JSX和适用于Android的VectorDrawable)以不同格式实际生成图标文件。
从传递给函数
generateAssets [格式] [平台]的参数数量中可以看出,这是管道中最复杂的部分。 这是针对不同平台
的过程开始分裂的地方。 参见下面的脚本的完整逻辑流程,以及与资产生成相关的部分如何
分成三个相似但不相同的流程:
为了生成具有与所处理品牌相关的正确颜色的最终资产,我们需要对Sketch JSON文件进行另一组操作:我们迭代遍历应用了共享样式的每个图层,并替换颜色值以及品牌设计标记中的颜色。
对于Android世代,需要进行额外的操作(稍后再介绍):我们将每个图层的fill-rule属性从
奇偶更改
为非零 (这由JSON对象中的“ windingRule”属性控制,其中“ 1个“均值”为“奇数”,“ 0个”均值为“非零”)。
完成这些操作后,我们将Sketch JSON文件压缩回标准的Sketch文件中,以便可以对其进行处理以导出具有更新属性的资产(克隆和更新的文件绝对是普通的Sketch文件:可以在Sketch中打开它们,查看,编辑,保存等)。
在这一点上,我们可以使用sketchtool(
在节点包装器中 )为特定平台自动以特定格式导出所有资产。 对于与品牌相关的每个文件(更准确地说,是其克隆和更新的版本),我们运行以下命令:
sketchtool.run(`export slices ${cloneSketchFile} --formats=svg <i>--scales=1 </i>--output=${destinationFolder} --overwriting`);
您可能会猜到,此命令将特定格式的资产导出,并应用可选的缩放比例(目前我们始终保持原始比例)到目标文件夹中。
--overwrite选项在这里很关键:就像我们对assetsMetadata对象进行“深度合并”(相当于Sketch文件的“逻辑合并”)一样,在导出时,我们将多个文件导入到相同的文件夹(每个品牌/平台唯一)。 这意味着,如果以图层名称标识的资产已经存在于先前的Sketch文件中,则该资产将被后续的导出覆盖。 同样,这仅是“合并”操作。
但是,在这种情况下,我们可能会有一些“鬼魂”资产。 当图标在文件中经过AB测试,但在后续文件中被覆盖时,会发生这种情况。 在这种情况下,变体文件将导出到目标文件夹中,在
assessMetadata对象中作为资产(及其键和属性)进行引用,但不与任何“基础”资产关联(由于
assessMetadata对象的深度合并)。 在完成该过程之前,将在以后的步骤中删除这些文件。
如上所述,对于不同的平台,我们需要不同的最终格式。 对于iOS,我们需要PDF文件,我们可以使用
sketchtool命令直接将其
导出 。 而对于Mobile Web,我们需要JSX文件;对于Android,我们需要VectorDrawable文件。 因此,我们将SVG格式的资产导出到中间文件夹中,然后对其进行进一步处理。
适用于iOS的PDF文件
奇怪的是,PDF是Xcode和OS / iOS支持的(唯一?)格式,用于导入和呈现矢量资产(
这是 Apple做出此选择背后的技术原因
的简短说明 )。
由于我们可以通过Sketchtool直接以PDF格式导出,因此该平台无需采取其他步骤:我们只需将文件直接保存在目标文件夹中即可。
Web的React / JSX文件
对于Web,我们使用一个名为
svgr的Node库,
它将普通的SVG文件转换为React组件。 但是我们想做些更强大的事情:我们希望在运行时“动态绘制”图标,其颜色来自设计标记。 因此,在转换之前,我们在SVG中将最初应用共享样式的路径的
填充值替换为与该样式相关联的相应令牌值。
因此,如果这是从Sketch导出的
badge-feature-like.svg文件:
<?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>
最终的
badge-feature-like.js资产/图标将如下所示:
/* 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> ); };
如您所见,我们将圆形的
填充色的静态值替换为动态值,该值从设计标记中获取了动态值(这些标记将通过Context API提供给React
<Icon />组件,但这是另一个故事)。
通过
资产元数据对象中存储的
资产的Sketch元数据可以实现此替换:在资产层中递归循环,可以创建DOM选择器(在上述情况下,将是
#Icons#badge-feature-像#circle ),并使用它在SVG树中查找节点,并替换其
fill属性的值(对于此操作,我们使用
cheerio库)。
Android的VectorDrawable文件
Android使用其自定义矢量格式(称为
VectorDrawable)支持矢量图形。 通常,由开发人员
直接在Android Studio中完成从SVG到VectorDrawable的转换。 但是这里我们想使整个过程自动化,因此我们需要找到一种通过代码转换它们的方法。
在查看了不同的库和工具之后,我们决定使用一个名为
svg2vectordrawable的库。 它不仅得到了积极的维护(至少比我们发现的要好),而且也更加完善。
事实是,VectorDrawable与SVG的功能并不相同:不支持SVG的某些高级功能(例如,径向渐变,复杂蒙版等),而其中一些仅在最近才获得支持(使用Android API 24和更高)。 这样做的一个缺点是,在Android 24之前
的版本中,不支持“奇数”填充规则 。 但是在Badoo,我们需要支持Android 5及更高版本。 这就是如上所述的原因,对于Android,我们需要将Sketch文件中的每个路径转换为“非零”填充。
潜在地,设计人员可以手动执行此操作:

但这很容易被忽视,因此容易发生人为错误。
因此,我们在Android流程中增加了一个额外步骤,即在Sketch JSON中将所有路径自动转换
为非零 。 这样,当我们将图标导出到SVG时,它们已经采用这种格式,并且生成的每个VectorDrawable也与Android 5设备兼容。
在这种情况下,最终的
badge-feature-like.xml文件如下所示:
<!-- 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>
如您所见,同样在VectorDrawable文件中,我们为
填充颜色注入了变量名称,这些变量名称通过Android应用程序中的自定义样式与设计标记相关联。
这是将VectorDrawable导入Android Studio后的样子:
导入到Android Studio中的VectorDrawable图标的示例在这种情况下要注意的一件事:Android Studio具有一种非常严格和规范的组织资产的方式:没有嵌套的文件夹和所有小写名称! 这意味着我们必须为它们的图标名称使用略有不同的格式:对于正在实验的资产,其名称将类似于
ic_icon-name__experiment-name__variant-name 。
JSON字典作为资产库
一旦资产文件以其最终格式保存,最后要做的就是保存在构建过程中收集的所有元信息,并将其存储在“字典”中,以便以后可以使用当资产由不同平台的代码库导入和使用时。
从
assetsMetadata对象中提取图标的平面列表后,我们对其进行循环,并针对每个项目进行检查:
- 如果是正常资产(例如tabbar-livestream ),如果是,我们就保留它;
- 如果它是AB测试中的变体(例如实验/ tabbar-livestream [variant] ),我们会将其名称,路径,AB测试和变体名称与“基础”资产的属性abtests (在这种情况下,为tabbar- livestream ),然后从列表/对象中删除变体条目(仅“基本”计数);
- 如果是“ ghost”变体,我们将删除文件,然后从列表/对象中删除条目。
循环完成后,词典将仅包含所有“基本”图标的列表(以及处于实验状态的AB测试)。 对于其中的每一个,它将包含其名称,大小,路径,并且如果图标在AB测试中,则还包含有关资产不同选项的信息。
然后,该词典以JSON格式保存在
品牌和
平台的目标文件夹中。 例如,这是为“移动网络”上的“ Blendr”应用程序生成的
assets.json文件:
{ "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" } } }, ... } }
最后一步是压缩所有
资产文件夹。
zip文件,以便可以更轻松地下载它们。
最终结果
上述过程-从初始克隆和操作Sketch文件到以每个受支持平台所需的格式导出(和转换)资产,再到将所收集的元信息存储在资产库中-对构建脚本中声明的每个品牌重复此操作。
下面是构建过程完成后
src和
dist文件夹的结构的屏幕截图:
构建过程完成后,“ src”和“ dist”文件夹的结构。此时,只需一个简单的命令,就可以将所有资源(JSON文件,ZIP文件和资产文件)上传到远程存储库,并使它们可用于所有各种平台,以在其代码库中下载和使用。
(实际的平台如何(通过为此目的临时构建的自定义脚本来检索和处理资产)不在本文讨论范围之内。但是,在其中一篇专门的博客文章中,很可能很快就会涉及到这一点。与我一起从事此项目的其他开发人员)。
结论(以及在此过程中学到的教训)
我一直很喜欢
Sketch 。 多年来,它一直是Web和应用程序设计(和开发)的首选“事实”工具。 因此,我对探索可能的集成(例如
html-sketchapp或类似工具,我们可以在我们的工作流和管道中使用)非常感兴趣并且好奇。
这种(理想的)流程一直是
我 (
以及许多其他人 )的
圣杯 :

可以将Sketch作为设计工具想象为代码库的可能“目标”。
但是我不得不承认,最近我开始怀疑Sketch是否仍然是正确的工具,尤其是在设计系统的情况下。 因此,我开始探索新工具,例如具有开放API的
Figma和与React令人难以置信的集成的
Framer X ,因为我没有看到Sketch朝着与代码(无论是哪种代码)集成的同等努力。
好吧,这个项目改变了我的想法。 并不完全,但是绝对很多。
Sketch可能没有正式公开其API,但是可以肯定的是,他们构建文件内部结构的方式是一种“非官方” API。 他们可能使用了隐秘的名称,或者混淆了JSON对象中的密钥; 取而代之的是,他们选择了清晰,易读,易于理解的语义命名约定。 我不能认为这仅仅是偶然的。
Sketch文件可以被操纵的事实为我打开了很多可能的未来发展和改进的思路。 从用于验证图标各层的命名,样式和结构的插件,到与我们的Wiki和我们的设计系统文档的可能集成(双向),通过在
Electron或
Carlo中托管的Node应用程序的创建,以促进许多设计师必须承担的重复性任务。
这个项目的意外收获(至少对我而言)是,现在带有“ Cosmos图标”的Sketch文件已经成为“真相的来源”,类似于
Cosmos设计系统所发生的情况。 如果图标不存在,则它在代码库中不存在(或者更好,它不应该存在:但至少我们知道这是一个例外)。 我知道现在看起来很明显,但这不是以前,至少对我而言。
最初从MVP项目开始,很快就深入到了Sketch文件的内部,并意识到可以对它们进行操作。 我们还不知道所有这一切将导致什么,但是到目前为止,它已经取得了成功。 设计人员,开发人员,项目经理和利益相关者都同意,这将为每个人节省大量的人工工作,并避免了很多潜在的错误。 但是,这也将打开使用图标的大门,而这些图标到目前为止是不可能的。
最后一件事:在这篇长篇文章中,我描述的是我们在此处构建的用于解决特定问题的管道,因此它必须针对
我们的情况进行超级定制。 请记住,它可能不适合
您的业务需求或不适合
您的环境。
但是对我来说重要的是,我想分享的是可以做到的。 可能以不同的方式,不同的方法和不同的输出格式,可能涉及的复杂性更低(即:您可能不需要多品牌和AB测试)。 但是现在,您可以使用自定义Node.js脚本和Sketch来自动化交付图标所需的工作流程。
找到自己的方式。 很好玩(而且相对容易)。
学分
这个庞大的项目是与创建了构建脚本的第一个版本的
Nikhil Verma (移动网络),
Artem Rudoi (Android)和
Igor Savelev (iOS)共同开发的,后者开发了用于导入和使用其资产的脚本。各自的本机平台。 谢谢大家,这是与您一起完成这个项目并观看它变成现实的过程。