作者简介

尹正波,携程机票研发部前端工程师,专注设计和开发的交叉领域,用系统和工具改进设计体验和交付。

Sketch 是伴随移动应用程序崛起而流行的 UI 设计工具。2014年 Sketch V3 增加 Symbols 功能,在 UI 设计工具领域的优势越来越大。它持续改进和增强功能,不断加强对插件社区的建设,吸引越来越多的开发者进入。

随着 Design System 的普及和流行,许多大公司都在设计插件领域有所投入,如 Google,Airbnb 等,同时诞生了一系列提供设计管理的初创企业,如 Abstract,UXPIN 等。中国很多大中型互联网企业也开始研制自己的设计系统和插件工具,例如 Dapllo,Kitchen,Fusion,Anto。

2016年,携程机票UED团队主力生产工具完全切换到 Sketch。与此同时,机票前端研发技术团队也关注到设计系统和插件工具规范化自动化对业务交付工作流程的加速作用。于是设计团队与前端技术团队开始携手探索设计语言升级,从业务需求项目实践中提炼通用规范,落地插件工具系统,并输出一整套设计资源管理规范和流程。

一、设计资源管理

产品的设计语言是一家公司留给消费者最直观的形象,通常包含品牌 Logo,颜色,文字,符号,插画,动画和文案话术等。而 Design System 是为了让设计语言落地执行而构建的解决方案,包括设计指导文档,设计资源,组件代码和工具等。

设计资源的共享和版本管理一直困扰着设计师们。Sketch 通过引入 Symbols,Library 等功能解决了共享组件问题,但在颜色,文字排版,图标管理等问题上依然缺少足够好的解决方案,需要各家公司针对自身的特点开发插件和服务去解决这些问题。

二、Kirby - Sketch Plugin

Kirby 是携程机票前端团队的 Sketch Plugin 系统代号,故事源于一次 Sketch 版本升级引起的标注导出功能失效问题。

Sketch 社区著名插件 Sketch Measure,它将设计稿和数据参数导出 HTML 网页,供技术人员查看,节省从设计到开发过程的沟通成本。但 Sketch 的版本升级经常致其无法正常使用,维护者也无暇快速修复问题,设计师们若继续使用,将被迫使用一个低版本 Sketch。

为了让设计师能够使用 Sketch 最新版本,并修复 Sketch Measure 缺陷功能,Kirby 诞生。

之后我们陆续添加更多功能,从 Design Token,到 Icon System,再到 Component,以及 Template,一步步接近成熟和完整。

Kirby 目前已交付若干重要特性:

2.1设计语言规范约束

Color Pallete

Typography

Shadow

2.2 设计稿静态扫描检查

方便设计师查找和修正问题。

字体与图标系统

在线版设计资源模版库

三、Sketch Plugin 开发技术

在插件开发实现过程中,我们遇到许多交叉技术领域的问题,也因此进行了多次技术重构。

3.1 基础知识

Sketch 官方技术文档提供了简单介绍:

1)Sketch 插件是按照特定方式管理的一个文件夹,包含一个或多个 scripts,每个 script 含有若干扩展 Sketch 用途的命令。

2)插件主要使用 Javascript 语言编写,支持 ES6 语法,但运行环境既不是浏览器也不是 Nodejs,而是 Hybrid SketchAPI for macOS Native 运行环境。

从最简单的部分看起:

打开一个 Sketch 文件,control + shift + k 快捷键开启 Run Script 面板,输入:

const sketch = require('sketch')
sketch.UI.message('Hello, world!')

运行以上代码,将在 Sketch 文件下方区域显示Toast:Hello, world,该 Script 面板常用于快速测试脚本API。

3.2 API 概述

The plugin system in Sketch gives you full access to the app’s internals and the core frameworks in macOS. So you have an immense power to build almost anything.

Sketch 插件系统开放了几乎所有权限,让许多天马行空的想法可以实现。但是插件开发者需要及时关注 Sketch 版本升级,其向下兼容性较差,或者说官方团队并不重视这部分。典型案例例如,著名插件 Paddy,在开发V2.0版本过程中,因 Sktech API 大量变更,原插件无法兼容,作者最终无力修复而放弃开发,非常可惜。

官方 API 有两个: Actions API, Javascript API。

3.3 Actions API

用于监听用户操作行为和触发的事件。据社区消息,该API未来会被新的 Events API 替代。它代表了 Sketch App 内部触发的事件,例如 CloseDocument, TogglePresentationMode 等, 细节详见官网:

https://developer.sketch.com/reference/action/

1)订阅 Actions

manifest.json 文件,配置相应 handlers。

