<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    本文由環(huán)信技術(shù)黃飛鵬分享,原題“實戰(zhàn)|如何利用 Electron 快速開發(fā)一個桌面端應用”,本文進行了排版和內(nèi)容優(yōu)化等。

    1、引言

    早就聽說利用Electron可以非常便捷的將網(wǎng)頁端快速打包成桌面應用,并且利用 Electron 提供的 API 調(diào)用可以使用原生桌面 API 一些高級功能。于是這次借著論證 Web IM端 SDK 是否可以在 Electron 生成的桌面端正常穩(wěn)定使用,我決定把官方新推出的 webim-vue3-demo,打包到桌面端,并記錄了這次驗證的過程以及所遇到的問題和解決方法。

    2、系列文章

    本文是系列文章中的第11篇,本系列總目錄如下:

    IM跨平臺技術(shù)學習(一):快速了解新一代跨平臺桌面技術(shù)——Electron

    IM跨平臺技術(shù)學習(二):Electron初體驗(快速開始、跨進程通信、打包、踩坑等)

    IM跨平臺技術(shù)學習(三):vivo的Electron技術(shù)棧選型、全方位實踐總結(jié)

    IM跨平臺技術(shù)學習(四):蘑菇街基于Electron開發(fā)IM客戶端的技術(shù)實踐

    IM跨平臺技術(shù)學習(五):融云基于Electron的IM跨平臺SDK改造實踐總結(jié)

    IM跨平臺技術(shù)學習(六):網(wǎng)易云信基于Electron的IM消息全文檢索技術(shù)實踐

    IM跨平臺技術(shù)學習(七):得物基于Electron開發(fā)客服IM桌面端的技術(shù)實踐

    IM跨平臺技術(shù)學習(八):新QQ桌面版為何選擇Electron作為跨端框架

    IM跨平臺技術(shù)學習(九):全面解密新QQ桌面版的Electron內(nèi)存占用優(yōu)化

    IM跨平臺技術(shù)學習(十):快速選型跨平臺框架Electron、Flutter、Tauri、React Native等

    IM跨平臺技術(shù)學習(十一):環(huán)信基于Electron打包WebIM桌面端的技術(shù)實踐》(* 本文

    3、前置技能

    • 1)擁有良好的情緒自我管理,能夠在遇到棘手問題時不一拳給到鍵盤;
    • 2)擁有較為熟練的水群能力,能夠在遇到問題時,主動向技術(shù)群內(nèi)參差不齊的群友們拋出自己的問題;
    • 3)重要的是,要擁有較為熟練的搜索引擎使用能力;
    • 4)能夠看到這篇文章,那說明以上能力你已完全具備。

    PS:不開玩笑的說,開始Electron的踩坑之前,肯定還是要對Electron的方方面面有所了解才能磨刀不誤砍柴工,建議從《快速了解新一代跨平臺桌面技術(shù)——Electron》、《Electron初體驗(快速開始、跨進程通信、打包、踩坑等)》這兩篇開始。

    4、第1步:準備工作

    • 1)克隆 vue3 Demo 項目到本地(vue3-demo的源碼地址);
    • 2)在編輯器內(nèi)打開此項目并執(zhí)行yarn install安裝項目相關(guān) npm 依賴;
    • 3)在此項目目錄下打開終端請敲下yarn add electron,從而在該項目中安裝 electron;
    • 4)安裝一些依賴工具wait-on以及cross-env。

    PS:如果訪問vue3 Demo的Github倉庫太慢,可以直接下載以下附件:

     webim-vue-demo(demo-vue3).zip (1.05 MB , 下載次數(shù): 0 , 售價: 1 金幣)

    wait-on:它是一個 Node.js 包,它可以用于等待多個指定的資源(如 HTTP 資源、TCP 端口或文件)變得可用。它通常用于等待應用程序的依賴項準備好后再啟動應用程序。例如,您可以使用 wait-on 等待數(shù)據(jù)庫連接、消息隊列和其他服務就緒后再啟動您的應用程序。這樣可以確保您的應用程序在嘗試使用這些資源之前不會崩潰。

    cross-env:是一個 npm 包,它的作用是在不同平臺上設(shè)置環(huán)境變量。在不同操作系統(tǒng)中,設(shè)置環(huán)境變量的方式是不同的。例如,在 Windows 中使用命令 set NODE_ENV=production 設(shè)置環(huán)境變量,而在 Unix/Linux/Mac 上則需要使用 export NODE_ENV=production 命令。

    此時可能會進入到漫長的等待階段(第一、這個包本身就比較大,第二、相信大家都懂由于網(wǎng)絡原因?qū)е拢⑶矣锌赡苓M行會經(jīng)歷幾次TIMOUT安裝失敗。此時就需要心平氣和,且有耐心的進行改變鏡像地址、科學進行上網(wǎng),WIFI切換為移動流量多去重試幾次,相信道友你總會成功過的。

    有如下輸出則應該為安裝成功:

    5、第2步:項目目錄增加 Electron 文件

    在項目增加 Electron 文件時我們需要擴展一部分知識從而了解為什么創(chuàng)建創(chuàng)建這個目錄,并在該目錄下增加main.js文件的作用。當然如果覺得不需要可以直接略過。

    5.1主進程與渲染進程的概念

    在 Electron 中,主進程和渲染進程是兩個不同的概念。主進程是 Electron 應用程序的核心,它運行在一個 Node.js 實例中,并管理應用程序的生命周期、窗口創(chuàng)建和銷毀、與底層操作系統(tǒng)進行交互等。主進程還可以通過 IPC(進程間通信)機制與渲染進程進行通信。

    渲染進程則是應用程序的 UI 界面所在的進程。每個 Electron 窗口都有其自己的渲染進程。渲染進程是一個 Chromium 渲染引擎實例,它運行在一個僅包含 Web API 的環(huán)境中。渲染進程負責渲染 HTML、CSS 和 JavaScript,并處理來自用戶的輸入事件,同時通過 IPC 機制與主進程進行通信。

    由于渲染進程只能訪問 Web API 而不能直接訪問 Node.js API,因此如果需要在渲染進程中使用 Node.js API,就需要通過 IPC 機制向主進程發(fā)出請求,由主進程代為執(zhí)行并將結(jié)果返回給渲染進程。

    PS:關(guān)于Electron的進程知識,可以詳讀《Electron初體驗(快速開始、跨進程通信、打包、踩坑等)》一文的“5、進程詳解”一節(jié)。

    5.2主進程與渲染進程分別應該寫在哪?

    在 Electron 應用程序中,主進程通常寫在名為 main.js 或者 index.js 的 JavaScript 文件中,這個文件是應用程序的入口點。

    而渲染進程則通常寫在 HTML 文件和其引入的 JavaScript 文件中。在一個 Electron 窗口中,可以通過調(diào)用 webContents 對象的 loadURL 方法來加載一個 HTML 文件,其中包含了渲染進程所需的代碼和資源。該 HTML 文件中的 JavaScript 代碼將運行在對應的渲染進程中,可以通過 Electron 提供的一些 API 和 Web API 來進行與用戶界面相關(guān)的操作。

    需要注意的是,在 Electron 中,由于主進程和渲染進程是不同的 Node.js 實例,因此它們之間并不能直接共享變量或者調(diào)用函數(shù)。如果想要實現(xiàn)主進程和渲染進程之間的通信,必須使用 Electron 提供的 IPC 機制,通過發(fā)送消息的方式來進行進程間通信。

    5.3有些 Electron 文件目錄下 preload.js 的作用

    在 Electron 中,preload.js 文件是一個可選的 JavaScript 文件,用于在渲染進程創(chuàng)建之前加載一些額外的腳本或者模塊,從而擴展渲染進程的能力。preload.js 文件通常存放在與主進程代碼相同的目錄下。

    preload.js 的實際運用主要有以下幾個方面。

    1)托管 Node.js API:preload.js 中可以引入 Node.js 模塊,并將其暴露到 window 對象中,從而使得在渲染進程中也能夠使用 Node.js API,避免了直接在渲染進程中調(diào)用 Node.js API 帶來的安全風險;

    2)擴展 Web API:preload.js 中還可以定義一些自定義的函數(shù)或者對象,然后將它們注入到 window 對象中,這樣在渲染進程中就可以直接使用它們了,而無需再進行額外的導入操作;

    3)進行一些初始化操作:preload.js 文件中的代碼會在每個渲染進程的上下文中都運行一遍,在這里可以進行一些初始化操作,比如為頁面添加一些必要的 DOM 元素、為頁面注冊事件處理程序等。

    需要注意的是:preload.js 文件中的代碼運行在渲染進程的上下文中,因此如果 preload.js 中包含一些惡意代碼,那么它很可能會危及整個渲染進程的安全性。因此,在編寫 preload.js 文件時,一定要格外小心,并且僅引入那些你信任的模塊和對象。

    1) 添加 Electron 文件(此時項目目錄):

    2) Electron 下新建main.js示例代碼如下:

    const { app, BrowserWindow } = require('electron');

    const path = require('path');

    const NODE_ENV = process.env.NODE_ENV;

    app.commandLine.appendSwitch('allow-file-access-from-files');

    function createWindow() {

      // Create the browser window.

      const mainWindow = new BrowserWindow({

        width: 980,

        height: 680,

        fullscreen: true,

        skipTaskbar: true,

        webPreferences: {

          nodeIntegration: true,

          preload: path.join(__dirname, 'preload.js'),

        },

      });

     

      if (NODE_ENV === 'development') {

        mainWindow.loadURL('http://localhost:9001/');

        mainWindow.webContents.openDevTools();

      } else {

        mainWindow.loadURL(`file://${path.join(__dirname, '../dist/index.html')}`);

      }

    }

     

    // This method will be called when Electron has finished

    // initialization and is ready to create browser windows.

    // Some APIs can only be used after this event occurs.

     

    app.whenReady().then(() => {

      createWindow();

    });

     

    // Quit when all windows are closed, except on macOS. There, it's common

    // for applications and their menu bar to stay active until the user quits

    // explicitly with Cmd + Q.

    app.on('window-all-closed', function () {

      if (process.platform !== 'darwin') app.quit();

    });

    3)Electron 下新建preload.js,示例代碼如下(此文件為可選文件):

    //允許vue項目使用 ipcRenderer 接口, 演示項目中沒有使用此功能

    const { contextBridge, ipcRenderer } = require('electron');

    contextBridge.exposeInMainWorld('ipcRender', ipcRenderer);

    4)修改package.json:

    當前示例代碼如下:

    • 1)修改"main"配置,將其指向為"main": "electron/main.js";
    • 2)增加一個針對 electron 啟動的"scripts","electron:dev": "wait-on tcp:3000 && cross-env NODE_ENV=development electron ./"。

    當前項目配置如下所示:

    {

      "name": "webim-vue3-demo",

      "version": "0.1.0",

      "private": true,

      "main": "electron/main.js",

      "scripts": {

        "dev": "vue-cli-service serve",

        "build": "vue-cli-service build",

        "lint": "vue-cli-service lint",

        "electron:dev": "wait-on tcp:9001 && cross-env NODE_ENV=development  electron ./"

      },

      "dependencies": {

        "@vueuse/core": "^8.4.2",

        "agora-rtc-sdk-ng": "^4.14.0",

        "axios": "^0.27.2",

        "benz-amr-recorder": "^1.1.3",

        "core-js": "^3.8.3",

        "easemob-websdk": "^4.1.6",

        "element-plus": "^2.2.5",

        "nprogress": "^0.2.0",

        "pinyin-pro": "^3.10.2",

        "vue": "^3.2.13",

        "vue-router": "^4.0.3",

        "vuex": "^4.0.0"

      },

      "devDependencies": {

        "@babel/core": "^7.12.16",

        "@babel/eslint-parser": "^7.12.16",

        "@vue/cli-plugin-babel": "~5.0.0",

        "@vue/cli-plugin-eslint": "~5.0.0",

        "@vue/cli-plugin-router": "~5.0.0",

        "@vue/cli-plugin-vuex": "~5.0.0",

        "@vue/cli-service": "~5.0.0",

        "cross-env": "^7.0.3",

        "electron": "^24.3.1",

        "eslint": "^7.32.0",

        "eslint-plugin-vue": "^8.0.3",

        "sass": "^1.51.0",

        "sass-loader": "^12.6.0",

        "wait-on": "^7.0.1"

      }

    }

    6、第3步:本地啟動起來驗證一下

    6.1啟動運行原 vue 項目

    這里啟動項目至端口號 9001,跟上面 electron/main.jsmainWindow.loadURL(' http://localhost:9001/')是可以對應上的,也就是 Electron 運行起來將會加載此服務地址。

    yarn run dev

    6.2新開終端,啟動Electron

    新開一個終端執(zhí)行,輸入下方命令啟動 Electron。

    執(zhí)行下面命令:

    yarn run electron:dev

     

    并且經(jīng)過測試驗證登錄沒有什么問題。

    7、第4步:嘗試打包并驗證打包出來的安裝包是否可用

    7.1安裝electron-builder

    該工具為 Electron 打包工具庫,點擊打開electron-builder 官方文檔

    終端執(zhí)行下面命令安裝 electron-builder:

    yarn add electron-builder --dev

    7.2配置打包腳本命令及個性化配置項

    package.json 配置打包腳本命令以及設(shè)置打包個性化配置項。

    具體配置項作用請參考官網(wǎng)文檔,下面有些配置也是 CV 大發(fā)過來的,沒有具體深入研究。

    {

      "name": "webim-vue3-demo",

      "version": "0.1.0",

      "private": true,

      "main": "electron/main.js",

      "scripts": {

        "dev": "vue-cli-service serve",

        "build": "vue-cli-service build",

        "lint": "vue-cli-service lint",

        "electron:dev": "wait-on tcp:9001 && cross-env NODE_ENV=development  electron ./",

        "electron:build": "rimraf dist &&  vue-cli-service build &&  electron-builder",

        "electron:build2": "electron-builder"

      },

      "dependencies": {

        "@vueuse/core": "^8.4.2",

        "agora-rtc-sdk-ng": "^4.14.0",

        "axios": "^0.27.2",

        "benz-amr-recorder": "^1.1.3",

        "core-js": "^3.8.3",

        "easemob-websdk": "^4.1.6",

        "element-plus": "^2.2.5",

        "nprogress": "^0.2.0",

        "pinyin-pro": "^3.10.2",

        "vue": "^3.2.13",

        "vue-router": "^4.0.3",

        "vuex": "^4.0.0"

      },

      "devDependencies": {

        "@babel/core": "^7.12.16",

        "@babel/eslint-parser": "^7.12.16",

        "@vue/cli-plugin-babel": "~5.0.0",

        "@vue/cli-plugin-eslint": "~5.0.0",

        "@vue/cli-plugin-router": "~5.0.0",

        "@vue/cli-plugin-vuex": "~5.0.0",

        "@vue/cli-service": "~5.0.0",

        "cross-env": "^7.0.3",

        "electron": "^24.3.1",

        "electron-builder": "^23.6.0",

        "eslint": "^7.32.0",

        "eslint-plugin-vue": "^8.0.3",

        "sass": "^1.51.0",

        "sass-loader": "^12.6.0",

        "wait-on": "^7.0.1"

      },

      "build": {

        "productName": "webim-electron",

        "appId": "com.lvais",

        "copyright": "2023@easemob",

        "directories": {

          "output": "output"

        },

        "extraResources": [

          {

            "from": "./src/assets",

            "to": "./assets"

          }

        ],

        "files": ["dist/**/*", "electron/**/*"],

        "mac": {

          "artifactName": "${productName}_${version}.${ext}",

          "target": ["dmg"]

        },

        "win": {

          "target": [

            {

              "target": "nsis",

              "arch": ["x64"]

            }

          ],

          "artifactName": "${productName}_${version}.${ext}"

        },

        "nsis": {

          "oneClick": false,

          "allowElevation": true,

          "allowToChangeInstallationDirectory": true,

          "createDesktopShortcut": true

        },

        "linux": {}

      }

    }

    7.3開始 build

    先這樣——build 原始 vue 項目:

    yarn run build

    再那樣——build Electron 項目:

    yarn run electron:build

    可能會進入漫長的等待,但是不要慌,可能與網(wǎng)絡關(guān)系比較大,需要耐心等待。

    打包成功之后可以看到有一個 output 文件夾的生成,打開之后可以選擇雙擊打開軟件驗證看下是否可以正常開啟應用。

    8、 痛苦踩坑1:打包后頁面空白等

    8.1概述

    打包后頁面空白并出現(xiàn)類似“Failed to load resource: net::ERR_FILE_NOT_FOUND”的報錯。

    問題簡述:發(fā)現(xiàn)只有在打包之后的 Electron 應用,啟動后存在頁面空白,dev 情況下正常。

    8.2解決手段1

    經(jīng)排查,更改vue.config.js中publicPath的配置為‘./’。

    const { defineConfig } = require('@vue/cli-service');

    module.exports = defineConfig({

      transpileDependencies: true,

      lintOnSave: false,

      devServer: {

        host: 'localhost',

        port: 9001,

        // https:true

      },

      publicPath: './',

      chainWebpack: (config) => {

        //最小化代碼

        config.optimization.minimize(true);

        //分割代碼

        config.optimization.splitChunks({

          chunks: 'all',

        });

      },

    });

    原因是:打包后的應用 Electron 會從相對路徑開始找資源,所以經(jīng)過此配置可以所有資源則開始從相對路徑尋找。

    默認情況下:Vue CLI 會假設(shè)你的應用是被部署在一個域名的根路徑上,例如 https://www.my-app.com/。如果應用被部署在一個子路徑上,你就需要用這個選項指定這個子路徑。

    例如:如果你的應用被部署在 https://www.my-app.com/my-app/,則設(shè)置 publicPath為 /my-app/。這個值也可以被設(shè)置為空字符串 ('') 或是相對路徑 ('./'),這樣所有的資源都會被鏈接為相對路

    8.3解決手段2

    經(jīng)過一頓操作之后發(fā)現(xiàn)仍然還是空白,并且打開控制臺看到頁面可以正常加載資源文件,但是 index.html 返回此類錯誤:“We're sorry but XXX doesn't work properly without JavaScript”,經(jīng)過查找發(fā)現(xiàn)可以通過修改路由模式來解決,經(jīng)過測試確實有效。

    參考文章為:vue3項目打包時We're sorry but XXX doesn't work properly without JavaScript》。

    修改后的代碼示例:

    const router = createRouter({

      //改為#則可以直接變更路由模式

      history: createWebHistory('#'),

      routes,

    });

    9、痛苦踩坑2:頁面展示正常后,調(diào)用登錄報錯

    問題簡述:頁面展示正常后,調(diào)用登錄發(fā)現(xiàn)出現(xiàn)如下圖所示的報錯。

     

    解決方式:經(jīng)發(fā)現(xiàn)原來是發(fā)起 axios 請求環(huán)信置換連接 token 接口的時候,協(xié)議的獲取是通過window.location.protocol來獲取的,那么打包之后的協(xié)議為file:那么這時發(fā)起的請求就會變更為以 file 協(xié)議發(fā)起的請求,那么修改這里的邏輯,判斷如果為 file 協(xié)議則默認走 http 協(xié)議發(fā)起請求。

    示例代碼如下:

    import axios from 'axios';

    const defaultBaseUrl = '//a1.easemob.com';

    console.log('window.location.protocol', window.location.protocol);

    // create an axios instance

    const service = axios.create({

      withCredentials: false,

      // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url

      baseURL: `${

        window.location.protocol === 'file:' ? 'https:' : window.location.protocol

      }${defaultBaseUrl}`,

      // withCredentials: true, // send cookies when cross-domain requests

      timeout: 30000, // request timeout

      headers: { 'Content-Type': 'application/json' },

    });

    // request interceptor

    service.interceptors.request.use(

      (config) => {

        // do something before request is sent

        return config;

      },

      (error) => {

        // do something with request error

        console.log('request error', error); // for debug

        return Promise.reject(error);

      }

    );

     

    // response interceptor

    service.interceptors.response.use(

      /**

       * If you want to get http information such as headers or status

       * Please return  response => response

       */

     

      /**

       * Determine the request status by custom code

       * Here is just an example

       * You can also judge the status by HTTP Status Code

       */

      (response) => {

        const res = response.data;

        const code = response.status;

        // if the custom code is not 20000, it is judged as an error.

        if (code >= 400) {

          return Promise.reject(new Error(res.desc || 'Error'));

        } else {

          return res;

        }

      },

      (error) => {

        if (error.response) {

          const res = error.response.data; // for debug

          if (error.response.status === 401 && res.code !== '001') {

            console.log('>>>>>無權(quán)限');

          }

          if (error.response.status === 403) {

            res.desc = '您沒有權(quán)限進行查詢和操作!';

          }

          return Promise.reject(res.desc || error);

        }

        return Promise.reject(error);

      }

    );

     

    export default service;

    10、參考資料

    [1] Electron官方文檔

    [2] 快速了解新一代跨平臺桌面技術(shù)——Electron

    [3] Electron初體驗(快速開始、跨進程通信、打包、踩坑等)

    [4] Electron + Vue3 + TS + Vite 桌面應用項目搭建教程

    [5] Electron + Vue3 +Ant Design Vue 桌面應用從項目搭建到打包發(fā)布

    [6] vivo的Electron技術(shù)棧選型、全方位實踐總結(jié)

    [7] 一文讀懂前端技術(shù)演進:盤點Web前端20年的技術(shù)變遷史

    [8] 詳解Web端通信方式的演進:從Ajax、JSONP 到 SSE、Websocket

    [9] WebSocket從入門到精通,半小時就夠!

    (本文已同步發(fā)布于:http://www.52im.net/thread-4666-1-1.html



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發(fā)交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 亚洲韩国精品无码一区二区三区| 国产高清不卡免费视频| 老司机在线免费视频| 噜噜噜亚洲色成人网站∨| 久久国产免费一区| 亚洲综合无码一区二区| 日本zzzzwww大片免费| 亚洲成人黄色网址| 2021免费日韩视频网| 亚洲熟妇无码一区二区三区导航| 欧洲精品免费一区二区三区| 亚洲成AV人片在WWW| 免费国产成人午夜电影| 思思久久99热免费精品6| 亚洲精品色婷婷在线影院| 国产日韩AV免费无码一区二区三区| 国产成A人亚洲精V品无码| 久久久久久精品成人免费图片| 亚洲国产精品综合久久久| 日本免费观看网站| CAOPORM国产精品视频免费| 亚洲AV永久精品爱情岛论坛| 在线免费中文字幕| 亚洲第一综合天堂另类专| MM131亚洲国产美女久久| 91香蕉在线观看免费高清| 亚洲色偷偷偷综合网| 亚洲中文字幕在线观看| 成人免费视频69| 老司机福利在线免费观看| 国产亚洲av片在线观看播放| 99国产精品永久免费视频| 极品美女一级毛片免费| 亚洲视频在线观看| 四虎影视在线永久免费观看| 久久免费精品视频| 亚洲高清毛片一区二区| 亚洲永久无码3D动漫一区| 搡女人免费视频大全| 伊人免费在线观看| 精品亚洲视频在线|