Реалізація автооновлення (Auto-Update) десктоп-застосунку

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація автооновлення (Auto-Update) десктоп-застосунку
Середня
~2-3 робочих дні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація автообновлення (Auto-Update) десктоп-приложення

Автообновлення — критична функція для десктоп-приложень. Без неї користувачі месяцями працюють зі старими версіями. З поганою реалізацією — втрачають дані або отримують сломані оновлення. Розглянемо для Electron та Tauri.

Electron: electron-updater

electron-updater з пакета electron-builder — стандартний інструмент. Підтримує GitHub Releases, S3, власні сервери.

npm install electron-updater
// main/updater.js
const { autoUpdater } = require('electron-updater');
const { app, BrowserWindow } = require('electron');
const log = require('electron-log');

autoUpdater.logger = log;
autoUpdater.autoDownload = false;
autoUpdater.autoInstallOnAppQuit = true;

function setupAutoUpdater(mainWindow) {
  autoUpdater.on('update-available', (info) => {
    mainWindow.webContents.send('update:available', {
      version: info.version,
      releaseNotes: info.releaseNotes,
      releaseDate: info.releaseDate
    });
  });

  autoUpdater.on('download-progress', (progress) => {
    mainWindow.webContents.send('update:progress', {
      percent: Math.round(progress.percent)
    });
  });

  autoUpdater.on('update-downloaded', (info) => {
    mainWindow.webContents.send('update:downloaded', {
      version: info.version
    });
  });

  const { ipcMain } = require('electron');
  ipcMain.handle('updater:check', () => autoUpdater.checkForUpdates());
  ipcMain.handle('updater:download', () => autoUpdater.downloadUpdate());
  ipcMain.handle('updater:install', () => autoUpdater.quitAndInstall(false, true));

  setInterval(() => autoUpdater.checkForUpdates(), 4 * 60 * 60 * 1000);
  setTimeout(() => autoUpdater.checkForUpdates(), 10000);
}

module.exports = { setupAutoUpdater };

Конфігурація для GitHub Releases

# electron-builder.yml
publish:
  provider: github
  owner: your-github-username
  repo: your-repo-name
  private: false

При сборці electron-builder створює latest.yml з метаданими версії. autoUpdater читає її для перевірки оновлень.

UI компонент для оновлень

// renderer/components/UpdateNotification.tsx
import { useEffect, useState } from 'react';

type UpdateState =
  | { status: 'idle' }
  | { status: 'checking' }
  | { status: 'available'; version: string }
  | { status: 'downloading'; percent: number }
  | { status: 'ready'; version: string }
  | { status: 'error'; message: string };

export function UpdateNotification() {
  const [state, setState] = useState<UpdateState>({ status: 'idle' });

  useEffect(() => {
    const unsubscribers = [
      window.electronAPI.onUpdateAvailable((info) =>
        setState({ status: 'available', version: info.version })
      ),
      window.electronAPI.onUpdateProgress((p) =>
        setState({ status: 'downloading', percent: p.percent })
      ),
      window.electronAPI.onUpdateDownloaded((info) =>
        setState({ status: 'ready', version: info.version })
      ),
    ];

    return () => unsubscribers.forEach(fn => fn?.());
  }, []);

  if (state.status === 'available') {
    return (
      <div className="update-banner">
        <span>Версія {state.version} доступна</span>
        <button onClick={() => window.electronAPI.downloadUpdate()}>Завантажити</button>
      </div>
    );
  }

  if (state.status === 'ready') {
    return (
      <div className="update-banner">
        <span>Версія {state.version} готова</span>
        <button onClick={() => window.electronAPI.installUpdate()}>Перезапустити та встановити</button>
      </div>
    );
  }

  return null;
}

Tauri: вбудоване оновлення

# src-tauri/Cargo.toml
[dependencies]
tauri-plugin-updater = "2"
// src-tauri/src/lib.rs
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_updater::Builder::default().build())
        .invoke_handler(tauri::generate_handler![check_for_updates])
        .run(tauri::generate_context!())
        .expect("error running app");
}

#[tauri::command]
async fn check_for_updates(app: tauri::AppHandle) -> Result<(), String> {
    let updater = app.updater().map_err(|e| e.to_string())?;
    let response = updater.check().await.map_err(|e| e.to_string())?;

    if let Some(update) = response {
        app.emit("update:available", &update.version).unwrap();
        update.download_and_install(
            |chunk, total| {
                if let Some(total) = total {
                    let percent = (chunk * 100 / total) as u8;
                    app.emit("update:progress", percent).unwrap();
                }
            },
            || { app.emit("update:installed", ()).unwrap(); }
        ).await.map_err(|e| e.to_string())?;
    }

    Ok(())
}

Tauri вимагає підписаних оновлень — не можна встановити неподписаний апдейт.

Оновлення без перезапуску

Повністю безшовне оновлення технічно неможливе для бінарника, який працює. Але мінімізуйте дискомфорт:

  • Завантажувати оновлення у фоні тихо
  • Пропонувати встановлення при наступному закритті
  • Показувати нотифікацію у треї
  • Зберігати стан перед перезапуском та відновлювати після