Electron 应用商店:开箱即用工具集成方案

📋 项目概述

在 Electron 应用中实现应用商店功能,支持一键下载、安装和运行各种工具(Web应用、桌面应用),实现真正的"开箱即用"体验。

🎯 系统架构图

ini 复制代码
graph TB
    A[Electron 主应用] --> B[应用商店模块]
    B --> C[工具管理器]
    C --> D[下载引擎]
    C --> E[安装引擎]
    C --> F[运行引擎]
    
![image.png](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/623e226a0bac4a7794deca187c012569~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQmFjb24=:q75.awebp?rk3s=f64ab15b&x-expires=1763026897&x-signature=LKZVFK7%2BTDP61T5zdm7PjAqEi2o%3D)
    D --> D1[HTTP 下载]
    D --> D2[BT 下载]
    D --> D3[分块下载]
    
![image.png](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/04da0aa702ed4d70a11acfdb4c9d8cfd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQmFjb24=:q75.awebp?rk3s=f64ab15b&x-expires=1763026897&x-signature=o6hmn%2FCQkjpmbUAw8Tj2yxkvMSI%3D)
    E --> E1[Web应用安装]
    E --> E2[桌面应用安装]
    E --> E3[Docker应用安装]
    
    F --> F1[WebView 运行]
    F --> F2[子进程运行]
    F --> F3[Docker 运行]
    
    G[工具仓库] --> D
    H[本地工具库] --> E

📁 目录结构

bash 复制代码
electron-app/
├── src/
│   ├── main/
│   │   ├── appStore/           # 应用商店核心
│   │   │   ├── ToolManager.js      # 工具管理器
│   │   │   ├── DownloadEngine.js   # 下载引擎
│   │   │   ├── InstallEngine.js    # 安装引擎
│   │   │   └── RunEngine.js        # 运行引擎
│   │   ├── utils/
│   │   │   ├── fileUtils.js        # 文件操作工具
│   │   │   ├── networkUtils.js     # 网络工具
│   │   │   └── processUtils.js     # 进程工具
│   │   └── config/
│   │       ├── toolRegistry.js     # 工具注册表
│   │       └── paths.js           # 路径配置
│   ├── renderer/
│   │   └── components/
│   │       ├── AppStore.vue       # 应用商店界面
│   │       ├── ToolCard.vue       # 工具卡片
│   │       └── ProgressModal.vue  # 进度弹窗
│   └── shared/
│       └── constants.js           # 共享常量
├── tools/                        # 本地工具存储
│   ├── web/                     # Web应用目录
│   ├── desktop/                 # 桌面应用目录
│   └── docker/                  # Docker应用目录
└── config/
    └── tool-manifest.json       # 工具清单配置

🛠️ 核心模块设计

1. 工具管理器 (ToolManager)

javascript 复制代码
// src/main/appStore/ToolManager.js
class ToolManager {
  constructor() {
    this.downloadEngine = new DownloadEngine()
    this.installEngine = new InstallEngine()
    this.runEngine = new RunEngine()
    this.installedTools = new Map()
  }

  // 安装工具
  async installTool(toolId, options = {}) {
    const toolConfig = await this.getToolConfig(toolId)
    
    // 下载工具包
    const downloadPath = await this.downloadEngine.download(
      toolConfig.downloadUrl, 
      toolId,
      options
    )
    
    // 安装工具
    const installPath = await this.installEngine.install(
      downloadPath,
      toolConfig.type,
      toolConfig.installConfig
    )
    
    // 注册工具
    await this.registerTool(toolId, installPath, toolConfig)
    
    return installPath
  }

  // 运行工具
  async runTool(toolId, runOptions = {}) {
    const toolInfo = this.installedTools.get(toolId)
    if (!toolInfo) throw new Error(`工具未安装: ${toolId}`)
    
    return await this.runEngine.run(toolInfo, runOptions)
  }

  // 卸载工具
  async uninstallTool(toolId) {
    const toolInfo = this.installedTools.get(toolId)
    if (!toolInfo) return
    
    await this.runEngine.stop(toolInfo)
    await this.installEngine.uninstall(toolInfo.installPath)
    this.installedTools.delete(toolId)
  }
}

2. 下载引擎 (DownloadEngine)

javascript 复制代码
// src/main/appStore/DownloadEngine.js
class DownloadEngine {
  constructor() {
    this.downloads = new Map()
  }

  async download(url, toolId, options = {}) {
    const downloadDir = this.getDownloadDir(toolId)
    const fileName = this.getFileNameFromUrl(url)
    const filePath = path.join(downloadDir, fileName)
    
    // 支持断点续传
    return await this.downloadWithResume(url, filePath, {
      onProgress: options.onProgress,
      onComplete: options.onComplete
    })
  }