示例:当 OpenDocument 事件被触发时调用 onOpenDocument handler 。

"commands" : [    ... {   "script" : "my-action-listener.js", "name" : "My Action Listener",  "handlers" : {    "actions": {  "OpenDocument": "onOpenDocument"    }   },  "identifier" : "my-action-listener-identifier"  }   ...
],

my-action-listener.js

export function onOpenDocument(context) {  context.actionContext.document.showMessage('Document Opened')
}

2)Action Context

Action事件会将 context.actionContext 传递给handler。有些 Action 包含两个状态,begin 和 finished,例如 SelectionChanged 。需分别订阅 SelectionChanged.begin 和 SelectionChanged.finished,否则会触发两次事件。

当我们不知道应该订阅哪个 Action 时,可以使用通配符。但运行时性能开销很大,建议仅在开发阶段使用。

示例:Terminal 打开通配符支持。

defaults write com.bohemiancoding.sketch3 actionWildcardsAllowed -bool YES

manifest.json 文件配置通配符。

{ ... "handlers": { "actions": {  "*": "onActionHandler"  }   }   ...
}

3.4 Javascript API

它是针对 Native API 的封装,目前还未涵盖所有场景,官方承诺未来将覆盖90%。细节详见官网和GitHub:

https://developer.sketch.com/reference/api/

https://github.com/BohemianCoding/SketchAPI/blob/develop/CHANGELOG.json


3.5 开发环境

官方提供了一个打包工具 skpm, 用于快速上手插件开发。它基于 webpack,项目根目录下存放 webpack.skpm.config.js, 用于工程配置修改。

安装示例

npm install -g skpm
skpm create my-plugin
cd my-plugin
npm run build
# 然后在 Plugins -> my-plugin -> MyCommand 中运行插件命令

典型的插件开发工程的目录结构示例

.

├── .gitignore
├── README.md
├── src                         // sources
│   ├── manifest.json           // plugin's manifest
│   └── my-command.js           // source code of the command
├── node_modules
│   └── skpm                    // the sketch plugin developer toolchain
├── my-plugin.sketchplugin      // compilation output, the actual plugin
│   └── Contents
│       ├── Resources
│       └── Sketch
│           ├── manifest.json
│           └── my-command.js
└── package.json

3.6 崩溃保护

当 Sketch 运行发生崩溃,它会停用所有插件以避免循环崩溃。对于使用者,每次崩溃重启后手动在菜单栏启用所需插件非常繁琐。因此可以通过如下命令禁用该特性。

defaults write com.bohemiancoding.sketch3 disableAutomaticSafeMode true

3.7 插件缓存


通过配置启用或禁用缓存机制:

defaults write com.bohemiancoding.sketch3 AlwaysReloadScript -bool YES

但是该方法对于某些场景不适用。例如当正在使用一个 long-running 脚本时,即 Javascript Context 不变,并存储在内存中,那么则需要重启 Sketch 或通过 coscript.setShouldKeepAround(false) 使改动生效。

3.8 WebView 调试

如果插件实现方案使用 WebView 做界面,可通过以下配置开启调试功能。

defaults write com.bohemiancoding.sketch3 WebKitDeveloperExtras -bool true

3.9 打印输出日志

Sketch 运行环境 JavascriptCore 的日志输出方式:

1)macOS console.app 中搜索 与 sketch 相关的 Filter。

2)查看 ~/Library/Logs/com.bohemiancoding.sketch3/Plugin Output.log。

3)运行 skpm log 查看上述文件,-f 参数使用 stream 方式查看。

4)使用 skpm 开发的插件,可以使用 console.log 语法,需安装 sketch-dev-tools。

3.10 代码调试

Safari 浏览器开发工具可用于插件的 Javascript 代码调试。

Developer > name of your machine > Automatically Show Web Inspector for JSContexts

同时启用选项 Automatically Pause Connecting to JSContext

3.11 Objective-C Classes

Sketch 对外暴露了全部内部方法的调用权限,其 Objective-C 类 通过 Bridge 提供 Javascript API 调用。

3.12 插件 GUI 的实现

用户(设计师)可以通过以下几种方式使用插件:

1)菜单 -> 插件 -> 选择插件已定义的 Handler

2)Handler 预定义的快捷键

3)插件提供的其他 GUI 方案

其他 GUI 方案有 Native(Appkit) 和 WebView ,以 Kirby 为例,目前大部分 UI 由 WebView 实现。这种方案对于 Web 前端技术人员上手学习成本较低。 skpm 提供了已封装好的基于 WKWebView 的 sketch-module-web-view,其 API 设计接近 Electron,细节详见 GitHub。

