前言

理论上在 Electron 应用程序中,localStorage 是基于每个源(origin)存储的,这意味着它是与特定协议、主机名和端口绑定的。当 Electron 应用重启时,通常情况下 localStorage 中的数据应该会保持不变,不会自动清空。但是我偏偏遇到了这个问题。

  • 背景:由于特殊需求,访问我们的网站需要通过一个客户端来使用。所以,使用了electron的loadURL api 嵌入了链接。
  • 问题:登录后的token的用户数据会保存在localstorage中,在electron中,这份数据默认是持久化的,但是在个别window电脑中每次重启软件,都需要重新登录网页,导致了用户的投诉。
  • 原因:原因不详,升级Electron也没有解决。原因估计会有很多种,比如系统原因、权限原因等,但是无法去一一排查和兼容,所以想使用一劳永逸的方法,直接持久化数据。

解决方法: 持久化

Electron 内置的 electron-store 或者 electron-json-storage 插件,这些插件能够确保数据安全地存储在用户的应用数据目录下,即使应用重启或系统重启也能保持数据完整。

本文主要讲如何利用electron-store数据持久化保存用户的密码,自动登录。无论是用在vue项目或者react项目都是可以的。

它的使用场景可以有很多,保存登录信息只是其中一个使用场景。

具体步骤和代码

  1. 主线程暴露保存数据的方法
  2. 渲染端在登录的时候,把密码保传给Electron存起来,并标记时间
  3. 下载在登录界面时,从主线程获取密码,调用登录接口自动登录
  4. 如果用户主动退出登录,则清空数据

主进程


electron/main.js

const { app, BrowserWindow, ipcMain, Menu } = require('electron')
const path = require('path')
const Store = require('electron-store')
const Config = require('./config/env.js')

// 数据持久化
const store = new Store()

// 定义ipcRenderer监听事件
initIpcRenderer()

let mainWindow = null
function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1920,
    height: 1200,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  mainWindow.loadURL(Config.url)
}

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

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

function initIpcRenderer(params) {
  ipcMain.on('setStore', (_, key, value) => {
    store.set(key, value)
  })

  ipcMain.on('getStore', (_, key) => {
    let value = store.get(key)
    _.returnValue = value || ''
  })

  ipcMain.on('deleteStore', (_, key) => {
    let value = store.delete(key)
    _.returnValue = value || ''
  })
}

electron/preload.js

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

...

const electronHandler = {
  ipcRenderer: {
    setStoreValue: (key, value) => {
      ipcRenderer.send('setStore', key, value)
    },

    getStoreValue(key) {
      const resp = ipcRenderer.sendSync('getStore', key)
      return resp
    },

    deleteStore(key) {
      ipcRenderer.send('deleteStore', key)
    }
  }
}

contextBridge.exposeInMainWorld('electron', electronHandler)

...

渲染进程(网页端)


封装一个Electron.js 用于与集中处理web端和electron的通信

/**
 * Eletron.js
 * 封装了与H5 与 electron的通信
 */

export default class Electron {
    static isInElectron() {
        return navigator.userAgent.toLowerCase().indexOf(' electron/') > -1
    }

    static saveLoginData(data) {
        const loginData = {
            ...data,
            createTime: this.getNextMonthTime(),
        }
        this.setStore({ loginData })
    }

    static deleteLoginData() {
        this.deleteStore('loginData')
    }

    static setStore(key, value) {
        if (!this.isInElectron()) {
            return
        }
        window.electron?.ipcRenderer?.setStoreValue(key, value)
    }

    static getStore(key) {
        if (!this.isInElectron()) {
            return
        }
        return window.electron?.ipcRenderer?.getStoreValue(key)
    }

    static deleteStore(key) {
        if (!this.isInElectron()) {
            return
        }
        window.electron?.ipcRenderer?.deleteStore(key)
    }
    
    // 保存一个月 (示例,根据实际情况来做)
    static getNextMonthTime() {
        const date = new Date()

        const currentMonth = date.getMonth()
        const currentYear = date.getFullYear()

        let nextMonth = currentMonth + 1
        let nextYear = currentYear

        if (nextMonth > 11) {
            nextMonth = 0
            nextYear += 1
        }

        return new Date(nextYear, nextMonth).getTime()
    }
}

Login.js :使用electron.js 持久化登录数据

import Electron from '@/common/electron.js'

// 检测是否有数据,有则自动登录 (示例,注意不要泄露用户数据,需要进行加密)
if (Electron.isInElectron()) {
    const loginData = Electron.getStore('loginData')
    const { username, password, createTime } = loginData
    if (username && password && createTime > new Date().getTime()) {
        login({ username, password })
    }
}

// 登录时,保存登录密码
Electron.saveLoginData({
    username: config.username,
    password: config.password,
})

GitHub 加速计划 / vu / vue
83
16
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:4 个月前 )
9e887079 [skip ci] 3 个月前
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