  // 分块下载实现
  async downloadWithResume(url, filePath, callbacks = {}) {
    return new Promise((resolve, reject) => {
      const fileStream = fs.createWriteStream(filePath)
      const request = https.get(url, (response) => {
        const totalSize = parseInt(response.headers['content-length'], 10)
        let downloadedSize = 0
        
        response.on('data', (chunk) => {
          downloadedSize += chunk.length
          const progress = (downloadedSize / totalSize) * 100
          callbacks.onProgress?.(progress)
        })
        
        response.pipe(fileStream)
        
        fileStream.on('finish', () => {
          fileStream.close()
          callbacks.onComplete?.(filePath)
          resolve(filePath)
        })
      })
      
      request.on('error', reject)
    })
  }
}

3. 安装引擎 (InstallEngine)

javascript 复制代码
// src/main/appStore/InstallEngine.js
class InstallEngine {
  // 根据工具类型进行安装
  async install(filePath, toolType, config = {}) {
    switch (toolType) {
      case 'web':
        return await this.installWebApp(filePath, config)
      case 'desktop':
        return await this.installDesktopApp(filePath, config)
      case 'docker':
        return await this.installDockerApp(filePath, config)
      default:
        throw new Error(`不支持的工具体型: ${toolType}`)
    }
  }

  // 安装 Web 应用
  async installWebApp(filePath, config) {
    const installDir = this.getWebAppInstallDir(config.id)
    
    // 解压文件
    if (filePath.endsWith('.zip')) {
      await this.extractZip(filePath, installDir)
    } else if (filePath.endsWith('.tar.gz')) {
      await this.extractTarGz(filePath, installDir)
    }
    
    // 检查依赖并自动安装
    await this.installDependencies(installDir, config.dependencies)
    
    return installDir
  }

  // 安装桌面应用
  async installDesktopApp(filePath, config) {
    const installDir = this.getDesktopAppInstallDir(config.id)
    
    if (process.platform === 'win32') {
      // Windows: 静默安装 MSI/EXE
      return await this.silentInstallWindows(filePath, installDir, config)
    } else if (process.platform === 'darwin') {
      // macOS: 安装 DMG/APP
      return await this.installMacApp(filePath, installDir, config)
    } else {
      // Linux: 安装 DEB/RPM/AppImage
      return await this.installLinuxApp(filePath, installDir, config)
    }
  }
}

4. 运行引擎 (RunEngine)

typescript 复制代码
// src/main/appStore/RunEngine.js
class RunEngine {
  async run(toolInfo, options = {}) {
    const { type, installPath, config } = toolInfo
    
    switch (type) {
      case 'web':
        return await this.runWebApp(installPath, config, options)
      case 'desktop':
        return await this.runDesktopApp(installPath, config, options)
      case 'docker':
        return await this.runDockerApp(installPath, config, options)
    }
  }

  // 运行 Web 应用
  async runWebApp(installPath, config, options) {
    // 启动本地服务器
    const serverProcess = await this.startLocalServer(installPath, config)
    
    // 等待服务就绪
    await this.waitForServerReady(config.port, 30000)
    
    // 在 Electron 窗口中打开
    const window = new BrowserWindow({
      width: options.width || 1200,
      height: options.height || 800,
      webPreferences: {
        webSecurity: false,
        allowRunningInsecureContent: true
      }
    })
    
    window.loadURL(`http://localhost:${config.port}`)
    
    return {
      type: 'web',
      window,
      process: serverProcess,
      url: `http://localhost:${config.port}`
    }
  }

  // 启动本地服务器
  async startLocalServer(installPath, config) {
    const packageJsonPath = path.join(installPath, 'package.json')
    
    if (fs.existsSync(packageJsonPath)) {
      // Node.js 项目
      return this.startNodeServer(installPath, config)
    }
    
    // 其他类型服务器(Python、Go等)
    return this.startGenericServer(installPath, config)
  }
}

📊 工具清单配置

json 复制代码
// config/tool-manifest.json
{
  "tools": {
    "presenton": {
      "id": "presenton",
      "name": "Presenton AI",
      "description": "AI 演示文稿生成器",
      "version": "1.0.0",
      "type": "web",
      "category": "productivity",
      "icon": "https://example.com/presenton-icon.png",
      
      "download": {
        "url": "https://github.com/presenton/presenton/releases/latest/download/presenton-web.zip",
        "checksum": "sha256:abc123...",
        "size": 15678900
      },
      
      "install": {
        "dependencies": ["nodejs"],
        "commands": {
          "windows": "npm install && npm run build",
          "unix": "npm install && npm run build"
        }
      },
      
      "run": {
        "command": "npm start",
        "port": 5000,
        "healthCheck": "/health",
        "timeout": 30000
      },
      
      "requirements": {
        "minMemory": "512MB",
        "minStorage": "200MB",
        "dependencies": ["docker"]
      }
    },
    
    "vscode": {
      "id": "vscode",
      "name": "Visual Studio Code",
      "type": "desktop",
      "download": {
        "windows": "https://code.visualstudio.com/sha/download?build=stable&os=win32-x64",
        "darwin": "https://code.visualstudio.com/sha/download?build=stable&os=darwin",
        "linux": "https://code.visualstudio.com/sha/download?build=stable&os=linux-x64"
      }
    }
  }
}

