zoukankan      html  css  js  c++  java
  • 用Electron开发企业网盘(一)--通信

    效果展示 

     项目背景:

    由于浏览器的限制,web批量下载体验不好以及无法下载文件夹。采用Electron技术,通过js开发PC应用程序,着力解决批量下载、断点续传、文件夹下载等问题。配合网页版网盘使用,单个小文件使用浏览器内置下载,单个大文件、多文件、文件夹调用PC应用程序,提升下载体验。

    技术栈

    Electron项目的目的,是为了要避免使用 vue 手动建立起 electron 应用程序。electron-vue 充分利用 vue-cli 作为脚手架工具,加上拥有 vue-loader 的 webpackelectron-packager 或是 electron-builder,以及一些最常用的插件,如vue-routervuex 等等。

    技术点分析

    1、web、PC应用程序通信

    官方描述:

     app.setAsDefaultProtocolClient(protocol[, path, args])

    • protocol String - 协议的名称, 不包含 ://。 如果您希望应用程序处理 electron:// 的链接, 请将 electron 作为该方法的参数.
    • path String (可选) Windows -默认为 process.execPath
    • args String[] (可选) Windows - 默认为空数组

    返回 Boolean -是否成功调用。

    此方法将当前可执行文件设置为协议(也称为URI方案) 的默认处理程序。 它允许您将应用程序更深入地集成到操作系统中。 一旦注册成功, 所有 your-protocol:// 格式的链接都会使用你的程序打开。 整个链接 (包括协议) 将作为参数传递给您的应用程序。

    在 Windows 系统中,你可以提供可选参数 path,可执行文件的路径和 args (在启动时传递给可执行文件的参数数组)

    注意: 在 macOS 上, 您只能注册已添加到应用程序的 info. plist 中的协议, 在运行时不能对其进行修改。 但是,您可以在构建时使用简单的文本编辑器或脚本更改文件。 有关详细信息,请参阅 Apple's documentation

    API 在内部使用 Windows 注册表和 LSSetDefaultHandlerForURLScheme。

    获取参数:

    主要分为两个阶段:一是初次启动应用,而是应用已启动打开链接时。

    阶段一:

    webContents渲染以及控制web页面,是BrowserWindow对象的一个属性。

    Event:'did-finish-load'

    导航完成时触发,即选项卡的旋转器将停止旋转,并指派 onload 事件后。

    contents.on('did-finish-load', () => {
        getPath().then(dir => {
          setDir(dir)
          fileList("DOWN_FILE_LIST_FLAG__804e62a93de9fda85bb6ca68b20d3d6d")
          if(macOpenUrl != ''){//macOS
            fileList(macOpenUrl)
          }else{
            try {
              let str = process.argv.slice(1)[0].split('//')[1]
              let downloadFlag = str.slice(0, str.length - 1)
              fileList(downloadFlag)  
            } catch (e) { console.log(e) }
          }
    
          let httpList = deepList('.cfg')
          contents.send('download', httpList)
        })
      })

    阶段二:

    应用已启动时,用户打开URL。macOS有直接可捕捉的事件,Windows需要通过单实例的方法捕捉参数。

    事件: 'open-url' macOS

    返回:

    • event Event
    • url String

    当用户想要在应用中打开一个 URL 时发出。 应用程序的 Info. plist 文件必须在 CFBundleURLTypes 项中定义 url 方案, 并将 NSPrincipalClass 设置为 AtomApplication 

    如果你想处理这个事件,你应该调用 event.preventDefault() 。

    app.on("open-url", function(event, url) {
      //macOS:先进入open-url,再进入did-finish-load
      let downloadFlag = url.split('//')[1]
      macOpenUrl = downloadFlag
      if (mainWindow) {
        if (mainWindow.isMinimized()) mainWindow.restore()
        mainWindow.focus()
        try {
            fileList(downloadFlag)
        } catch (e) { console.log(e) }
      }
    })

    app.makeSingleInstance()

    返回 Boolean

    此方法使应用程序成为单个实例应用程序, 而不是允许应用程序的多个实例运行, 这将确保只有一个应用程序的实例正在运行, 其余的实例全部会被终止并退出。

    const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => {
      // Someone tried to run a second instance, we should focus our window.
      if (mainWindow) {
        if (mainWindow.isMinimized()) mainWindow.restore()
        mainWindow.focus()
        try {   
          //dialog.showErrorBox('makeSingleInstance', commandLine.toString())
          let str = commandLine.slice(1)[0].split('//')[1]
          let downloadFlag = str.slice(0, str.length - 1)
          fileList(downloadFlag)
        } catch (e) { console.log(e) }
      }
    })

    URL长度限制问题:

     基于项目背景,web、PC应用程序需要传递文件列表。一开始的想法是整个文件列表通过URL传递,后来调试的时候发现:受限于URL的长度限制,可以传递的文件项十分有限。于是另寻他路,通过后台中转:web选中文件后,调用后台接口,生成下载标识位,传递给PC应用程序。PC应用程序那边获取到下载标识位后,通过下载标识位再请求后台接口获取下载列表。

    2、文件重命名算法

     文件名的完整含义是文件的完整路径,如:D:/tmp/新建文件夹/002.docx。文件重命名有两个场景:一是当前的文件列表内,如果存在同名的文件,需要对当前的文件重命名,算法同windows文件重命名算法。二是文件保存到本地路径时,如果当前路径存在同名的文件,需要对当前的文件重命名,算法同windows文件重命名算法。

    方法:fireRename(arr, basename, key)

    • arr Arrary - 文件列表
    • basename String 当前文件的文件名
    • key String(可选) 文件列表内每个对象文件名的关键字

    文件重命名,返回重命名后的文件名。

    const fileRename = (arr, basename, key) => {
      let existed
      arr.forEach((e, i) => {
        if (e[key] == basename) {
          existed = true
        }
      })
      if (!existed) {
        return basename
      }
      let extname = path.extname(basename)
      let re = new RegExp('(\(\d\))*' + extname + '$')
      const compare = (c, b) => {
        return c.replace(re, '') == b.replace(re, '')
      }
      let arr_existed = []
      arr.forEach((e, i) => {
        let c = e[key]
    
        if (compare(c, basename)) {
          arr_existed.push(e[key].replace(c.replace(re, ''), ''))
        }
      })
      
      for (let i = 1; i < arr_existed.length + 2; i += 1) {
        if (arr_existed.indexOf('(' + i + ')' + extname) == -1) {
          return basename.replace(re, '(' + i + ')' + extname)
        }
      }
    }
  • 相关阅读:
    ASCII码表以及不同进制间的O(1)转换
    四则运算表达式的语法分析
    语法分析器初步学习——LISP语法分析
    ASC与HEX之间的转换
    字节存储数据
    进制之间的转换
    java多线程CountDownLatch
    java反射机制
    java注解
    使用javafx实现视频播放器
  • 原文地址:https://www.cnblogs.com/shawnyung/p/10060119.html
Copyright © 2011-2022 走看看