zoukankan      html  css  js  c++  java
  • Electron win10命令行调用与系统级别右键菜单项的实现

    我们在使用一些Electron开发的应用程序的时候,可以发现有些程序是可以通过命令行或者右键菜单唤起的。比如VSCode PicGo 那这个要怎么实现呢?

    这里只实现win 平台,其他平台参考:

    https://juejin.cn/post/6844903824709140488#heading-2

    项目初始化

    Electron 项目初始化很简单,这里不做赘述,请参考:

    https://www.cnblogs.com/makalochen/p/14355788.html

    参考里面的用的是 package 一般是用在调试,如果调试完了请用build,代码不用变

    我们需要知道,electron-builder和electron-packager基本类似,不过builder打包完成的是安装包,而packager打包完成的是可执行文件,packager里面有项目源码,builder里面则是编译后的。这可能是两者的最大差别。

    命令行调用

    实现思路

    首先我们要来实现命令行调用。其实Electron的命令行调用没有什么特殊的地方,与在Node.js端很类似,这里写个简单例子,你就明白了

    创建main.js主进程脚本,内容如下

    //为了管理应用程序的生命周期事件以及创建和控制浏览器窗口,您从 electron 包导入了 app 和 BrowserWindow 模块 。
    const { app, BrowserWindow } = require('electron')
    
    //在此之后,你定义了一个创建 新的浏览窗口的函数并将 nodeIntegration 设置为 true,将 index.html 文件加载到窗口中(第 12 行,稍后我们将讨论该文件)
    function createWindow () {
        const win = new BrowserWindow({
             800,
            height: 600,
            webPreferences: {
                nodeIntegration: true
            }
        })
    
        win.loadFile('index.html')
    }
    
    //你通过调用 createWindow方法,在 electron app 第一次被初始化时创建了一个新的窗口。
    app.whenReady().then(createWindow)
    
    //您添加了一个新的侦听器,当应用程序不再有任何打开窗口时试图退出。 由于操作系统的 窗口管理行为 ,此监听器在 macOS 上是禁止操作的
    app.on('window-all-closed', () => {
        if (process.platform !== 'darwin') {
            app.quit()
        }
    })
    
    //您添加一个新的侦听器,只有当应用程序激活后没有可见窗口时,才能创建新的浏览器窗口。 例如,在首次启动应用程序后或重启运行中的应用程序
    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) {
            createWindow()
        }
    })
    
    //应用启动
    app.on('ready', () => {
        /**
         *
         [
         'D:\myCode\my_electron\node_modules\electron\dist\electron.exe',
         '.'
         ] 111111111
         */
        console.log(process.argv, 111111111)
    })
    

    进入 ./out/my_electron-win32-x64目录 运行 my_electron.exe 并带上参数 aaa

    .outmy_electron-win32-x64my_electron.exe aaa
    

    效果

    image-20210218104241702

    关键出现了,我们可以通过process.argv这个在Node.js端获取命令行参数的关键变量同样获得Electron被命令行打开后的命令行参数。那么我们就可以在main进程的ready阶段通过获取的process.argv参数来实现我们对应的功能。

    案例: 命令行调用传入文件路径并读取内容

    定义命令格式

    首先我们定义命令格式,这里要读取我就定义成这样 ,如:

    程序 read 文件路径1 文件路径2
    

    这样可以区分其他动作

    定义主线程文件

    上面的例子都是有窗口界面的,但是我们现在这个例子完全用不上窗口,所以可以将主线程文件内容改成如下内容

    const { app } = require('electron')
    const path = require('path');
    const fs = require('fs-extra');
    //应用启动
    app.on('ready', () => {
    
        const getFiles = (argv = process.argv, cwd = process.cwd()) => {
            // 过滤['D:\myCode\my_electron\out\my_electron-win32-x64\my_electron.exe'', 'read']这两个参数,直接获取文件路径
            let files = argv.slice(2)
            //console.log(files, 'files .........');
            let result = []
            // 如果列表不为空
            if (files.length > 0) {
                result = files.map(item => {
                    // 如果是绝对路径
                    if (path.isAbsolute(item)) {
                        return {
                            path: item
                        }
                    } else {
                        // 如果是相对路径,就拼接
                        let tempPath = path.join(cwd, item)
    
                        // 判断文件是否存在
                        if (fs.existsSync(tempPath)) {
                            return {
                                path: tempPath
                            }
                        } else {
                            return null
                        }
                    }
                }).filter(item => item !== null) // 排除为null的路径
            }
            return result // 返回结果
        }
        //console.log(getFiles() , 33333);
        var files_path = getFiles();
    
        //遍历文件列表
        for(let i = 0; i < files_path.length; i++){
            let item  = files_path[i];
            //读取文件
            var data = fs.readFileSync(item.path, 'utf-8');
            console.log(data, 'file content....');
        }
    })
    

    安装扩展

    npm install fs-extra
    

    重新编译

    npm run make
    

    执行

    .outmy_electron-win32-x64my_electron.exe read .outmy_electron-win32-x64version
    

    效果

    image-20210218115627592

    系统级别右键菜单

    如何实现?

    Windows的右键菜单的原理其实很简单,在注册表里写入值就行。这里不会对Windows注册表的知识做过多的展开(自行百度)。我们只关注往哪里写值,写哪些值才能实现我们要的效果。

    首先我们可以看看PicGo是如何实现右键菜单「Upload pictures w&ith PicGo」

    image-20210218134847802

    在系统里按快捷键WIN+R然后输入regedit打开注册表编辑器,我们来找到PicGo的右键菜单所在地:

    HKEY_CLASSES_ROOT*shellPicGo
    

    image-20210218135116131

    可以看到一个「默认」的属性下的数据为「Upload pictures w&ith PicGo」,这个就是我们看到的菜单名。而一个叫「Icon」的属性下的数据为PicGoexe安装路径。所以可以认为这个Icon可以获取exeIcon并显示到菜单上。

    不过这里还没有看到如何将文件路径作为参数传入PicGo的。继续看:

    HKEY_CLASSES_ROOT*shellPicGocommand
    

    image-20210218135452753

    可以看出这个%1就是作为参数传给PicGo.exe的。有了PicGo作为参考,给自己的Electron应用实现一个系统级别的右键菜单也不难了。有人可能会说我可以在应用启动阶段通过某些npm包(比如windows-registry)来实现对注册表的写入。

    通过electron-builder实现

    实际上,在Windows平台,如果你是用electron-builder打包的话有一个更简洁的解决方案,那就是编写NSIS脚本来实现,对此electron-builder官方给出的文档可以一看。

    本文不对NSIS脚本做过多的描述,你只需要知道它是用来生成Windows安装界面的一门脚本语言,你可以通过它来控制安装(卸载)界面都有哪些元素。并且它可以接入安装的生命周期,做一些操作,比如写入注册表。我们利用这个特性,来给程序做一个安装阶段写入注册表的操作,实现系统级别的右键菜单。

    electron-builderNSIS暴露的钩子主要有customHeader, preInit, customInit, customInstall, customUnInstall,等等。

    我们可以在customInstall阶段通过获取用户安装程序的路径$INSTDIR来实现对注册表关键值的写入。自己书写的installer.nsh默认放在项目的build目录下,那么electron-builder在构建Windows应用的时候将会自动读取这个文件以及package.json里的配置来生成安装界面。

    写入注册表的格式大概是这样:

    WriteRegStr <reg-path> <your-reg-path> <attr-name> <value>
    

    以下是PicGoinstaller.nsh,参考:

    !macro customInstall
    WriteRegStr HKCR "*shellPicGo" "" "Upload pictures w&ith PicGo"
    WriteRegStr HKCR "*shellPicGo" "Icon" "$INSTDIRPicGo.exe"
    WriteRegStr HKCR "*shellPicGocommand" "" '"$INSTDIRPicGo.exe" "upload" "%1"'
    !macroend
    !macro customUninstall
    DeleteRegKey HKCR "*shellPicGo"
    !macroend
    

    注意HKCR即是注册表目录HKEY_CLASSES_ROOT的缩写。在写value的时候如果要写多个参数,可以用单引号包起来。attr-name不写即为默认。相信有了PicGo的右键菜单注册表说明,你也能看得懂上面的PicGo的脚本了。同时注意我们应该在卸载阶段将之前写的注册表删除,以免用户卸载了应用之后菜单还在,上述脚本的后面部分是是在做这个事情。

    因为上一章实现了命令行调用,所以我们的菜单就可以通过'"$INSTDIRPicGo.exe" "upload" "%1"'来实现菜单调用命令了。

    参考自:

    https://juejin.cn/post/6844903824709140488#heading-7

    例:定义NSIS脚本安装时写入注册表和卸载删除注册表

    添加文件build/installer.nsh

    注意路径一定不能错,默认是这个路径,会自动读取配

    ;安装时写入
    !macro customInstall
       WriteRegStr HKCR "*shellmy_electron" "" "测试........"
       WriteRegStr HKCR "*shellmy_electron" "Icon" "$INSTDIRmy_electron.exe"
       WriteRegStr HKCR "*shellmy_electroncommand" "" '"$INSTDIRmy_electron.exe" "read" "%1"'
    !macroend
    ;卸载时清除
    !macro customUninstall
       DeleteRegKey HKCR "*shellmy_electron"
    !macroend
    

    !macro customInstall 表示安装时触发,下面的三项都是注册表的值

    !macro customUninstall表示卸载时触发

    有关nsis 脚本的参考手册

    https://omega.idv.tw/nsis/Contents.html

    niss 脚本基础参考

    https://www.cnblogs.com/jingmoxukong/p/5033622.html

    image-20210218144600078

    安装electron-builder

    npm install electron-builder --save-dev
    

    配置electron-builder

    添加scripts脚本

    参考:

    https://www.cnblogs.com/yuNotes/p/12957018.html

    https://www.e-learn.cn/topic/3904742

    "build": "electron-builder"
    

    image-20210218152214613

    配置electron-builder配置项

    参考:

    https://www.electron.build/configuration/configuration

    也可以不用配置,都有默认配置

    常见配置参考

    "build": {  // electron-builder配置
        "productName":"xxxx",//项目名 这也是生成的exe文件的前缀名
        "appId": "xxxxx",//包名  
        "copyright":"xxxx",//版权  信息
        "compression": "store", // "store" | "normal"| "maximum" 打包压缩情况(store 相对较快),store 39749kb, maximum 39186kb
        "directories": {
            "output": "build" // 输出文件夹
        }, 
        "asar": false, // asar打包
        "extraResources":  { // 拷贝dll等静态文件到指定位置
            "from": "./app-update.yml",
            "to": "./b.txt"
        },
        "win": {  
            "icon": "xxx/icon.ico"//图标路径,
            "extraResources":  { // 拷贝dll等静态文件到指定位置(用于某个系统配置)
                "from": "./app-update.yml",
                "to": "./b.txt"
            }
        },
        "nsis": {
            "oneClick": false, // 一键安装
            "guid": "xxxx", //注册表名字,不推荐修改
            "perMachine": true, // 是否开启安装时权限限制(此电脑或当前用户)
            "allowElevation": true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
            "allowToChangeInstallationDirectory": true, // 允许修改安装目录
            "installerIcon": "./build/icons/aaa.ico", // 安装图标
            "uninstallerIcon": "./build/icons/bbb.ico", //卸载图标
            "installerHeaderIcon": "./build/icons/aaa.ico", // 安装时头部图标
            "createDesktopShortcut": true, // 创建桌面图标
            "createStartMenuShortcut": true, // 创建开始菜单图标
            "shortcutName": "xxxx" // 图标名称
        }
      }
    
    例:自定义niss安装配置
    "nsis": {
          "shortcutName": "my_electron",
          "oneClick": false,
          "allowElevation": true,
          "allowToChangeInstallationDirectory": true,
          "perMachine": true,
          "include": "./build/installer.nsh"
        }
    

    image-20210220152611474

    执行打包

    npm run build
    

    image-20210218152923797

    安装和卸载测试

    安装,直接双击my_electron Setup 1.0.0.exe进行安装

    image-20210218153153700

    查看注册表

    注意要F5刷新

    image-20210220163127477

    image-20210220163147743

    卸载

    image-20210220163621141

    可以看到已经清除

  • 相关阅读:
    【zookeeper】
    关于redis-windows环境下的一些配置:
    mybatis-注解开发
    jQuery的Validate插件
    Thymeleaf 学习笔记-实例demo(中文教程)
    thymeleaf 学习笔记-基础篇(中文教程)
    AGC 043C
    JOISC 2020 部分题解
    Loj #2687
    CF 1270I
  • 原文地址:https://www.cnblogs.com/makalochen/p/14422008.html
Copyright © 2011-2022 走看看