🔧 环境隔离方案

1. 依赖管理

javascript 复制代码
// 自动环境管理
class EnvironmentManager {
  async ensureRuntime(toolId, runtimeConfig) {
    const runtimeDir = this.getRuntimeDir(toolId)
    
    // 检查是否已安装
    if (!await this.checkRuntimeInstalled(runtimeDir, runtimeConfig)) {
      await this.installRuntime(runtimeDir, runtimeConfig)
    }
    
    return runtimeDir
  }

  // 安装 Node.js 运行时
  async installNodeRuntime(runtimeDir, version) {
    const nodeUrl = this.getNodeDownloadUrl(version, process.platform)
    const nodeArchive = await this.downloadEngine.download(nodeUrl)
    
    await this.extractArchive(nodeArchive, runtimeDir)
    await this.setupEnvironment(runtimeDir)
  }
}

2. 容器化运行(可选)

javascript 复制代码
// 使用 Docker 进行环境隔离
class DockerRunner {
  async runToolInContainer(toolInfo, options) {
    const imageName = `tool-${toolInfo.id}`
    
    // 构建 Docker 镜像
    if (!await this.imageExists(imageName)) {
      await this.buildDockerImage(toolInfo.installPath, imageName)
    }
    
    // 运行容器
    const containerId = await this.runContainer(imageName, {
      ports: { [toolInfo.config.port]: options.hostPort },
      volumes: this.getVolumeMounts(toolInfo),
      environment: options.environment
    })
    
    return { containerId, imageName }
  }
}

🎨 用户界面设计

1. 应用商店界面组件

ini 复制代码
<!-- src/renderer/components/AppStore.vue -->
<template>
  <div class="app-store">
    <div class="toolbar">
      <input v-model="searchQuery" placeholder="搜索工具..." />
      <div class="filters">
        <button 
          v-for="category in categories" 
          :key="category"
          :class="{ active: activeCategory === category }"
          @click="setCategory(category)"
        >
          {{ category }}
        </button>
      </div>
    </div>

    <div class="tool-grid">
      <ToolCard
        v-for="tool in filteredTools"
        :key="tool.id"
        :tool="tool"
        :installation-status="getInstallationStatus(tool.id)"
        @install="installTool(tool)"
        @run="runTool(tool)"
        @uninstall="uninstallTool(tool)"
      />
    </div>

    <ProgressModal
      v-if="currentOperation"
      :operation="currentOperation"
      :progress="operationProgress"
      @cancel="cancelCurrentOperation"
    />
  </div>
</template>

🚀 部署和更新策略

1. 自动更新机制

csharp 复制代码
// 工具自动更新
class AutoUpdater {
  async checkForUpdates() {
    const updates = []
    
    for (const [toolId, toolInfo] of this.toolManager.installedTools) {
      const latestVersion = await this.getLatestVersion(toolId)
      if (this.isNewerVersion(latestVersion, toolInfo.version)) {
        updates.push({
          toolId,
          currentVersion: toolInfo.version,
          latestVersion,
          changelog: await this.getChangelog(toolId)
        })
      }
相关推荐
行走的陀螺仪2 小时前
uni-app + Vue3 实现折叠文本(超出省略 + 展开收起)
前端·javascript·css·uni-app·vue3
冴羽2 小时前
JavaScript 异步循环踩坑指南
前端·javascript·node.js
jump6802 小时前
commonjs 和 ES Module
前端
旧曲重听12 小时前
前端需要掌握多少Node.js?
前端·node.js
Mr.Jessy2 小时前
Web APIs 学习第四天:DOM事件进阶
开发语言·前端·javascript·学习·ecmascript
云枫晖2 小时前
前端工程化实战:手把手教你构建项目脚手架
前端·前端工程化
醉方休2 小时前
开发一个完整的Electron应用程序
前端·javascript·electron
故作春风3 小时前
手把手实现一个前端 AI 编程助手:从 MCP 思想到 VS Code 插件实战
前端·人工智能
不会算法的小灰3 小时前
Vue.js 基础教程:从入门到实践
前端·javascript·vue.js