本文为稀土技能社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!
序
本系列前面的两篇文章《概念篇》、《中心篇》中现已详细阐明晰猎豹跨渠道插件开发所需求的技能,以及针对对不同渠道做的中心模块抽取流程。
本文首要解说怎么接入咱们抽取的中心模块怎么运用在 uTools 渠道的插件开发中,而且介绍一下 uTools 插件开发用到的 API,以及 uTools 插件的发布流程。
项目装备
uTools 为开发者供给了一个东西插件,能够在插件市场直接查找“uTools 开发者东西”装置,项意图新建、运转,发布都在这个插件内操作。
创立项目
装置完开发者东西后,直接在 uTools
输入框查找翻开开发者东西,点击左下角的新建项目,翻开项目创立面板,依据提示完结项目创立。
依据官网文档指引,需求为项目新建一个 plugin.json
文件,用于装备项目信息,功用进口等等。
开发者能够围绕 plugin.json
文件创立项目,运用自己了解的构建东西完结项目资源构建,plugin.json
中的 preload
字段指向构建成果中的进口文件即可。
plugin 装备
{
"version": "1.0.0", // 插件版本
"preload": "index.js", // 插件功用进口
"logo": "assets/logo.png", // 插件 Logo
"platform": [ // 插件支撑的渠道
"win32", // Windows
"darwin" // Mac OS
],
"features": [ // 插件运用功用
{
"code": "open", // 功用仅有标识,查找项目并运用与指令相关的软件翻开
"explain": "查找并翻开项目",
"cmds": [ // 查找这些字符都能够进入 open 功用,其值将作为 action 参数传入后续履行的函数
"open",
"git_gui_open",
"terminal_open",
"folder_open",
"set_application",
"编辑器",
"Git运用",
"终端",
"文件夹",
"设置项目默许运用"
]
},
{
"code": "setting", // 功用仅有标识,翻开插件设置面板
"explain": "翻开设置面板",
"cmds": [ // 这俩指令都是翻开设置面板
"setting",
"设置"
]
}
]
}
设置面板
从上面装备中能够看出,除了 open
功用外,还有一个翻开设置面板功用,这么做的原因是 uTools 的插件办理没有供给现成的偏好设置功用,一些个性化的装备想要用户自己输入时比较费事,所以这边添加了一个指令,用于翻开咱们自己开发的装备面板,装备的数据能够存储在 uTools 供给的存储环境中。
指令面板能够运用恣意结构开发,最终构建成 html
、css
、js
即可经过 uTools 供给的 API utools.createBrowserWindow
翻开窗口。
插一句:uTools 基于 Electron 开发,了解 Electron 的小伙伴应该很容易上手。
下面看一看设置面板翻开今后得样子:
文件结构
首要的功用文件运用 rollup.js
构建,设置面板运用 vite + vue3
,输出到 package
目录下,将 plugin.json
也放置其内,处理好引证联系,插件的项目装备就基本完结了,结构如下:
cheetah-for-utools
├─ lib
│ ├─ common
│ │ ├─ constant.ts
│ │ ├─ core.ts
│ │ ├─ index.ts
│ │ └─ utils.ts
│ ├─ index.ts
│ └─ mount.ts
├─ package
│ ├─ assets
│ │ ├─ empty.png
│ │ ├─ logo.png
│ │ ├─ refresh.png
│ │ └─ type
│ │ ├─ android.png
│ │ ├─ applescript.png
│ │ ├─ dart.png
│ │ ├─ hexo.png
│ │ ├─ javascript.png
│ │ ├─ nuxt.png
│ │ ├─ react.png
│ │ ├─ react_ts.png
│ │ ├─ rust.png
│ │ ├─ typescript.png
│ │ ├─ unknown.png
│ │ ├─ vscode.png
│ │ └─ vue.png
│ ├─ plugin.json
├─ package.json
├─ rollup.config.js
├─ tsconfig.json
├─ types.d.ts
├─ vite.config.ts
└─ window
├─ index.html
└─ src
├─ App.vue
├─ assets
│ └─ logo.png
├─ components
│ ├─ app-choose-item.vue
│ ├─ cell-button.vue
│ └─ workspace-manager.vue
├─ env.d.ts
├─ main.ts
├─ pages
│ └─ index.vue
└─ router
└─ index.ts
rollup
的装备与中心篇大同小异,最大的区别是,构建成果不能压缩,因为发布时要保证 preload.js
明文可读,不然审阅会不经过,审阅人员会检查插件是否会造成对用户系统的危害。
引进中心模块
中心篇中现已论述了怎么开发、发布插件,而且现已将猎豹的中心模块 cheetah-core
发布到 npm
,现在直接在 uTools 插件项目中装置运用即可:
npm install cheetah-core
# or
yarn add cheetah-core
功用完结
设置面板
上面说到设置面板首要是为了让用户进行一些插件功用的设置,首要包括下面这些选项。
工作区设置
东西将在以下工作区目录查找 Git 项目,可装备多个,每个工作区目录能够包括多个 Git 项目。
默许编辑器
open 指令挑选项目默许由此编辑器翻开
Git GUI 运用
git_gui_open 指令挑选项目由此运用翻开
终端
terminal_open 指令挑选项目由此终端翻开
以上这些设置今后经过 utools.dbStorage.setItem
写入本地数据库,便利 open
指令履行时获取运用。
那么怎么翻开设置面板呢?
在 preload.ts
中添加:
window.exports = {
open: {...}, // open 指令后续解说
setting: {
mode: 'none',
args: {
enter: (action: any) => {
const settingWindow = utools.createBrowserWindow(
'./window/index.html',
{
show: false,
title: '设置',
resizable: false,
minimizable: false,
maximizable: false,
height: 800,
width: 500,
webPreferences: {
preload: 'index.js',
},
},
() => {
settingWindow.show();
}
);
utools.hideMainWindow();
},
},
},
}
上面的代码表明在 uTools 输入框中输入 setting
相关指令并运转后,运用 utools.createBrowserWindow
翻开咱们构建的页面,而且载入 preload
文件为 rollup
构建的进口文件。
在进口文件中引进了 mount.ts
文件,其作用是向 window
对象挂载一系列东西函数:
// index.ts
import mount.ts
...
// mount.ts
import {
chooseFile,
chooseFolder,
getValue,
setValue,
notice,
getAllDefaultApp,
setDefaultApp,
platform,
onClearCache
} from './common';
Object.assign(window, {
platform,
chooseFile,
chooseFolder,
notice,
getValue,
setValue,
getAllDefaultApp,
setDefaultApp,
onClearCache,
});
这样在设置面板中就能够直接运用 window
上挂载的函数完结装备了。
查找项目
项目查找的逻辑在中心篇中有详细解说,此处不多赘述,只解说用法。
其实前面 open
功用中界说的指令,触发的查找都一致,只是在查找成果挑选今后履行的操作不同,所以不同的指令进来只需履行相同的查找函数即可。
uTools 为开发者供给了几个插件模板,猎豹首要运用了 list
这个模板完结功用开发。
import cp from 'child_process';
import './mount'; // 在 window 挂载上挂载东西函数
import {
filterWithCache,
filterWithSearchResult,
updateHits,
Project,
ResultItem,
COMMAND,
getOpenCommand,
setProjectApp,
} from 'cheetah-core'; // 从中心模块中引进
import {
initCore,
output,
chooseFile,
commandMap,
getAllDefaultApp,
errorHandle,
} from './common'; // uTools 功用适配的函数
const refreshKeyword = '[refresh]'; // 改写关键字,查找字符串中包括此关键字时会疏忽缓存,从头查找项目
/**
* @description: 查找项目
* @param {any} action
* @param {string} keyword 查找关键字
* @param {any} callbackSetList 烘托候选列表的回调
* @return {*}
*/
async function search(
action: any,
keyword: string,
callbackSetList: any
): Promise<void> {
try {
initCore();
const needRefresh: boolean = keyword.includes(refreshKeyword);
const searchKeyword = keyword.replace(refreshKeyword, '');
if (!searchKeyword) return callbackSetList();
let projects: Project[] = await filterWithCache(searchKeyword);
let fromCache = true;
// 假如缓存成果为空或许需求改写缓存,则从头查找
if (!projects.length || needRefresh) {
projects = await filterWithSearchResult(searchKeyword);
fromCache = false;
}
const result: ResultItem[] = output(projects);
if (fromCache) {
result.push({
title: '疏忽缓存从头查找',
description: '以上成果从缓存中获得,挑选本条将从头查找项目并更新缓存',
icon: 'assets/refresh.png',
arg: searchKeyword,
});
}
if (!result.length) {
result.push({
title: `没有找到称号包括 ${searchKeyword} 的项目`,
description: '请测验更换关键词,回车回来从头查找',
icon: 'assets/empty.png',
type: 'empty',
});
}
callbackSetList(result);
} catch (error: any) {
errorHandle(error);
}
}
/**
* @description: 处理点击成果,假如是从头查找会回来跳过
* @param {ResultItem} itemData 被点击的条目
* @return {boolean} 是否需求跳过
*/
function commonSelect(itemData: ResultItem): boolean {
const { arg, type } = itemData;
// 查找成果为空的条目被点击则置空输入框
if (type === 'empty') {
utools.setSubInputValue('');
return true;
}
// 从头查找时重置查找框内容为 [refresh]+关键字
const skip = arg !== null && arg !== undefined;
if (skip) {
utools.setSubInputValue(`${refreshKeyword}${arg}`);
}
return skip;
}
window.exports = {
open: {
mode: 'list',
args: {
search,
// 在查找列表内挑选项目并回车今后,将履行此函数,action 为当时履行
select: async (action: any, itemData: ResultItem) => {
try {
if (commonSelect(itemData)) return;
initCore();
const { payload }: { payload: string } = action;
const commandType = commandMap[payload];
if (commandType === COMMAND.SET_APPLICATION) {
const appPath: string = chooseFile();
setProjectApp(itemData.path!, appPath);
utools.hideMainWindow();
utools.outPlugin();
return;
}
const defaultAppPath = getAllDefaultApp()?.[commandType] ?? '';
const command = await getOpenCommand(
itemData,
commandType,
defaultAppPath
);
cp.exec(command, { windowsHide: true }, (error: any) => {
if (error) {
utools.showNotification(error?.message ?? '不知道过错');
}
updateHits(itemData.path!);
utools.hideMainWindow();
utools.outPlugin();
});
} catch (error: any) {
errorHandle(error);
}
},
},
},
setting: {...}
}
open
下的 mode
字段装备为 list
表明运用 list
模板, args
下为 list
模板在运用时触发的函数,界说如下:
search
uTools 插件子输入框内容变化时调用,第一个参数是描绘当时翻开 open
功用的指令,第二个参数是输入框的值,第三个参数为 Callback
函数,将列表依照文档要求传入即可烘托。
select
在 search
回来的列表中挑选项目后回车时履行,第一个参数与 search
一致,第二个参数为被挑选项意图详细信息。
明白了 list 模板的运用后,就能开端功用的开发了。
首先在 search 中运用中心模块供给的项目查找函数,filterWithSearchResult
,履行查找后成果会被缓存,下一次运用时将直接调用 filterWithCache
从缓存中挑选成果,为了避免项目变动后查找成果不精确,添加了一个手动改写的候选项,最终将查找成果经过 Callback
回来给 uTools 烘托列表。
在查找成果中挑选目标项目回车后履行 select
函数,依据 action.payload
的值以及 itemData
履行不同的操作:
- 在
itemData.type
为empty
时,查找成果为空,挑选空提示项目时仅将子输入框内容置空,能够从头输入关键字查找。 - 当
itemData.arg
不为空时,将子输入框内容改为[refresh]${itemData.arg}
,触发新一轮查找,因为关键词中包括改写关键字,将直接调用filterWithSearchResult
疏忽缓存直接查找项目。 - 排除以上两种状况后,将依据
action.payload
的值运用关联的运用翻开项目。
运用指定运用翻开项目
Mac OS 下运用指定运用翻开文件或许文件夹十分便利,运用以下指令即可:
open -a 运用称号 项目绝对途径
# 例
open -a "Visual Studio Code" /Users/***/Documents/works/test
Windows 下可用的软件比较少,编辑器可用的有 VSCode
,WebStorm
,Sublime
,其余未做更多测验,Git GUI
仅支撑 Fork
,终端仅 CMD
、PowerShell
可用,软件的运用指令为:
"运用途径" "项目途径"
# 例
"D:\Program Files JetBrains\WebStorm 2021.1.1\webstorm.exe" "D:\works\test"
Windows 下终端运转需求经过特别处理:
/**
* @description: windows 下终端指令处理
* @param {string} realAppPath 运用途径
* @param {string} projectPath 项目途径
* @return {*}
*/
function windowsTerminal(realAppPath: string, projectPath: string): string {
if (/powershell/i.test(realAppPath)) {
return `start powershell -NoExit -Command "cd ${projectPath}"`;
}
if (/cmd/i.test(realAppPath)) {
return `start /D ${projectPath}`;
}
throw new Error('109');
}
编辑器翻开项意图优先级规则为:缓存文件内装备的项目编辑器 > 缓存文件内装备的项目类型编辑器 > 设置面板内装备的默许编辑器。
在没有装备任何编辑器时,兜底的是文件浏览器,Mac OS 下为 Finder
,Windows 下为 explorer.exe
。
运用 Git GUI 与终端时也会从本地存储中读取设置面板中装备的相关运用。
铲除缓存
设置面板最下方有一个铲除缓存按钮,能够将缓存文件删去,中心模块中也供给了相关函数,在 uTools 项目中直接调用即可,调用成功后运用 uTools 供给的告诉方式提示铲除成功。
export async function onClearCache(): Promise<void> {
try {
initCore();
await clearCache();
notice('缓存铲除成功');
} catch (error: any) {
errorHandle(error);
}
}
为项目设置软件
猎豹能够为每个项目装备编辑器,在缓存的项目描绘中有个字段是 idePath
,将编辑器称号或许途径装备在此即可。 但是每次装备都要翻开缓存文件找到项目,仿制编辑器称号张贴十分费事,所以直接装备了设置项目运用的指令,此指令也属于 open
功用下,在项目查找列表挑选项目后,直接调用 uTools 供给的文件挑选 API utools.showOpenDialog
,获取到运用信息后直接设置,便利快捷,白叟小孩都会用。
export function chooseFile() {
return utools.showOpenDialog({
filters: [{ extensions: ['app', 'exe', 'lnk'] }],
properties: ['openFile'],
});
}
...
const { payload }: { payload: string } = action;
const commandType = commandMap[payload];
if (commandType === COMMAND.SET_APPLICATION) {
const appPath: string = chooseFile();
setProjectApp(itemData.path!, appPath); // 此函数由中心模块供给
utools.hideMainWindow();
utools.outPlugin();
return;
}
...
过错处理
中心模块中函数会在某些状况下抛出过错,过错信息是以 code
及映射 Map
方式供给,便利后续做国际化,在获取到提示文本后,经过 uTools 供给的告诉 API utools.showNotification
提示用户。
import { ErrorCodeMessage } from 'cheetah-core';
export function notice(message: string) {
utools.showNotification(message)
}
export function errorHandle(error: any) {
const errorCode: number = error.message;
notice(ErrorCodeMessage[errorCode]);
utools.hideMainWindow();
}
提交审阅
完结功用开发后,后边的工作就是发布到插件市场啦~
发布流程如下:
- 构建项目
- 翻开 uTools 开发者东西
- 挑选需求发布的项目
- 选中“发布”选项卡
- 点击右下角的“发布版本”按钮
- 填写版本号,承认打包
plugin.json
所在目录 - 填写版本阐明、插件介绍,上传插件截图
- 提交审阅
⚠️ preload.js
需求坚持明文可读,不然审阅直接不经过。
提交今后就能够去 uTools 开发者交流群催办理员审阅了,哈哈哈哈哈。
小结
至此 Cheetah for uTools 的开发就完结了,当时版本现已更新到 1.2.0
,欢迎各位看官前往下载体验,Cheetah 项目现已开源,假如对插件安全方面有疑虑的能够逐行检查。
Cheetah 插件只运用了 uTools 很小一部分能力,还有很多强壮的功用没有用到,有兴趣的朋友能够移步开发者文档。
下一篇将介绍猎豹 for Alfred 适配中心模块的过程,敬请期待~