
هذا هو الجزء الثاني من منشور حول إنشاء خط أنابيب يمكن أن يأخذ ملف Sketch وتصدير جميع الرموز المدرجة في الملف ، بتنسيقات مختلفة ، لأنظمة تشغيل مختلفة ، مع إمكانية اختبار AB لكل رمز.
يمكنك قراءة الجزء الأول من المنشور
هنا .

كانت ملفات Sketch ، مع جميع الرموز التي تم جمعها وتصميمها وتسميتها بشكل صحيح ، جاهزة. الآن حان الوقت لبدء كتابة الكود.
يكفي القول ، إن العملية كانت إلى حد كبير تجربة وخطأ: بعد مجموعة التعليمات البرمجية الأولية المهمة ، التي طورها فريقي الرائد
نيخيل فيرما (الذي وضع أسس البرنامج النصي) ، مررت بعملية تدريجية تطلبت على الأقل ثلاث مراحل من إعادة البناء. وعدد لا بأس به من التنقيحات. لهذا السبب ، لن أخوض في الكثير من التفاصيل حول كيفية تطوير البرنامج النصي ، لكنني أركز على كيفية عمل البرنامج النصي اليوم ، بشكله النهائي.
بناء السيناريو
النص البرمجي للبناء - المكتوب في Node.js - واضح نسبيًا في التدفق: بمجرد استيراد التبعيات ، أعلن قائمة ملفات Sketch المراد معالجتها (كقائمة من العلامات التجارية ، ولكل علامة تجارية قائمة ملفات لهذه العلامة التجارية) و تأكد من تثبيت Sketch على العميل ، ويقوم البرنامج النصي بحفظ مجموعة من العلامات التجارية ، ولكل واحدة من هذه الخطوات يتم تنفيذ هذه الخطوات بالتسلسل:
- احصل على الرموز المميزة للعلامة التجارية (نحتاج إلى قيم الألوان)
- استنساخ ملفات Sketch المرتبطة بالعلامة التجارية ، وقم بفك ضغطها لفضح ملفات JSON الداخلية ، ومعالجة بعض القيم الداخلية لملفات JSON هذه (المزيد حول هذا لاحقًا)
- اقرأ البيانات الوصفية ذات الصلة من ملفات Sketch JSON ( document.json و meta.json والصفحات / 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 }); }); }
في الواقع ، رمز خط الأنابيب بالكامل أكثر تعقيدًا من هذا ، والتعقيد يكمن في
وظائف preparSketchFiles و
getSketchMetadata و
createAssets [format] [platform] . سأحاول شرحهم بمزيد من التفاصيل أدناه.
تحضير ملفات Sketch
الخطوة الأولى في عملية الإنشاء هي إعداد ملفات Sketch ، بحيث يمكن استخدامها لاحقًا لتصدير الأصول للأنظمة الأساسية المختلفة.
الملفات المرتبطة بالعلامة التجارية - بالنسبة إلى Blendr ، على سبيل المثال ،
icons_common.sketch و
icons_blendr.sketch - يتم استنساخها في البداية في مجلد مؤقت (بشكل أكثر دقة ، في مجلد فرعي يحمل اسم العلامة التجارية التي تتم معالجتها) ثم فك ضغطها.
ثم تتم معالجة ملفات JSON الداخلية ، إلى بادئة تضاف إلى الأصول التي ستخضع لاختبار AB ، بحيث يتم حفظها عند تصديرها في مجلد فرعي باسم محدد مسبقًا (الاسم الفريد للتجربة). لفهم الأصول التي يتم اختبارها ، نحن ببساطة نتحقق مما إذا كان اسم الصفحة المخزنة في Sketch مسبوقًا بـ
"XP_" .
مقارنة بين أسماء الطبقات ، داخل ملفات Sketch ، قبل التحديث وبعده.في المثال أعلاه ، عندما يتم تصدير الأصول ، سيتم حفظ الأصول في المجلد الفرعي
"this__is_an_experiment" ، مع اسم الملف
" اسم
الرمز [variant-name] .ext" .
قراءة البيانات الوصفية للرسم
تتمثل الخطوة المهمة الثانية في العملية في إخراج جميع بيانات التعريف ذات الصلة من ملفات 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 } }, ...
لكل نمط ، نقوم بتخزين بعض المعلومات الأساسية في كائن قيمة المفتاح. سيتم استخدام هذا لاحقًا كلما احتجنا لاسترداد اسم النمط استنادًا إلى
معرفه الفريد (في 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 للحصول على قائمة الصفحات ، ولا سيما نحتاج إلى
معرّفها الفريد واسمها :
{ "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]" } } },
ثم ، لكل صفحة نقرأ ملف JSON المقابل ضمن مجلد
الصفحات (كما سبق ذكره ، اسم الملف هو
[pageUniqueId] .json ) ، ونحن نذهب إلى الأصول الموجودة في تلك الصفحة (تظهر كطبقات). وبهذه الطريقة ، لكل رمز نحصل عليه ، عرضه / ارتفاعه ، بيانات تعريف Sketch لأيقونة الطبقة ، وإذا كان موجودًا على صفحة التجربة ، اسم اختبار AB المعني ، واسم المتغير لهذا الرمز.
إشعار : الكائن "page.json" معقد للغاية ، لذلك لن أخوض فيه هنا. إذا كنت فضوليًا وترغب في رؤية شكله ، أقترح عليك إنشاء ملف رسم جديد وفارغ وإضافة محتوى فيه وحفظه ؛ ثم أعد تسمية امتداده في zip ، وقم بفك ضغطه والنظر في أحد الملفات التي تظهر ضمن مجلد "الصفحات".
أثناء معالجة اللوحات الفنية ، نقوم أيضًا بإنشاء قائمة بالتجارب (مع أصولها المقابلة) التي سيتم استخدامها لاحقًا لتحديد خيارات الأيقونات المستخدمة ولأي تجربة ، يتم ربط اسم خيارات الأيقونة بالكائن "icon icon".
لكل ملف Sketch قيد المعالجة مرتبط بالعلامة التجارية ، ننتج كائن بيانات
تعريفية للممتلكات يشبه هذا:
{ "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 ...
كما ترون ، يمكن أن تحتوي "الأيقونة" نفسها (في هذه الحالة
، شريط التنقل ) على "أصول" متعددة مرتبطة بها ، من حيث التجارب. ولكن يمكن أن يظهر الرمز نفسه بنفس الاسم في ملف رسم ثانٍ مرتبط بالعلامة التجارية ، وهذا مفيد للغاية: إنها الحيلة التي استخدمناها ، لتجميع مجموعة مشتركة من الرموز ثم تحديد أشكال مختلفة من الرموز المختلفة بناءً على العلامة التجارية.
لهذا السبب أعلنا ملفات Sketch المرتبطة بكل علامة تجارية معينة كصفيف:
const SKETCH_FILES = { badoo: ['icons_common'], blendr: ['icons_common', 'icons_blendr'], fiesta: ['icons_common', 'icons_fiesta'], hotornot: ['icons_common', 'icons_hotornot'], };
لأنه في هذه الحالة يهم الأمر. وفي الواقع ، في الدالة
getSketchMetadata ، التي يطلق عليها البرنامج النصي للبناء ، لا
نرجع كائنات
الأصول Metadata (واحد لكل ملف) كقائمة ، بل نؤدي إلى دمج عميق لكل كائن ، واحد في الآخر ، ثم إرجاع كائن
الأصولMetadata المدمج واحد.
هذا ليس أكثر من الدمج "المنطقي" لملفات Sketch وأصولها في ملف واحد. لكن المنطق ليس في الواقع بسيطًا كما يبدو. في ما يلي المخطط الذي كان يتعين علينا إنشاؤه لمعرفة ما يحدث عندما تكون هناك أيقونات تحمل نفس الاسم (ربما تحت اختبار AB) في ملفات مختلفة مرتبطة بنفس العلامة التجارية:
المخطط المنطقي لكيفية عمل "تجاوز" نفس الأيقونة ، بين مجموعة مشتركة / مشتركة من الرموز والرموز المصممة خصيصًا للعلامات البيضاء (مع الأخذ في الاعتبار أيضًا حالة اختبار AB)إنشاء الملفات النهائية بتنسيقات مختلفة للأنظمة الأساسية المختلفة
الخطوة الأخيرة من العملية هي إنشاء ملفات الرموز فعليًا بتنسيقات مختلفة للأنظمة الأساسية المختلفة (PDF لـ iOS و SVG / JSX للويب و VectorDrawable لنظام Android).
كما ترون من خلال عدد المعلمات التي تم تمريرها إلى الوظائف التي
تنشئ مجموعات [تنسيق] [النظام الأساسي] ، فإن هذا هو الجزء الأكثر تعقيدًا من خط الأنابيب. هنا
تبدأ العملية في الانقسام والاختلاف بين الأنظمة الأساسية المختلفة. انظر أدناه التدفق المنطقي الكامل للبرنامج النصي ، وكيف
ينقسم الجزء المتعلق بتوليد الأصول
في ثلاثة تدفقات متشابهة ولكن غير متطابقة:
من أجل توليد الأصول النهائية بالألوان الصحيحة المرتبطة بالعلامة التجارية التي تتم معالجتها ، نحتاج إلى القيام بمجموعة أخرى من المعالجات على ملفات Sketch JSON: نحن نكرر التكرار على كل طبقة لها نمط مشترك مطبق ، واستبدال قيم اللون مع الألوان من الرموز المميزة للعلامة التجارية.
بالنسبة إلى نظام أندرويد ، هناك حاجة إلى معالجة إضافية (المزيد حول هذا لاحقًا): نقوم بتغيير خاصية تعبئة قاعدة كل طبقة من
الغريب إلى
غير الصفري (يتم التحكم في هذا بواسطة خاصية "windingRule" في كائن JSON ، حيث " 1 تعني كلمة "زوجي فردي" و "0" تعني "غير صفري").
بعد الانتهاء من هذه العمليات ، نقوم بضغط ملفات Sketch JSON مرة أخرى في ملف Sketch قياسي ، بحيث يمكن معالجتها لتصدير الأصول مع الخصائص المحدثة (الملفات المستنسخة والمحدثة هي ملفات Sketch عادية للغاية: يمكن فتحها في Sketch ، عرض ، تحرير ، حفظ ، الخ).
في هذه المرحلة ، يمكننا استخدام sketchtool (
في غلاف عقدة ) لتصدير جميع الأصول تلقائيًا بتنسيقات محددة لمنصات معينة. لكل ملف مرتبط بعلامة تجارية (بشكل صحيح ، نسخته المستنسخة والمحدثة) نقوم بتشغيل هذا الأمر:
sketchtool.run(`export slices ${cloneSketchFile} --formats=svg <i>--scales=1 </i>--output=${destinationFolder} --overwriting`);
كما تعتقد ، يقوم هذا الأمر بتصدير الأصول بتنسيق معين ، مع تطبيق تحجيم اختياري (في الوقت الحالي ، نحافظ دائمًا على المقياس الأصلي) ، في مجلد وجهة. خيار -
الكتابة هو المفتاح هنا: بنفس الطريقة التي نقوم بها "دمج عميق" للكائنات الأصول البيانات الوصفية (التي ترقى إلى "دمج منطقي" لملفات Sketch) ، عندما نقوم بتصدير نقوم به من ملفات متعددة إلى نفس المجلد (فريد لكل ماركة / منصة). هذا يعني أنه إذا كان موجودًا - تم تحديده بواسطة اسم الطبقة - موجودًا بالفعل في ملف رسم سابق ، فستتم الكتابة فوقه بواسطة التصدير التالي. التي ، مرة أخرى ، ليست أكثر من عملية "دمج".
في هذه الحالة ، على الرغم من ذلك ، قد يكون لدينا بعض الأصول "الأشباح". يحدث هذا عندما يتم اختبار رمز AB في ملف ، ولكن يتم الكتابة عليه في ملف لاحق. في مثل هذه الحالات ، يتم تصدير الملفات المتغيرة إلى مجلد الوجهة ، والمشار إليها في كائن الأصول البيانات
الوصفية كأصل (مع مفتاحه وخصائصه) ، ولكن لا ترتبط بأي أصل "أساسي" (بسبب الدمج العميق لكائنات
أصول البيانات ). ستتم إزالة هذه الملفات في خطوة لاحقة ، قبل إتمام العملية.
كما ذكر أعلاه ، نحن بحاجة إلى صيغ نهائية مختلفة لأنظمة مختلفة. بالنسبة لنظام التشغيل iOS ، نريد ملفات PDF ، ويمكننا تصديرها مباشرة باستخدام أمر
sketchtool . بينما ، بالنسبة إلى Mobile Web ، نريد ملفات JSX ، وبالنسبة إلى Android ، نريد ملفات VectorDrawable ؛ لهذا السبب ، نقوم بتصدير الأصول بتنسيق SVG إلى مجلد وسيط ، ثم نعرضها لمزيد من المعالجة.
ملفات PDF لنظام التشغيل iOS
الغريب أن PDF هو (فقط؟) التنسيق المدعوم من Xcode و OS / iOS لاستيراد أصول المتجهات وعرضها (فيما يلي
شرح موجز للأسباب التقنية وراء هذا الاختيار من قِبل Apple).
نظرًا لأننا نستطيع التصدير مباشرة في PDF عبر Sketchtool ، ليست هناك حاجة لخطوات إضافية لهذا النظام الأساسي: ببساطة نقوم بحفظ الملفات مباشرة في مجلد الوجهة ، وهذا كل شيء.
React / JSX الملفات للويب
في حالة الويب ، نستخدم مكتبة Node تسمى
svgr لتحويل ملفات SVG العادية إلى مكونات
React . لكننا نريد أن نفعل شيئًا أكثر قوة: نريد أن "نرسم الأيقونة ديناميكيًا" في وقت التشغيل ، مع الألوان القادمة من الرموز المميزة للتصميم. لهذا السبب ، قبل التحويل مباشرة ، استبدلنا في SVG قيم
تعبئة المسارات التي كان لها في الأصل نمط مشترك مطبق ، مع قيمة الرمز المميز المقابل المرتبطة بهذا النمط.
لذلك ، إذا كان هذا هو ملف
badge-feature-like.svg الذي تم تصديره من Sketch:
<?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>
سيبدو أصل / رمز
الشارة النهائي كما يلي:
/* 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> ); };
كما ترون ، لقد استبدلنا القيمة الثابتة للون
تعبئة الدائرة ، بقيمة ديناميكية ، تأخذ قيمتها من الرموز المميزة للتصميم (سيتم توفيرها لمكون React
<Icon /> عبر Context API ، ولكن هذه قصة أخرى).
أصبح هذا الاستبدال ممكناً من خلال بيانات تعريف Sketch للأصل المخزن في كائن
Metadata للأصول : تكرار الحلقات بشكل متكرر من خلال طبقات الأصل ، من الممكن إنشاء محدد DOM (في الحالة أعلاه ، سيكون
#Icons # badge-feature- مثل #circle )
واستخدمها للعثور على العقدة في شجرة SVG ، واستبدال قيمة سمة
الملء الخاصة بها (لهذه العملية ، نستخدم مكتبة
cheerio ).
VectorDrawable الملفات لالروبوت
يدعم Android الرسومات المتجهة باستخدام تنسيق المتجه المخصص الخاص به ، والذي يسمى
VectorDrawable . عادة ما يتم التحويل من SVG إلى VectorDrawable
مباشرة داخل Android Studio بواسطة المطورين. لكننا أردنا هنا أتمتة العملية برمتها ، لذلك كنا بحاجة لإيجاد طريقة لتحويلها عبر الكود.
بعد النظر إلى المكتبات والأدوات المختلفة ، قررنا استخدام مكتبة تسمى
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:
مثال على أيقونة VectorDrawable التي تم استيرادها إلى Android Studioهناك شيء واحد يجب ملاحظته في هذه الحالة: يحتوي Android Studio على طريقة صارمة وموضوعة لتنظيم الأصول: لا يوجد مجلد متداخل وكل الأسماء الصغيرة! هذا يعني أنه كان علينا التوصل إلى تنسيق مختلف قليلاً عن أسماء الرموز الخاصة بهم: في حالة الأصل الموجود تحت التجربة ، سيكون اسمه مثل
اسم_اسم_اسم_اسم_العلامة_العلامة_المعيار _ الاسم البديل .
JSON القاموس كمكتبة الأصول
بمجرد حفظ ملفات الأصول في نسقها النهائي ، فإن آخر شيء لا يزال يتعين القيام به هو حفظ جميع المعلومات الوصفية التي تم جمعها أثناء عملية الإنشاء ، وتخزينها في "قاموس" ، بحيث يمكن إتاحتها لاحقًا عندما يتم استيراد الأصول واستهلاكها بواسطة codebase من الأنظمة الأساسية المختلفة.
بعد استخلاص قائمة الأيقونات المسطحة من كائن
أصول البيانات ، نقوم
بحلها فوق كل عنصر نتحقق منه:
- إذا كان رصيدًا عاديًا (على سبيل المثال ، tabbar-livestream ) ، وإذا كان كذلك ، فنحن نحتفظ به ؛
- إذا كان هناك اختلاف في اختبار AB (على سبيل المثال ، التجربة / tabbar-liveestream [البديل] ) ، فإننا نربط اسمها ومسارها واختبارها AB وأسماء المتغيرات ، باختبارات خاصية الأصل "الأساسي" (في هذه الحالة ، tabbar- livestream ) ، ثم نزيل إدخال المتغير من القائمة / الكائن (فقط التهم "الأساسية") ؛
- إذا كان متغير "شبح" ، فنحن نحذف الملف ، ثم نزيل الإدخال من القائمة / الكائن.
بمجرد اكتمال الحلقة ، سيحتوي القاموس على قائمة بجميع الرموز "الأساسية" فقط (واختبارات AB الخاصة بهم ، إذا كانت قيد التجربة). لكل منها ، سوف تحتوي على اسمها وحجمها ومسارها ، وإذا كانت أيقونة تحت اختبار AB ، فإن المعلومات حول الخيارات المختلفة للأصل.
ثم يتم حفظ هذا القاموس بتنسيق JSON في مجلد الوجهة
للعلامة التجارية والنظام
الأساسي . هنا ، على سبيل المثال ، هو ملف
الأصول.json الذي تم إنشاؤه لتطبيق "Blendr" على "الويب المحمول":
{ "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 وملفات الأصول) إلى مستودع بعيد ، وإتاحتها لجميع الأنظمة الأساسية المختلفة ، للتنزيل والاستهلاك في قواعدها البرمجية.
(كيف تسترجع المنصات الفعلية الأصول وتعالجها - عن طريق البرامج النصية المخصصة التي تم تصميمها خصيصًا لهذا الغرض - تتجاوز نطاق هذا المقال ، لكن من المحتمل أن يتم تغطيتها قريبًا في منشورات مدونة مخصصة أخرى ، بواسطة أحد المطورين الآخرين الذين عملوا معي في هذا المشروع).
الاستنتاجات (والدروس المستفادة على طول الطريق)
لطالما أحببت
رسم لسنوات ، كانت الأداة "الفعلية" لاختيار تصميم الويب والتطبيقات (والتطوير). لذلك كنت مهتمًا جدًا
وفضوليًا لاستكشاف تكاملات محتملة مثل
html-sketchapp أو أدوات مشابهة ، يمكن استخدامها في سير العمل وخطوط الأنابيب الخاصة بنا.
هذا التدفق (المثالي) كان دائمًا
الكأس المقدسة بالنسبة لي (
وكثير غيرها ):

يمكن أن تتخيل رسم كأداة تصميم ك "هدف" محتمل لقاعدة البيانات.
لكن عليّ أن أعترف أنني بدأت أخيرًا أتساءل عما إذا كانت Sketch لا تزال الأداة الصحيحة ، لا سيما في سياق نظام التصميم. لذلك ، بدأت استكشاف أدوات جديدة مثل
Figma ، مع واجهات برمجة التطبيقات المفتوحة ، و
Framer X ، مع تكاملها المذهل مع React ، لأنني لم أشاهد جهودًا مماثلة من Sketch للانتقال إلى التكامل مع الكود (مهما كانت الكود).
حسنًا ، لقد غير هذا المشروع رأيي. ليس تماما ، ولكن بالتأكيد الكثير.
ربما لا يقوم Sketch بالكشف عن واجهات برمجة التطبيقات الخاصة به رسميًا ، ولكن بالتأكيد الطريقة التي بنوا بها البنية الداخلية لملفاتهم هي نوع من واجهة برمجة التطبيقات "غير الرسمية". كان بإمكانهم استخدام أسماء خفية ، أو تشويش المفاتيح في كائنات JSON ؛ وبدلاً من ذلك ، اختاروا اتفاقية تسمية واضحة وسهلة القراءة ، وقابلة للقراءة ، وشاملة. لا أستطيع أن أعتقد أن هذا مجرد عرضي.
حقيقة أن ملفات Sketch يمكن معالجتها قد فتحت في ذهني مجموعة واسعة من التطورات والتحسينات المستقبلية المحتملة. من المكونات الإضافية للتحقق من صحة تسمية ، وتصميم وهيكل الطبقات للأيقونات ، إلى التكامل ممكن مع ويكي لدينا ووثائق نظام التصميم لدينا (في كلا الاتجاهين) ، من خلال إنشاء تطبيقات العقدة المستضافة في
الكترون أو
كارلو لتسهيل العديد من المهام المتكررة التي يتعين على المصممين القيام بها.
ومن بين المكافآت غير المتوقعة لهذا المشروع (على الأقل بالنسبة لي) أن ملفات Sketch التي تحمل أيقونات كوزموس أصبحت "مصدراً للحقيقة" ، على غرار ما حدث مع
نظام تصميم Cosmos . إذا لم يكن هناك رمز ، فلن يكون موجودًا في قاعدة البيانات (أو أفضل منه ، يجب ألا يكون موجودًا: لكننا على الأقل نعرف أنه استثناء). أعلم أن الأمر واضح تمامًا الآن ، لكنه لم يكن من قبل ، على الأقل بالنسبة لي.
ما بدأ كمشروع MVP ، سرعان ما أصبح الغوص العميق (حرفيًا) في الملفات الداخلية لملفات Sketch ، مع إدراك أنه يمكن التلاعب بها. لا نعرف حتى الآن إلى أين سيؤدي كل هذا ، لكنه كان حتى الآن نجاحًا. يوافق جميع المصممين والمطورين ومديري البرامج وأصحاب المصلحة ، على أن هذا سيوفر الكثير من العمل اليدوي للجميع ، ويمنع الكثير من الأخطاء المحتملة. ولكنه أيضًا سيفتح الأبواب أمام استخدامات الرموز التي كانت مستحيلة حتى الآن.
شيء واحد أخير: ما وصفته في هذا المنشور الطويل هو خط أنابيب قمنا ببنائه هنا لحل
مشاكلنا الخاصة ، وبالتالي فهو بالضرورة مخصص للغاية لسياقنا.
ضع في اعتبارك أنه قد لا يناسب احتياجات عملك أو يناسب السياق
الخاص بك .
لكن المهم بالنسبة لي وما أردت مشاركته هو أنه يمكن القيام به. ربما بطرق مختلفة ، مع أساليب مختلفة وتنسيقات الإخراج المختلفة ، ربما تنطوي على تعقيد أقل (على سبيل المثال: قد لا تحتاج إلى العلامة التجارية المتعددة واختبار AB). ولكن الآن يمكنك أتمتة سير العمل الذي ينطوي عليه تسليم أيقوناتك باستخدام برنامج نصي Node.js مخصص ورسم.
ابحث عن طريقتك الخاصة للقيام بذلك. انها ممتعة (وسهلة نسبيا).
الاعتمادات
تم تطوير هذا المشروع الضخم بالتعاون مع
Nikhil Verma (Mobile Web) ، الذي أنشأ الإصدار الأول من النص البرمجي للبناء ، و
Artem Rudoi (Android) و
Igor Savelev (iOS) ، الذين طوروا البرامج النصية التي تستورد الأصول
وتستهلكها في منصات الأصلية منها. شكراً لكم أيها الناس ، لقد كان انفجارًا يعمل معكم في هذا المشروع وشاهده على أرض الواقع.