https://github.com/skpm/sketch-module-web-view/blob/master/docs/browser-window.md

除此之外,skpm 还提供了一些供 JavaScript 调用的 Native 控件,例如 Dialog:

import dialog from '@skpm/dialog'
console.log(    dialog.showOpenDialog({ properties: ['openFile', 'openDirectory', 'multiSelections']  })
)

3.13 CocoaScript GUI

CocoaScript is built on top of Apple’s JavaScriptCore, the same JavaScript engine that powers Safari. So when you write in CocoaScript, you are really writing JavaScript.

CocoaScript also includes a bridge which lets you access Apple’s Cocoa frameworks from JavaScript. This means you have a ton wonderful classes and functions you can use in addition to the standard JavaScript library.

Sketch 插件通过 Mohca / CocoaScript 连接到 Objective-C / Cocoa。Javascript 调用 Objective-C 方法,需要将方法名的冒号改为下划线(最后一个可选),所有 selector 连接成一个连续的字符串。例如 executeOperation:withObject:error: 将转为 executeOperation_withObject_error()。

示例:

/*
打开文件对话框,使用 Appkit NSOpenPanel。
https://developer.apple.com/documentation/appkit/nsopenpanel?language=objc
*/
var openPanel = NSOpenPanel.openPanel()
openPanel.setCanChooseDirectories(false)
openPanel.setCanChooseFiles(true)
openPanel.setCanCreateDirectories(false)
openPanel.setDirectoryURL(NSURL.fileURLWithPath('~/Documents/'))
openPanel.setTitle('Choose a file')
openPanel.setPrompt('Choose')
openPanel.runModal()    //设置异步操作不被 Sketch GC回收
COScript.currentCOScript().shouldKeepAround = true
//异步执行完成后,释放
COScript.currentCOScript().shouldKeepAround = false

3.14 Native GUI

实现 Native GUI 的难点在于“合适的时机”找到“正确的实例”。Actions API 用于解决“合适的时机”问题。而寻找“正确的实例”相对复杂一些。首先从 Sketch-Headers 入手,搜索与事件有关的方法。

例如,当我们需要扩展 “创建组件“ 对话框,该对话框在 “创建组件” 事件发生时才会出现,因此在 Actions API 中搜索与 symbol 有关的事件,找到名为 Create Symbol 的 Action。然后继续搜索关键字 CreateSymbol,可找到如下结果。

code 能够以黑盒方式分析系统当前运行的应用程序界面,提取对于插件开发有用的信息。使用 Xcode 分析 Sketch 可知,MSCreateSymbolNamingSheet 继承自 NSWindowController,如下示例代码可获取其调用对象。

const doc = context.actionContext.document;
const docData = doc.documentData();
const window = doc.window();
const sheetWindow = window.attachedSheet();
const createSymbolNameingSheet = sheetWindow.windowController();

3.15 Webview GUI

Webview 与 Plugin 之间需要实现双向通讯互操作。Webview 可通过 WKWebView delegates 向 Plugin 发送消息,Plugin 则通过webView.evaluateJavaScript_completionHandler() 触发 Webview 执行 Javascript 代码。

export function createPopoverWKHandler () {   return new MochaJSDelegate({    'userContentController:didReceiveScriptMessage:': (function (controller, message) {   let body = Utils.toJSON(message.body()),   { key, value } = body  switch (key) {  case 'setTypography': Utils.setTextStyle(value)   break   }   })  })
}

四、Milestone One

一个功能完整易用性佳的Sketch插件系统,除了上述技术实现细节,还有很多需要思考兼顾的方面。例如,设计文件版本管理,Sketch 版本兼容性,用户配置文件,云同步协作,用户(企业内网)鉴权认证接入。

Kirby 每一个新增功能都是围绕着从设计到研发再到交付的一致性和复用性,这也正是设计系统所要解决的核心问题。

我们 hack 的不仅是一个软件,而是完整的 DesignOps 工作流程。

【推荐阅读】

  • 携程机票 App Kotlin Multiplatform 初探

  • 快速融入云原生,携程开源 Dubbo for Go 版本

  • 当你在携程搜索时,背后的推荐系统是如何工作的

  • 携程酒店iOS动态View的探索

  • 浅谈Node.js在携程的应用

