用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)
    }
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM