【笔记】Sketch插件开发随手记
Nov 1, 2020笔记sketch插件Sketch 插件开发随手记
Sketch 是一套原生 Objective-C 开发的设计软件,它的作用和特点就不在此描述。由于最近简单研究并开发了几个 Sketch 插件,借本文来记录开发过程中的一些重要知识点。
结构
插件包的目录结构
1 | my-plugin.sketchplugin/ |
开发
Manifest
manifest.json
用来描述主要插件配置,具体字段说明如下:
appcast
:{String}
,该字段指向的 appcast 文件 URL 包含可用的版本信息,包括下载特定版本的 URL。Sketch 会自动检查该文件更新,如果有更新可用时会通知用户。author
:{String}
,插件作者。authorEmail
:{String}
,插件作者的 Email 地址,可选。bundleVersion
:{Number}
,指定版本的插件包的元数据结构和文件布局。这是可选的,默认为1
。目前没有其他版本的支持。compatibleVersion
:{String}
,定义了 Sketch 运行插件所需的最低版本。这个字符串必须提供使用语义版本控制。commands
:{Object[]}
,定义插件提供的所有命令。其中对象字段如下:identifier
:{String}
,定义了一个惟一的标识符内的命令插件包。name
:{String}
,定义 Sketch 软件“插件”目录下的菜单名称。shortcut
:{String}
,命令快捷键,如ctrl shift t
。具体按键对应申明可见https://developer.sketch.com/plugins/plugin-manifest。script
:{String}
,指定执行命令对应脚本的路径文件。handler
:{String}
,声明命令的指定函数名称。函数的声明应该在脚本作用域顶层,并接受一个context
上下文参数包含信息,如当前文档和选择内容。如果省略该字段插件将默认使用一个名为onRun
的处理程序。(如果使用skpm
的话,可以通过export default
导出函数而不用申明。)handlers
:{Object}
,更精细的处理控制。定义setup › run › tearDown
生命周期的控制。对象字段:run
:{String}
,命令运行时的执行声明,同handler
字段。setUp
:{String}
,命令被调用前的执行声明(命名为 setUp 是为了避免与 StartUp 动作重名或混淆)。tearDown
:{String}
,命令函数调用完成的执行声明(命名为 tearDown 是为了避免与 Shutdown 动作重名)。onDocumentChanged
:{String}
,Sketch 设计稿 Document 变更时的执行声明。actions
:{String}
,Sketch 应用事件,更多可见https://developer.sketch.com/plugins/actions
description
:{String}
,插件描述文案。disableCocoaScriptPreprocessor
:{Boolean}
,CocaScript 支持开关,默认为false
。CocoaScript 默认支持@import
和中括号语法,如[obj hello: world]
。注意,如果使用 ES6 语法或者使用 skpm 等构建工具,该项必须选择true
。homepage
:{String}
,官网。icon
:{String}
,插件图标,128*128
的 PNG 图片,并且在插件包的Contents/Resources
目录下。identifier
:{String}
,插件的唯一命名符,使用反向域名格式,如"com.example.sketch.plugin.select-shapes"
。maxCompatibleVersion
:{String}
,最高兼容版本。name
:{String}
,暴露给用户的插件名称。scope
:{String}
,申明插件的作用域。"document"(仅在打开设计文档时插件菜单可见)或"applicaton"(打开Sketch时插件菜单就可见)
。suppliesData
:{Boolean}
,申明是否为一个数据插件。如果设置为true
则该插件是一个可视窗口,显示所有已安装的插件的列表。version
:{String}
,版本号。menu
:{Object}
,菜单栏控制。字段说明:isRoot
:{Boolean}
,菜单是否在“插件”根目录下展示,默认在插件的二次菜单。注意子菜单不支持。items
:{String[]}
,数组的菜单项,支持值命令标识符,"-"
分隔符和对象定义子菜单。title
:{String}
,菜单名称声明,当isRoot
为true
时被忽略。
demo
1 | { |
开发模式
笼统来说,Sketch Plugin 作用到 Sketch.app
本身,有两种主要方式:
- 编写 CocoaScript + JavaScript API 间接作用
- 编写 CocoaScript、Objective-C 直接作用
它之所以能支持使用 JS 开发,是因为它使用 CocoaScript 作为插件的开发语言。它就像是一座桥(Bridge),类似于 js-bridge,能让我们在插件中写 OC 和 JS,然后 Sketch 将基础方法进行了封装,实现了一套 JavaScript API,这样我们就能使用 JS 开发 Sketch 插件了。
使用 JS API 的最大弊端是 API 的功能覆盖太少(截止到 Sketch 49 版本前),而我们期望实现的功能大都没有对应的接口来完成。因此在开发时,我们选择使用 CocoaScript + Objective-C Framework 的组合方式,这样的好处是能够平衡开发的敏捷性与插件的私密性
之前对于 CocoaScript 的了解并不多,但如官方介绍的那样作用是作为通信桥梁:CocoaScript is a bridge providing access to the internal Sketch APIs and macOS frameworks in JavaScript.
JavaScript 封装包
Sketch 根据作用领域对 JavaScript API 做了封装库:
- sketch/ui:界面相关,包括 toast、alert 等;
- sketch/dom:访问、修改和创建文档,从颜色到层和插件;
- sketch/settings:保存图层/文档,或者插件的用户设置(类似于 localStorage);
- sketch/data-supplier:提供图片或文字数据,直接输出设计相关的用户界面;
- sketch/async:默认插件命令的 JavaScript 上下文会在成功执行后销毁。通过这个包的异步操作方法可以延长作用生命周期。
选型
像我这样对于 OC 语法不熟悉的 web 开发,目前 Sketch 开发有两大开发方案:
- 1.React 组件渲染成 sketch:react-sketchapp ,由 airbnb 团队发起
- 2.使用 skpm 构建开发 Sketch 插件。
本人当前主要使用 skpm,所以就主要记录 skpm 的使用功能点。
skpm
安装
1 | npm i -g skpm |
创建项目
1 | skpm create <plugin-name> |
当前主要的模版:
skpm/skpm
:普通插件 (default)skpm/with-prettier
: 使用 ESLint 和 Prettier 的插件skpm/with-datasupplier
: 插件数据展示插件skpm/with-webview
: 带有 webview 界面的插件
如
1 | skpm create testPlugin --template=skpm/with-webview |
构建:
1 | npm run build |
如果观察数据:
1 | npm run watch |
如果你想每次构建时运行:
1 | npm run start |
注意:尽可能不要使用npm start
进行开发,它携带的 --run
命令会使得构建速度特别慢。虽然它带 Live Reload 功能会很方便,但在官方未修复该问题前还是不建议大家使用。
skpm/with-webview 使用记录
由于目前开发的插件主要是 Webview 界面的形式,那么先记录一下开发工程中遇到的坑与解决方案。
1.文档地址
sketch 包:https://developer.sketchapp.boltdoggy.com/reference/api/#document
skpm/with-webview 中 BrowserWindow 对象文档:https://github.com/skpm/sketch-module-web-view/blob/master/docs/browser-window.md,实例的 webContents 文档:https://github.com/skpm/sketch-module-web-view/blob/master/docs/web-contents.md
2.webview 页面与插件运行环境的通信
Sketch 显示型插件肯定需要调用或者触发 sketch plugin\/sketch api 功能,那么首先就涉及到 webview 通知插件运行环境,姑且称 webview 环境为 frontend,插件运行环境为 backend。
fontend -> backend:window.postMessage()
webview 自带window.postMessage方法,与 backend 的通信方式就是通过此方法。
首先 backend 注册事件监听,如:
1 | /** |
1 | /** |
注意:webContents 本身存在一些如生命周期的默认事件,要避免与这些事件命名冲突。关于 webContents 及默认事件见后文。
backend -> frontend:browserWindow.webContents .executeJavaScript
通过 browserWindow 实例中 webContents 上下文的 executeJavaScript 方法,可以调用 webview 中的全局方法,调用形式类似于eval()
。browserWindow.webContents .executeJavaScript()
方法返回一个 Promise 实例,以获取和处理调用的响应结果。如:
1 | /** |
1 | /** |
小技巧:如果你不想装 sketch-dev-tools,但想看到 console.log 的信息,可以通过
Safari > Develop > “你的电脑” > “你的插件”
。
BrowserWindow
构造函数,用于创建和控制浏览器窗口。
js 与 OC(Objective-C)
OC 信息
SKetch 运行的插件环境可以获取很多 OC 结构体信息,这些结构体提供设备信息等原生开发才有的应用权限。比如 NSScreen 提供屏幕信息。
OC 属性代表:NSScreen
文档:http://www.gnustep.org/resources/OpenStepSpec/ApplicationKit/Classes/NSScreen.html
如:
1 | console.log(NSScreen.mainScreen().frame()); |
返回画布及坐标信息:
OC 方法代表:NSPasteboard
如清理剪贴板:
1 | NSPasteboard.generalPasteboard().clearContents(); |
添加剪贴板:
1 | NSPasteboard.generalPasteboard().writeObjects(); |
Sketch 环境下 OC 方法与 JS 方法的语法关系
OC 的方括号语法在 js 中转换为点语法。具体来说的话,CocoaScript 创建了一个对 OC 的 js 代理对象。
OC 在 js 中的引用方法:
- Getter:
object.name()
- Setter:
object.name = 'Sketch'
- 方法调用:
object.setName()
- Getter:
OC 方法选择器转换为了 js 方法:
:
(参数与函数名分割符) 转换为_
,最后一个下划线可省略;- 下划线从一杠变成两杠
sketch_method
->sketch__method
; - 选择器的每个组件都连接成一个没有分隔的字符串。
如 OC 的对象操作方法
1 | [executeOperation:withObject:error:] |
在 js 中转变为
1 | executeOperation_withObject_error(); |
实现插件的自动更新
Sketch 会定期检查 appcast 更新,并提示用户安装新的插件版本。
如何在使用 skpm 的情况下,实现闭源且用 github 提供下载更新的地址?
1.准备两个仓库。比如 xxx 和 xxx-release,xxx 存放源码,xxx-release 发布更新。
2.在
package.json
文件中加入repository
字段,指向 xxx-release。
1 | "repository": "https://github.com/xxx/xxx-release", |
3.使用 skpm 发布新版本
4.在
xxx-release
仓库更新.appcast.xml
文件,加入新的地址。
相关链接
- https://semver.org/
- https://github.com/skpm/sketch-dev-tools
- https://github.com/ccgus/CocoaScript
- https://zhuanlan.zhihu.com/p/264495854
- https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
- https://www.yuque.com/design-engineering/sketch-dev/tt9mzm
- https://github.com/amzn/sketch-constructor
Author
My name is Micheal Wayne and this is my blog.
I am a front-end software engineer.
Contact: michealwayne@163.com