干货 | 携程机票Sketch插件开发实践相关推荐

  1. 干货 | CrateDb在携程机票BI的实践

    作者简介 Loredp,携程数据分析经理,关注大数据存储.大数据处理以及linux等领域. 一.前言 随着整个互联网流量红利进入末期,各大厂在着力吸引新客的同时,在既有客户群体的运营上也是煞费苦心,各 ...

  2. 干货 | 携程机票前端安卓虚拟机测试集群建设实践

    作者简介 Liang,携程研发总监,关注DevOps,前端&服务端质量保障.能效提升: Tony,携程资深测试经理,关注自动化测试框架及平台类工具开发. 一.背景 在携程内部业务高频率敏捷迭代 ...

  3. 干货 | 携程机票大数据架构最佳实践

    本文转载自 携程技术中心(ctriptech) 公众号,本文PPT请点击下面 阅读原文 获取 作者简介 许鹏,携程机票大数据基础平台Leader,负责平台的构建和运维.深度掌握各种大数据开源产品,如S ...

  4. 干货 | 携程机票 Android Jetpack 与 Kotlin Coroutines 实践

    作者简介 禹昂,携程机票移动端资深工程师,Kotlin 中文社区核心成员,图书<Kotlin 编程实践>译者. 一.前言 1.1 技术背景与选型 自 2017年 Google IO 大会以 ...

  5. 干货 | 携程机票 App KMM 跨端生产实践

    作者简介 禹昂,携程移动端资深工程师,Kotlin 中文社区核心成员,图书<Kotlin 编程实践>译者. Derek,携程资深研发经理,专注于移动端开发,热衷于各种跨端技术的研究和实践. ...

  6. 干货 | 携程 Web CI/CD 实践

    作者简介 西杰,携程软件技术专家,关注前端技术及其生态,致力于提升前端开发效能及质量. 一.背景 在携程的日常Web开发生命周期中,本地代码开发阶段可通过NFES框架(携程内部一个支持SSR框架,其中 ...

  7. 干货 | 携程持久化KV存储实践

    作者简介 布莱德,携程软件技术专家:蔚浩,携程资深软件工程师:小董,携程技术培训生. 一.背景 过去几年,携程技术保障部门在Redis治理方面做了很多工作,解决了运营上的问题,在私有云上也积累了丰富的 ...

  8. 干货 | 携程无线APM升级实践

    作者简介 辛贵,携程无线研发总监.主要负责App基础框架研发相关工作,关注App开发框架.性能.质量.效率和新技术. 1.背景介绍 APM全称为Application Performance Mana ...

  9. 干货 | 携程酒店Flutter性能优化实践

    作者简介 Qifan,携程高级工程师,专注移动端开发:Yinuo,携程高级工程师,专注移动端开发:popeye,携程软件技术专家,关注移动端跨端技术,致力于快速,高性能地支撑业务开发. 一 .前言 携 ...

最新文章

  1. 2018 AI产业投融资分析:热钱涌向何处,谁的“寒冬”将至?
  2. Oracle 数据泵(IMPDP/EXPDP)导入导出总结
  3. make_ext4fs 失败
  4. DIP第二章习题解答
  5. 2021暑假每日一题 【week3 完结】
  6. Delphi如果要追赶C#,最应该做的
  7. leetcode 16. 3Sum Closest | 16. 最接近的三数之和(双指针)
  8. Dojo 如何测试 widget 1
  9. 计算机在轻化工程中的应用,计算机在轻化工程专业中的应用-中国大学mooc-题库零氪...
  10. mysql+yes数据类型,怎样修改mysql列的数据类型?
  11. Play on Words UVA - 10129 (欧拉回路)
  12. centos activemq 集群配置 Networks of Brokers
  13. qqwry.dat java 乱码_UTF-8使用纯真IP数据库乱码问题
  14. java 合并对象中属性_Java2个对象形集合按某一个属性合并
  15. 【渝粤题库】广东开放大学 电算化会计 形成性考核
  16. opencv 应用程序无法正常启动0xc000007b
  17. 【宋红康 MySQL数据库 】【高级篇】【07】MySQL的存储引擎
  18. 后台核心编程(二):调试工具
  19. 广东移动24日开始免除国内长途及漫游费
  20. 【jQuery 基础】$ (document) .ready和$(window).load

热门文章

  1. python九宫格拼图,Python生成九宫格图片
  2. 试用期离职,该如何解释?
  3. FPGA驱动RGB灯带WS2812B
  4. Remix-IDE安装开发环境与使用文档(Windows环境)
  5. 关于低功耗IPC市场介绍之原厂介绍
  6. c语言开头的作用是什么,C语言为什么开头都加;#includestdio.h有什么作用?
  7. win32com为word添加页码(示例)
  8. 云计算是什么,云计算的特点及主要形式
  9. 视频教程-深度学习与PyTorch入门实战教程-深度学习
  10. Android Studio 光标莫名其妙加粗后,与 insert 键相反的问题