feat: mobile-like window size and always-visible stats
- Changed window size to mobile phone format (400x800) - Removed width condition for ActiveProxyFooter - now always visible - Added run-umbrix.sh launch script with icon copying - Stats cards now display on all screen sizes
This commit is contained in:
107
update-server/.htaccess
Normal file
107
update-server/.htaccess
Normal file
@@ -0,0 +1,107 @@
|
||||
# Umbrix Update Server - Apache Configuration
|
||||
|
||||
# === ЧПУ (Красивые URL) ===
|
||||
RewriteEngine On
|
||||
|
||||
# Редирект с index.php на api.php
|
||||
RewriteRule ^index\.php$ api.php [L,R=301]
|
||||
|
||||
# API endpoints
|
||||
RewriteRule ^api/latest$ api.php [L,QSA]
|
||||
RewriteRule ^api/version$ api.php [L,QSA]
|
||||
|
||||
# === Безопасность ===
|
||||
|
||||
# Запретить доступ к служебным файлам
|
||||
<FilesMatch "^(latest\.json|\.htaccess|\.git.*|composer\.json|package\.json|README\.md)$">
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Разрешить доступ только к API и downloads
|
||||
<FilesMatch "^(api\.php)$">
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</FilesMatch>
|
||||
|
||||
# Запретить листинг директорий
|
||||
Options -Indexes
|
||||
|
||||
# Запретить выполнение PHP в папке downloads
|
||||
<Directory "downloads">
|
||||
php_flag engine off
|
||||
RemoveHandler .php .phtml .php3
|
||||
RemoveType .php .phtml .php3
|
||||
</Directory>
|
||||
|
||||
# === CORS Headers ===
|
||||
<IfModule mod_headers.c>
|
||||
# Разрешить CORS для API
|
||||
Header set Access-Control-Allow-Origin "*"
|
||||
Header set Access-Control-Allow-Methods "GET, OPTIONS"
|
||||
Header set Access-Control-Allow-Headers "Content-Type"
|
||||
|
||||
# Кеширование для APK файлов
|
||||
<FilesMatch "\.(apk)$">
|
||||
Header set Cache-Control "public, max-age=604800"
|
||||
</FilesMatch>
|
||||
|
||||
# Запрет кеширования для API
|
||||
<FilesMatch "\.(php|json)$">
|
||||
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
||||
Header set Pragma "no-cache"
|
||||
Header set Expires "0"
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
|
||||
# === Сжатие ===
|
||||
<IfModule mod_deflate.c>
|
||||
# Сжимать JSON и текстовые файлы
|
||||
AddOutputFilterByType DEFLATE application/json
|
||||
AddOutputFilterByType DEFLATE text/plain
|
||||
AddOutputFilterByType DEFLATE text/html
|
||||
|
||||
# НЕ сжимать APK файлы (они уже сжаты)
|
||||
SetEnvIfNoCase Request_URI \.apk$ no-gzip dont-vary
|
||||
</IfModule>
|
||||
|
||||
# === MIME типы ===
|
||||
<IfModule mod_mime.c>
|
||||
AddType application/vnd.android.package-archive .apk
|
||||
AddType application/json .json
|
||||
</IfModule>
|
||||
|
||||
# === Ограничение размера загрузки ===
|
||||
<IfModule mod_php7.c>
|
||||
php_value upload_max_filesize 100M
|
||||
php_value post_max_size 100M
|
||||
php_value max_execution_time 300
|
||||
php_value max_input_time 300
|
||||
</IfModule>
|
||||
|
||||
# === Защита от инъекций ===
|
||||
<IfModule mod_rewrite.c>
|
||||
# Блокировать подозрительные запросы
|
||||
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
|
||||
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
|
||||
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
|
||||
RewriteRule ^(.*)$ - [F,L]
|
||||
</IfModule>
|
||||
|
||||
# === Логирование ===
|
||||
<IfModule mod_log_config.c>
|
||||
# Кастомный формат логов
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" custom
|
||||
CustomLog logs/access.log custom
|
||||
</IfModule>
|
||||
|
||||
# === Производительность ===
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
|
||||
# APK файлы кешировать на неделю
|
||||
ExpiresByType application/vnd.android.package-archive "access plus 7 days"
|
||||
|
||||
# API не кешировать
|
||||
ExpiresByType application/json "access plus 0 seconds"
|
||||
</IfModule>
|
||||
227
update-server/CHANGELOG_DESKTOP.md
Normal file
227
update-server/CHANGELOG_DESKTOP.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# История изменений системы обновлений
|
||||
|
||||
## Версия 1.1 - Упрощение и Desktop-фокус
|
||||
|
||||
**Дата:** 2024
|
||||
|
||||
### 🎯 Главное изменение
|
||||
|
||||
Система обновлений переориентирована **только на Desktop платформы** (Windows, macOS, Linux).
|
||||
Android версия использует Google Play Store для автоматических обновлений.
|
||||
|
||||
---
|
||||
|
||||
### ✨ Что изменилось
|
||||
|
||||
#### Код приложения
|
||||
|
||||
1. **new_version_dialog.dart** - Упрощён:
|
||||
- ✅ Android: Открывает браузер/Google Play
|
||||
- ✅ Desktop: Скачивание с прогресс-баром + автозапуск установщика
|
||||
- ❌ Удалены: Android permissions, MethodChannel, InstallHandler
|
||||
|
||||
2. **about_page.dart**:
|
||||
- Кнопка "Проверить обновления" видна **только на Desktop**
|
||||
- Android не показывает кнопку (обновления через Google Play)
|
||||
|
||||
3. **Android код удалён**:
|
||||
- ❌ `InstallHandler.kt` - удалён
|
||||
- ❌ `REQUEST_INSTALL_PACKAGES` permission - удалён из манифеста
|
||||
- ❌ Регистрация InstallHandler в MainActivity - удалена
|
||||
|
||||
#### Документация
|
||||
|
||||
1. **README.md** - Обновлён:
|
||||
- Добавлено предупреждение о Desktop-only
|
||||
- Изменена диаграмма процесса обновления
|
||||
- Добавлены ссылки на Google Play для Android
|
||||
|
||||
2. **README_DESKTOP.md** - Создан:
|
||||
- Подробная инструкция для Desktop платформ
|
||||
- Структура файлов (.exe, .dmg, .AppImage)
|
||||
- Примеры конфигурации
|
||||
|
||||
3. **api.php** - Обновлён комментарий:
|
||||
- Указано, что API только для Desktop
|
||||
- Упомянуто использование Google Play для Android
|
||||
|
||||
---
|
||||
|
||||
### 🧹 Что почистили
|
||||
|
||||
#### Удалённые файлы
|
||||
- `android/app/src/main/kotlin/com/umbrix/app/InstallHandler.kt`
|
||||
|
||||
#### Удалённые permissions
|
||||
- `android.permission.REQUEST_INSTALL_PACKAGES` из AndroidManifest.xml
|
||||
|
||||
#### Удалённый код
|
||||
- MethodChannel для проверки Android permissions
|
||||
- Функции `checkInstallPermission()`, `requestInstallPermission()`
|
||||
- Сложная логика установки APK из приложения
|
||||
|
||||
---
|
||||
|
||||
### 📦 Зависимости
|
||||
|
||||
Используемые пакеты **только для Desktop**:
|
||||
- `dio` ^5.4.1 - HTTP запросы и загрузка файлов
|
||||
- `path_provider` ^2.1.1 - Временная директория для загрузок
|
||||
- `open_file` ^3.3.2 - Открытие установщика после загрузки
|
||||
|
||||
Android теперь использует только:
|
||||
- `UriUtils.tryLaunch()` - Открытие браузера/Google Play
|
||||
|
||||
---
|
||||
|
||||
### 🔄 Логика работы
|
||||
|
||||
#### Desktop (Windows/macOS/Linux)
|
||||
```dart
|
||||
if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
|
||||
// 1. Проверка обновлений на сервере
|
||||
// 2. Показ диалога с информацией о версии
|
||||
// 3. Скачивание с прогресс-баром (dio)
|
||||
// 4. Сохранение в temp директорию
|
||||
// 5. Автоматический запуск установщика (open_file)
|
||||
}
|
||||
```
|
||||
|
||||
#### Android
|
||||
```dart
|
||||
if (Platform.isAndroid) {
|
||||
// 1. Проверка обновлений НЕ показывается (кнопка скрыта)
|
||||
// 2. В production: прямая ссылка на Google Play
|
||||
// 3. В debug: открытие браузера с download_url
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Дальнейшие планы
|
||||
|
||||
#### Production деплой
|
||||
|
||||
1. **Windows**:
|
||||
- Создание `.exe` установщика
|
||||
- Подпись сертификатом
|
||||
- Загрузка в `downloads/windows/`
|
||||
|
||||
2. **macOS**:
|
||||
- Создание `.dmg` образа
|
||||
- Нотаризация Apple
|
||||
- Загрузка в `downloads/macos/`
|
||||
|
||||
3. **Linux**:
|
||||
- Создание `.AppImage`
|
||||
- Добавление `.deb` / `.rpm` пакетов
|
||||
- Загрузка в `downloads/linux/`
|
||||
|
||||
4. **Android**:
|
||||
- Публикация в Google Play Store
|
||||
- Удаление кастомного сервера обновлений
|
||||
- Автоматические обновления через магазин
|
||||
|
||||
---
|
||||
|
||||
### 💡 Почему так?
|
||||
|
||||
**Проблема:** Android требует сложные разрешения для установки APK из приложения:
|
||||
- Нужен `REQUEST_INSTALL_PACKAGES` permission
|
||||
- Пользователь должен вручную дать разрешение в настройках
|
||||
- Это запутывает пользователей и выглядит нелогично
|
||||
|
||||
**Решение:**
|
||||
- Android → Google Play Store (стандартный путь)
|
||||
- Desktop → Собственный сервер обновлений (гибкость и контроль)
|
||||
|
||||
---
|
||||
|
||||
### 📝 Заметки разработчика
|
||||
|
||||
> "как то нелогично . но мы же его установили уже ... на андроид может и не надо такое обновление на exe надо будет"
|
||||
|
||||
Было принято решение упростить систему:
|
||||
- На Android слишком сложно и нелогично обновлять APK изнутри приложения
|
||||
- Google Play Store делает это автоматически и безопасно
|
||||
- Desktop платформам нужна эта функция, так как нет централизованного магазина
|
||||
- Разделение платформ упрощает код и улучшает UX
|
||||
|
||||
---
|
||||
|
||||
## Версия 1.0 - Первый релиз
|
||||
|
||||
**Дата:** 2024
|
||||
|
||||
- ✅ PHP API для проверки обновлений
|
||||
- ✅ Web-панель администратора
|
||||
- ✅ История версий
|
||||
- ✅ Поддержка beta/stable релизов
|
||||
- ✅ CORS настройки
|
||||
- ✅ Rate limiting
|
||||
- ✅ Логирование запросов
|
||||
- ✅ Интеграция с Flutter приложением
|
||||
|
||||
**Проблемы версии 1.0:**
|
||||
- Пыталась поддерживать Android с установкой APK
|
||||
- Требовала сложные Android permissions
|
||||
- Запутанная UX для пользователей Android
|
||||
|
||||
---
|
||||
|
||||
## Миграция с 1.0 на 1.1
|
||||
|
||||
### Для разработчиков
|
||||
|
||||
1. Обновите код приложения (Flutter):
|
||||
```bash
|
||||
git pull
|
||||
flutter pub get
|
||||
flutter build apk --debug # для тестирования
|
||||
```
|
||||
|
||||
2. Удалите старый APK с устройства:
|
||||
```bash
|
||||
adb uninstall com.umbrix.app
|
||||
```
|
||||
|
||||
3. Установите новую версию:
|
||||
```bash
|
||||
adb install build/app/outputs/flutter-apk/app-debug.apk
|
||||
```
|
||||
|
||||
### Для сервера
|
||||
|
||||
Ничего менять не нужно! API осталось совместимым.
|
||||
Просто обновите документацию:
|
||||
- `README.md` ← основной файл
|
||||
- `README_DESKTOP.md` ← подробности для Desktop
|
||||
|
||||
### Для пользователей
|
||||
|
||||
**Android:**
|
||||
- Обновления теперь через Google Play Store
|
||||
- Кнопка "Проверить обновления" больше не показывается
|
||||
|
||||
**Desktop:**
|
||||
- Всё работает как раньше, но с улучшенным UX
|
||||
- Прогресс-бар при скачивании
|
||||
- Автоматический запуск установщика
|
||||
|
||||
---
|
||||
|
||||
## Контрольный список релиза
|
||||
|
||||
- [x] Упростить код для Android
|
||||
- [x] Реализовать скачивание для Desktop с прогресс-баром
|
||||
- [x] Удалить InstallHandler.kt
|
||||
- [x] Удалить REQUEST_INSTALL_PACKAGES permission
|
||||
- [x] Обновить README.md
|
||||
- [x] Создать README_DESKTOP.md
|
||||
- [x] Обновить комментарии в api.php
|
||||
- [x] Протестировать на Android emulator
|
||||
- [ ] Создать Windows .exe установщик
|
||||
- [ ] Создать macOS .dmg образ
|
||||
- [ ] Создать Linux .AppImage
|
||||
- [ ] Опубликовать в Google Play Store
|
||||
- [ ] Production деплой сервера
|
||||
174
update-server/CHEATSHEET.txt
Normal file
174
update-server/CHEATSHEET.txt
Normal file
@@ -0,0 +1,174 @@
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🚀 ШПАРГАЛКА - Система Обновлений Umbrix
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 📖 ШАГ 1: ПРОЧИТАЙТЕ ИНСТРУКЦИИ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
📄 UPDATE_SERVER_GUIDE.md ← НАЧНИТЕ ЗДЕСЬ
|
||||
📂 update-server/
|
||||
├── QUICK_START.md ← Быстрый старт (5 минут)
|
||||
├── README.md ← Полная инструкция
|
||||
└── TESTING.md ← Тестирование
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 🧪 ШАГ 2: ПРОТЕСТИРУЙТЕ ЛОКАЛЬНО │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
$ cd update-server
|
||||
$ ./start_test_server.sh
|
||||
|
||||
➜ Сервер запустится на http://localhost:8000
|
||||
➜ Для эмулятора: http://10.0.2.2:8000/api.php
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ⚙️ ШАГ 3: НАСТРОЙТЕ КОД │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Файл: lib/core/model/constants.dart
|
||||
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ // Для ТЕСТИРОВАНИЯ: │
|
||||
│ static const customUpdateServerUrl = │
|
||||
│ "http://10.0.2.2:8000/api.php"; │
|
||||
│ │
|
||||
│ // Для ПРОДАКШЕНА: │
|
||||
│ static const customUpdateServerUrl = │
|
||||
│ "https://api.umbrix.net/api/latest"; │
|
||||
│ │
|
||||
│ // ВКЛЮЧИТЬ собственный сервер: │
|
||||
│ static const useCustomUpdateServer = true; │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
|
||||
⚠️ ВАЖНО: Пересоберите после изменений!
|
||||
$ flutter build apk --release
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 🎯 ШАГ 4: ПРОВЕРЬТЕ В ПРИЛОЖЕНИИ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
1. Запустите приложение в эмуляторе
|
||||
2. Откройте: Настройки → О программе
|
||||
3. Нажмите: "Проверить обновления"
|
||||
4. Должно появиться окно с новой версией
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 🌐 ШАГ 5: ЗАГРУЗИТЕ НА СЕРВЕР (ПРОДАКШЕН) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Загрузите через FTP/панель хостинга:
|
||||
|
||||
📁 /var/www/updates/
|
||||
├── api.php ← главный скрипт
|
||||
├── latest.json ← информация о версии
|
||||
├── .htaccess ← настройки Apache
|
||||
└── downloads/ ← создайте пустую папку
|
||||
└── (APK файлы будут здесь)
|
||||
|
||||
Настройте домен: api.umbrix.net → /var/www/updates
|
||||
Включите SSL (Let's Encrypt бесплатно)
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 📦 КАК ВЫКАТИТЬ НОВОЕ ОБНОВЛЕНИЕ? │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
🎨 СПОСОБ 1: Через веб-панель (рекомендуется)
|
||||
|
||||
1. Откройте: https://api.umbrix.net/admin/
|
||||
2. Заполните форму (версия, URL, описание)
|
||||
3. Нажмите "Сохранить обновление"
|
||||
4. Готово! 🎉
|
||||
|
||||
📝 СПОСОБ 2: Вручную (старый способ)
|
||||
|
||||
1. Соберите APK:
|
||||
$ flutter build apk --release
|
||||
|
||||
2. Переименуйте:
|
||||
app-release.apk → umbrix-2.5.8.apk
|
||||
|
||||
3. Загрузите в папку downloads/ на сервере
|
||||
|
||||
4. Обновите latest.json:
|
||||
{
|
||||
"version": "2.5.8",
|
||||
"build_number": "258",
|
||||
"download_url": "https://api.umbrix.net/downloads/umbrix-2.5.8.apk",
|
||||
"release_notes": "🎉 Что нового...",
|
||||
"published_at": "2026-01-17T12:00:00Z"
|
||||
}
|
||||
|
||||
5. Готово! Пользователи получат уведомление
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ✅ ПРОВЕРОЧНЫЙ СПИСОК │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Перед запуском убедитесь:
|
||||
|
||||
□ PHP 7.4+ установлен на сервере
|
||||
□ Файлы загружены: api.php, latest.json, .htaccess
|
||||
□ Папка downloads/ создана (права 755)
|
||||
□ Домен настроен с HTTPS
|
||||
□ URL в constants.dart правильный
|
||||
□ useCustomUpdateServer = true
|
||||
□ Приложение пересобрано
|
||||
□ API отвечает в браузере: https://api.umbrix.net/api/latest
|
||||
□ APK скачивается: https://api.umbrix.net/downloads/umbrix-X.X.X.apk
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 🔧 ПОЛЕЗНЫЕ КОМАНДЫ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
# Проверить API в браузере:
|
||||
https://api.umbrix.net/api/latest
|
||||
|
||||
# Проверить через curl:
|
||||
$ curl https://api.umbrix.net/api/latest
|
||||
|
||||
# Собрать APK:
|
||||
$ flutter build apk --release
|
||||
|
||||
# Запустить в эмуляторе:
|
||||
$ flutter run
|
||||
|
||||
# Установить APK в эмулятор:
|
||||
$ flutter install
|
||||
|
||||
# Посмотреть логи:
|
||||
$ adb logcat | grep -i umbrix
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ❓ ЧАСТЫЕ ПРОБЛЕМЫ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
❌ "Обновления не приходят"
|
||||
✅ Проверьте: useCustomUpdateServer = true
|
||||
✅ Проверьте: URL правильный (с https://)
|
||||
✅ Пересоберите приложение
|
||||
✅ Версия в latest.json должна быть БОЛЬШЕ текущей
|
||||
|
||||
❌ "API не отвечает"
|
||||
✅ Откройте URL в браузере - должен показать JSON
|
||||
✅ Проверьте PHP логи на сервере
|
||||
✅ Проверьте, что файлы загружены
|
||||
|
||||
❌ "Не скачивается APK"
|
||||
✅ Проверьте, что файл существует в downloads/
|
||||
✅ Проверьте права: chmod 644 file.apk
|
||||
✅ Проверьте URL в latest.json
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 📞 ДОКУМЕНТАЦИЯ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
📄 UPDATE_SERVER_GUIDE.md - главная инструкция
|
||||
📂 update-server/INDEX.md - навигация
|
||||
📂 update-server/README.md - полное руководство
|
||||
📂 update-server/QUICK_START.md - быстрый старт
|
||||
📂 update-server/TESTING.md - тестирование
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🎉 Готово! Удачи с обновлениями! 🚀
|
||||
═══════════════════════════════════════════════════════════════
|
||||
299
update-server/DOCKER_STORAGE.md
Normal file
299
update-server/DOCKER_STORAGE.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# 🐳 Хранение APK файлов в Docker контейнере
|
||||
|
||||
## 📋 Проблема
|
||||
|
||||
При размещении update-server в Docker контейнере, нужно решить где хранить APK файлы (обычно 50-100 MB каждый).
|
||||
|
||||
## ✅ Решение: Docker Volume
|
||||
|
||||
### Вариант 1: Named Volume (Рекомендуется)
|
||||
|
||||
**docker-compose.yml:**
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
update-server:
|
||||
image: php:8.3-cli
|
||||
container_name: umbrix-update-server
|
||||
working_dir: /var/www
|
||||
command: php -S 0.0.0.0:8000
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
# Код сервера (read-only)
|
||||
- ./update-server:/var/www:ro
|
||||
# Файлы обновлений (read-write)
|
||||
- umbrix-downloads:/var/www/downloads
|
||||
# Логи (read-write)
|
||||
- umbrix-logs:/var/www/logs
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
umbrix-downloads:
|
||||
driver: local
|
||||
umbrix-logs:
|
||||
driver: local
|
||||
```
|
||||
|
||||
**Преимущества:**
|
||||
- ✅ Файлы сохраняются при пересоздании контейнера
|
||||
- ✅ Легко делать backup: `docker cp`
|
||||
- ✅ Данные изолированы от кода
|
||||
|
||||
**Как загружать APK:**
|
||||
```bash
|
||||
# 1. Соберите APK
|
||||
flutter build apk --release
|
||||
|
||||
# 2. Скопируйте в volume
|
||||
docker cp build/app/outputs/flutter-apk/app-release.apk \
|
||||
umbrix-update-server:/var/www/downloads/android/umbrix-1.7.1.apk
|
||||
|
||||
# 3. Обновите latest.json через веб-панель
|
||||
# http://your-server:8000/admin/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Вариант 2: Bind Mount (Для разработки)
|
||||
|
||||
**docker-compose.yml:**
|
||||
```yaml
|
||||
services:
|
||||
update-server:
|
||||
volumes:
|
||||
- ./update-server:/var/www
|
||||
# Downloads доступны локально
|
||||
- ./downloads:/var/www/downloads
|
||||
```
|
||||
|
||||
**Преимущества:**
|
||||
- ✅ Прямой доступ с хоста
|
||||
- ✅ Удобно для разработки
|
||||
- ✅ Можно редактировать напрямую
|
||||
|
||||
**Недостатки:**
|
||||
- ⚠️ Нужно следить за правами доступа
|
||||
- ⚠️ Файлы привязаны к хосту
|
||||
|
||||
**Загрузка:**
|
||||
```bash
|
||||
# Просто скопируйте файл
|
||||
cp build/app/outputs/flutter-apk/app-release.apk \
|
||||
downloads/android/umbrix-1.7.1.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Вариант 3: Внешнее хранилище (Продакшен)
|
||||
|
||||
Для продакшена лучше использовать CDN или объектное хранилище:
|
||||
|
||||
**Примеры:**
|
||||
- 🌐 **CloudFlare R2** (S3-совместимый, бесплатный)
|
||||
- 🌐 **AWS S3** + CloudFront
|
||||
- 🌐 **DigitalOcean Spaces**
|
||||
- 🌐 **Azure Blob Storage**
|
||||
- 🌐 **Backblaze B2**
|
||||
|
||||
**docker-compose.yml с S3:**
|
||||
```yaml
|
||||
services:
|
||||
update-server:
|
||||
environment:
|
||||
- STORAGE_TYPE=s3
|
||||
- S3_BUCKET=umbrix-updates
|
||||
- S3_REGION=eu-central-1
|
||||
- AWS_ACCESS_KEY_ID=${AWS_KEY}
|
||||
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET}
|
||||
```
|
||||
|
||||
**latest.json:**
|
||||
```json
|
||||
{
|
||||
"download_url": "https://cdn.umbrix.net/downloads/android/umbrix-1.7.1.apk"
|
||||
}
|
||||
```
|
||||
|
||||
**Преимущества:**
|
||||
- ✅ Быстрая доставка (CDN)
|
||||
- ✅ Неограниченное место
|
||||
- ✅ Автоматический backup
|
||||
- ✅ Не нагружает ваш сервер
|
||||
|
||||
---
|
||||
|
||||
## 📊 Сравнение вариантов
|
||||
|
||||
| Вариант | Разработка | Продакшен | Сложность | Стоимость |
|
||||
|---------|-----------|-----------|-----------|-----------|
|
||||
| Named Volume | ⭐⭐⭐ | ⭐⭐⭐ | Низкая | Бесплатно |
|
||||
| Bind Mount | ⭐⭐⭐⭐⭐ | ⭐⭐ | Низкая | Бесплатно |
|
||||
| S3/CDN | ⭐⭐ | ⭐⭐⭐⭐⭐ | Средняя | $5-20/мес |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Быстрый старт (Named Volume)
|
||||
|
||||
**1. Создайте docker-compose.yml:**
|
||||
```bash
|
||||
cd /home/vodorod/dorod/hiddify-umbrix-v1.7.0
|
||||
cat > docker-compose.yml << 'EOF'
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
update-server:
|
||||
image: php:8.3-cli
|
||||
container_name: umbrix-update-server
|
||||
working_dir: /var/www
|
||||
command: php -S 0.0.0.0:8000
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./update-server:/var/www:ro
|
||||
- umbrix-downloads:/var/www/downloads
|
||||
- umbrix-logs:/var/www/logs
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
umbrix-downloads:
|
||||
umbrix-logs:
|
||||
EOF
|
||||
```
|
||||
|
||||
**2. Запустите:**
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
**3. Загрузите APK:**
|
||||
```bash
|
||||
# Соберите
|
||||
flutter build apk --release
|
||||
|
||||
# Загрузите в контейнер
|
||||
docker cp build/app/outputs/flutter-apk/app-release.apk \
|
||||
umbrix-update-server:/var/www/downloads/android/umbrix-1.7.1.apk
|
||||
|
||||
# Проверьте
|
||||
docker exec umbrix-update-server ls -lh /var/www/downloads/android/
|
||||
```
|
||||
|
||||
**4. Обновите latest.json через веб-панель:**
|
||||
```
|
||||
http://localhost:8000/admin/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Защита от конфликта с оригинальным Hiddify
|
||||
|
||||
### ✅ Убедитесь что настроено:
|
||||
|
||||
**lib/core/model/constants.dart:**
|
||||
```dart
|
||||
// Ваш сервер обновлений
|
||||
static const useCustomUpdateServer = true; // ← ДОЛЖНО БЫТЬ true
|
||||
|
||||
// URL вашего сервера
|
||||
static const customUpdateServerUrl = "https://api.umbrix.net/api.php";
|
||||
```
|
||||
|
||||
**Что проверить:**
|
||||
```bash
|
||||
# 1. Проверьте константы
|
||||
grep "useCustomUpdateServer" lib/core/model/constants.dart
|
||||
|
||||
# 2. Должно вывести:
|
||||
# static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
### ⚠️ Если false - приложение будет проверять GitHub!
|
||||
|
||||
**При `useCustomUpdateServer = false`:**
|
||||
- ❌ Обращается к https://api.github.com/repos/hiddify/hiddify-app/releases
|
||||
- ❌ Увидит оригинальные обновления Hiddify
|
||||
- ❌ Предложит скачать оригинальную версию
|
||||
|
||||
**При `useCustomUpdateServer = true`:**
|
||||
- ✅ Обращается к вашему серверу
|
||||
- ✅ Видит только ваши обновления
|
||||
- ✅ Полный контроль
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Рекомендации
|
||||
|
||||
### Для локальной разработки:
|
||||
```bash
|
||||
# Используйте PHP встроенный сервер
|
||||
cd update-server && php -S localhost:8000
|
||||
```
|
||||
|
||||
### Для тестирования в Docker:
|
||||
```bash
|
||||
# Named Volume
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Для продакшена:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
update-server:
|
||||
image: php:8.3-fpm
|
||||
volumes:
|
||||
- ./update-server:/var/www
|
||||
- umbrix-downloads:/var/www/downloads
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
- umbrix-downloads:/var/www/downloads:ro
|
||||
- ./ssl:/etc/nginx/ssl
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Backup файлов обновлений
|
||||
|
||||
### Из Named Volume:
|
||||
```bash
|
||||
# Backup
|
||||
docker run --rm \
|
||||
-v umbrix-downloads:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar czf /backup/downloads-backup.tar.gz /data
|
||||
|
||||
# Restore
|
||||
docker run --rm \
|
||||
-v umbrix-downloads:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar xzf /backup/downloads-backup.tar.gz -C /
|
||||
```
|
||||
|
||||
### Из Bind Mount:
|
||||
```bash
|
||||
# Просто архивируйте
|
||||
tar czf downloads-backup.tar.gz downloads/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Итого
|
||||
|
||||
**Для вас (Umbrix):**
|
||||
1. ✅ Используйте **Named Volume** в Docker
|
||||
2. ✅ `useCustomUpdateServer = true` уже установлено
|
||||
3. ✅ Загружайте APK через `docker cp`
|
||||
4. ✅ Управляйте через веб-панель http://localhost:8000/admin/
|
||||
5. ✅ **НЕ будет** конфликта с оригинальным Hiddify!
|
||||
|
||||
**Версии теперь логичные:**
|
||||
- Текущая: **1.7.0 dev**
|
||||
- Доступна: **1.7.1**
|
||||
- Следующая: **1.7.2**, **1.8.0**, и т.д.
|
||||
161
update-server/INDEX.md
Normal file
161
update-server/INDEX.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# 🎯 Система Обновлений - Главная Документация
|
||||
|
||||
## 📁 Структура папки update-server/
|
||||
|
||||
```
|
||||
update-server/
|
||||
├── 📖 README.md ← Полная инструкция (начните отсюда)
|
||||
├── ⚡ QUICK_START.md ← Быстрый старт за 5 минут
|
||||
├── 🧪 TESTING.md ← Тестирование в эмуляторе
|
||||
├── 🚀 start_test_server.sh ← Скрипт для запуска тестового сервера
|
||||
│
|
||||
├── 🔧 api.php ← PHP скрипт API (загрузите на сервер)
|
||||
├── 📄 latest.json ← Информация о версии (обновляйте при релизе)
|
||||
├── ⚙️ .htaccess ← Настройки Apache (загрузите на сервер)
|
||||
│
|
||||
└── downloads/ ← Папка для APK файлов (создайте на сервере)
|
||||
└── umbrix-X.X.X.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Что читать?
|
||||
|
||||
### Для новичков:
|
||||
👉 **[QUICK_START.md](QUICK_START.md)** - простая инструкция на 5 минут
|
||||
|
||||
### Подробная настройка:
|
||||
👉 **[README.md](README.md)** - полное руководство со всеми деталями
|
||||
|
||||
### Для разработчиков:
|
||||
👉 **[TESTING.md](TESTING.md)** - как тестировать в эмуляторе
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Быстрый Старт
|
||||
|
||||
### 1️⃣ Тестирование (локально)
|
||||
|
||||
```bash
|
||||
# Запустите тестовый сервер
|
||||
cd update-server
|
||||
./start_test_server.sh
|
||||
|
||||
# Откроется на http://localhost:8000
|
||||
```
|
||||
|
||||
### 2️⃣ Настройка приложения
|
||||
|
||||
Измените `lib/core/model/constants.dart`:
|
||||
|
||||
```dart
|
||||
// Для тестирования в эмуляторе:
|
||||
static const customUpdateServerUrl = "http://10.0.2.2:8000/api.php";
|
||||
static const useCustomUpdateServer = true;
|
||||
|
||||
// Для продакшена (когда загрузите на свой сервер):
|
||||
static const customUpdateServerUrl = "https://api.umbrix.net/api/latest";
|
||||
static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
### 3️⃣ Проверка
|
||||
|
||||
1. Запустите приложение в эмуляторе
|
||||
2. Настройки → О программе → Проверить обновления
|
||||
3. Должно появиться окно (если версия в latest.json выше)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Для продакшена
|
||||
|
||||
1. **Загрузите файлы на хостинг:**
|
||||
- `api.php`
|
||||
- `latest.json`
|
||||
- `.htaccess`
|
||||
|
||||
2. **Создайте папку `downloads/`**
|
||||
|
||||
3. **Настройте домен и SSL**
|
||||
|
||||
4. **Измените URL в приложении** → пересоберите
|
||||
|
||||
5. **При новом релизе:**
|
||||
- Загрузите APK в `downloads/`
|
||||
- Обновите `latest.json`
|
||||
- Готово! Пользователи получат уведомление
|
||||
|
||||
---
|
||||
|
||||
## 📋 Чек-лист
|
||||
|
||||
Перед запуском убедитесь:
|
||||
|
||||
- [ ] PHP 7.4+ установлен
|
||||
- [ ] Все файлы загружены на сервер
|
||||
- [ ] Папка `downloads/` создана
|
||||
- [ ] Домен настроен с HTTPS
|
||||
- [ ] URL в `constants.dart` правильный
|
||||
- [ ] Приложение пересобрано
|
||||
- [ ] API отвечает в браузере
|
||||
- [ ] APK скачивается
|
||||
|
||||
---
|
||||
|
||||
## ❓ Проблемы?
|
||||
|
||||
### Не работает проверка обновлений?
|
||||
|
||||
1. Проверьте `useCustomUpdateServer = true`
|
||||
2. Проверьте URL (должен быть с `https://`)
|
||||
3. Пересоберите приложение после изменений
|
||||
4. Проверьте версию в `latest.json` (должна быть больше текущей)
|
||||
|
||||
### API не отвечает?
|
||||
|
||||
1. Откройте URL в браузере - должен показаться JSON
|
||||
2. Проверьте PHP логи на сервере
|
||||
3. Проверьте права на файлы
|
||||
|
||||
### Не скачивается APK?
|
||||
|
||||
1. Проверьте, что файл существует в папке `downloads/`
|
||||
2. Проверьте права: `chmod 644 file.apk`
|
||||
3. Проверьте URL в `latest.json`
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Полезные ссылки
|
||||
|
||||
- **Полная инструкция:** [README.md](README.md)
|
||||
- **Быстрый старт:** [QUICK_START.md](QUICK_START.md)
|
||||
- **Тестирование:** [TESTING.md](TESTING.md)
|
||||
|
||||
---
|
||||
|
||||
## 💡 Примеры использования
|
||||
|
||||
### GitHub (публичный репозиторий)
|
||||
```dart
|
||||
static const useCustomUpdateServer = false;
|
||||
```
|
||||
|
||||
### Собственный сервер (приватный репозиторий)
|
||||
```dart
|
||||
static const customUpdateServerUrl = "https://api.yoursite.com/api/latest";
|
||||
static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Готово!
|
||||
|
||||
Система обновлений настроена. Теперь вы можете:
|
||||
|
||||
✅ Выкатывать обновления без магазинов
|
||||
✅ Контролировать процесс релизов
|
||||
✅ Тестировать бета-версии
|
||||
✅ Видеть аналитику использования
|
||||
|
||||
---
|
||||
|
||||
**Удачи в разработке! 🚀**
|
||||
113
update-server/QUICK_START.md
Normal file
113
update-server/QUICK_START.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# ⚡ Быстрый Старт - 5 минут
|
||||
|
||||
Минимальная инструкция для тех, кто хочет запустить быстро.
|
||||
|
||||
## 🎯 Что делать (по шагам)
|
||||
|
||||
### 1️⃣ Загрузите файлы на хостинг
|
||||
|
||||
Через FTP/панель хостинга загрузите эти 4 файла:
|
||||
|
||||
```
|
||||
📁 Ваша папка на сервере (например: /var/www/updates/)
|
||||
├── api.php ← главный файл
|
||||
├── latest.json ← информация о версии
|
||||
├── .htaccess ← настройки
|
||||
└── downloads/ ← создайте пустую папку
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ Настройте домен
|
||||
|
||||
В панели хостинга:
|
||||
1. Создайте поддомен: `api.umbrix.net` (или любое имя)
|
||||
2. Укажите папку: `/var/www/updates`
|
||||
3. Включите SSL (Let's Encrypt бесплатно)
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ Измените `latest.json`
|
||||
|
||||
Откройте файл `latest.json` и замените:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.5.7",
|
||||
"download_url": "https://api.umbrix.net/downloads/umbrix-2.5.7.apk",
|
||||
↑↑↑ замените на свой домен
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ Измените код приложения
|
||||
|
||||
Откройте файл `lib/core/model/constants.dart`:
|
||||
|
||||
```dart
|
||||
// Было:
|
||||
static const customUpdateServerUrl = "https://your-server.com/api/updates/latest";
|
||||
|
||||
// Стало (ваш домен):
|
||||
static const customUpdateServerUrl = "https://api.umbrix.net/api/latest";
|
||||
|
||||
// Включаем собственный сервер:
|
||||
static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5️⃣ Пересоберите приложение
|
||||
|
||||
```bash
|
||||
flutter build apk --release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6️⃣ Загрузите APK на сервер
|
||||
|
||||
1. Найдите APK: `build/app/outputs/flutter-apk/app-release.apk`
|
||||
2. Переименуйте в: `umbrix-2.5.7.apk`
|
||||
3. Загрузите в папку `downloads/` на сервере
|
||||
|
||||
---
|
||||
|
||||
### 7️⃣ Проверьте
|
||||
|
||||
Откройте в браузере:
|
||||
```
|
||||
https://api.umbrix.net/api/latest
|
||||
```
|
||||
|
||||
Должны увидеть JSON с версией.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Готово!
|
||||
|
||||
Теперь когда выйдет новая версия:
|
||||
1. Соберите новый APK
|
||||
2. Загрузите в `downloads/`
|
||||
3. Обновите `latest.json` (версию и URL)
|
||||
4. Всё! Пользователи получат уведомление
|
||||
|
||||
---
|
||||
|
||||
## ❓ Не работает?
|
||||
|
||||
### Проверьте:
|
||||
- ✅ HTTPS включен
|
||||
- ✅ Файлы загружены в правильную папку
|
||||
- ✅ URL в `constants.dart` правильный (с `https://`)
|
||||
- ✅ Приложение пересобрано после изменений
|
||||
|
||||
### Частые ошибки:
|
||||
- Забыли пересобрать приложение
|
||||
- Опечатка в URL
|
||||
- Нет SSL сертификата
|
||||
- Версия в `latest.json` меньше или равна текущей
|
||||
|
||||
---
|
||||
|
||||
**📖 Подробная инструкция:** см. файл `README.md`
|
||||
319
update-server/README.md
Normal file
319
update-server/README.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# 🚀 Сервер Обновлений Umbrix
|
||||
|
||||
> **⚠️ Внимание:** Этот сервер предназначен **только для Desktop платформ** (Windows, macOS, Linux).
|
||||
> Для Android используется Google Play Store.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Что это?
|
||||
|
||||
Система автоматических обновлений для настольных версий Umbrix. Пользователи получают уведомления об обновлениях прямо в приложении с автоматической загрузкой и установкой.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Как это работает?
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────────┐ ┌─────────────┐
|
||||
│ Desktop App │ -------> │ Ваш сервер │ <------- │ Вы загружаете│
|
||||
│ Windows/Mac/ │ запрос │ (PHP API) │ файлы │ новую версию │
|
||||
│ Linux │ │ │ │ .exe/.dmg │
|
||||
└──────────────┘ └──────────────────┘ └─────────────┘
|
||||
│ │
|
||||
│ ответ JSON │
|
||||
│ + скачивание │
|
||||
│ с прогресс-баром │
|
||||
└──────────────────────────>│
|
||||
```
|
||||
|
||||
**Процесс:**
|
||||
1. **Desktop приложение** проверяет сервер на наличие обновлений
|
||||
2. **Сервер** возвращает информацию о последней версии
|
||||
3. **Приложение** скачивает обновление с прогресс-баром
|
||||
4. **Пользователь** запускает установщик
|
||||
|
||||
**Для Android:** Обновления через Google Play Store (автоматически)
|
||||
|
||||
---
|
||||
|
||||
## 📦 Что нужно?
|
||||
|
||||
### Минимальные требования:
|
||||
- ✅ Хостинг с PHP 7.4+ (любой: Timeweb, Beget, VPS)
|
||||
- ✅ Домен или поддомен (например: `api.umbrix.net`)
|
||||
- ✅ HTTPS сертификат (бесплатный Let's Encrypt)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Установка - Пошагово
|
||||
|
||||
### Шаг 1: Подготовка сервера
|
||||
|
||||
1. **Создайте папку на сервере:**
|
||||
```bash
|
||||
mkdir -p /var/www/updates
|
||||
```
|
||||
|
||||
2. **Загрузите файлы из папки `update-server/`:**
|
||||
- `api.php` - главный скрипт
|
||||
- `latest.json` - информация о последней версии
|
||||
- `.htaccess` - настройки Apache
|
||||
|
||||
3. **Создайте папку для APK файлов:**
|
||||
```bash
|
||||
mkdir -p /var/www/updates/downloads
|
||||
chmod 755 /var/www/updates/downloads
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Шаг 2: Настройка домена
|
||||
|
||||
1. **Создайте поддомен** (в панели хостинга):
|
||||
- Имя: `api` или `updates`
|
||||
- Полный адрес: `api.umbrix.net`
|
||||
- Папка: `/var/www/updates`
|
||||
|
||||
2. **Включите HTTPS:**
|
||||
- В панели хостинга найдите "SSL сертификат"
|
||||
- Выберите "Let's Encrypt" (бесплатно)
|
||||
- Нажмите "Установить"
|
||||
|
||||
---
|
||||
|
||||
### Шаг 3: Настройка приложения
|
||||
|
||||
Откройте файл `lib/core/model/constants.dart` и измените:
|
||||
|
||||
```dart
|
||||
// Замените на адрес вашего сервера
|
||||
static const customUpdateServerUrl = "https://api.umbrix.net/api/latest";
|
||||
|
||||
// Включите собственный сервер обновлений
|
||||
static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Шаг 4: Загрузка новой версии
|
||||
|
||||
Когда у вас готова новая версия:
|
||||
|
||||
1. **Соберите APK:**
|
||||
```bash
|
||||
flutter build apk --release
|
||||
```
|
||||
|
||||
2. **Переименуйте файл** (для удобства):
|
||||
```bash
|
||||
# Из: build/app/outputs/flutter-apk/app-release.apk
|
||||
# В: umbrix-2.5.8.apk
|
||||
```
|
||||
|
||||
3. **Загрузите на сервер:**
|
||||
- Через FTP/SFTP загрузите APK в папку `/var/www/updates/downloads/`
|
||||
- Или через панель хостинга
|
||||
|
||||
4. **Обновите файл `latest.json`:**
|
||||
```json
|
||||
{
|
||||
"version": "2.5.8",
|
||||
"build_number": "258",
|
||||
"is_prerelease": false,
|
||||
"download_url": "https://api.umbrix.net/downloads/umbrix-2.5.8.apk",
|
||||
"release_notes": "🎉 Что нового:\n\n- Исправлены ошибки соединения\n- Улучшена стабильность\n- Новые серверы",
|
||||
"published_at": "2026-01-17T12:00:00Z",
|
||||
"min_required_version": "2.5.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Проверка работы
|
||||
|
||||
### 1. Проверьте API в браузере:
|
||||
|
||||
Откройте: `https://api.umbrix.net/api/latest`
|
||||
|
||||
Должны увидеть JSON:
|
||||
```json
|
||||
{
|
||||
"version": "2.5.8",
|
||||
"build_number": "258",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Проверьте скачивание APK:
|
||||
|
||||
Откройте: `https://api.umbrix.net/downloads/umbrix-2.5.8.apk`
|
||||
|
||||
Должно начаться скачивание файла.
|
||||
|
||||
### 3. Проверьте в приложении:
|
||||
|
||||
1. Откройте приложение
|
||||
2. Зайдите в **Настройки → О программе**
|
||||
3. Нажмите **"Проверить обновления"**
|
||||
4. Должно появиться окно с новой версией (если она новее текущей)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Структура файлов на сервере
|
||||
|
||||
```
|
||||
/var/www/updates/
|
||||
├── api.php # Главный скрипт API
|
||||
├── latest.json # Информация о последней версии
|
||||
├── .htaccess # Настройки Apache (ЧПУ, безопасность)
|
||||
├── downloads/ # Папка с APK файлами
|
||||
│ ├── umbrix-2.5.7.apk
|
||||
│ ├── umbrix-2.5.8.apk
|
||||
│ └── umbrix-2.6.0-beta.apk
|
||||
└── logs/ # Логи (автоматически создается)
|
||||
└── access.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Безопасность
|
||||
|
||||
### Уже реализовано:
|
||||
|
||||
✅ **CORS защита** - только ваше приложение может запрашивать обновления
|
||||
✅ **Rate Limiting** - не более 10 запросов в минуту с одного IP
|
||||
✅ **Валидация JSON** - проверка формата данных
|
||||
✅ **Логирование** - все запросы записываются
|
||||
|
||||
### Рекомендации:
|
||||
|
||||
1. **Используйте HTTPS** (обязательно!)
|
||||
2. **Регулярно обновляйте** PHP на сервере
|
||||
3. **Делайте бэкапы** файлов и APK
|
||||
4. **Проверяйте логи** на подозрительную активность
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Дополнительные возможности
|
||||
|
||||
### 1. Принудительное обновление
|
||||
|
||||
Если нужно **заставить** пользователей обновиться:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.6.0",
|
||||
"force_update": true,
|
||||
"min_required_version": "2.5.0"
|
||||
}
|
||||
```
|
||||
|
||||
Приложение не запустится на версиях ниже 2.5.0.
|
||||
|
||||
### 2. Бета-версии
|
||||
|
||||
Для тестировщиков:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.6.0-beta",
|
||||
"is_prerelease": true,
|
||||
"download_url": "https://api.umbrix.net/downloads/umbrix-2.6.0-beta.apk"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Аналитика
|
||||
|
||||
Смотрите файл `logs/access.log`:
|
||||
- Сколько пользователей проверяют обновления
|
||||
- Какие версии используют
|
||||
- Откуда приходят запросы
|
||||
|
||||
---
|
||||
|
||||
## ❓ Частые проблемы
|
||||
|
||||
### Проблема: "Обновления не приходят"
|
||||
|
||||
**Решение:**
|
||||
1. Проверьте, что `useCustomUpdateServer = true` в `constants.dart`
|
||||
2. Проверьте, что URL правильный (с `https://`)
|
||||
3. Проверьте, что `version` в `latest.json` больше текущей
|
||||
4. Пересоберите приложение после изменения констант
|
||||
|
||||
### Проблема: "Ошибка при скачивании APK"
|
||||
|
||||
**Решение:**
|
||||
1. Проверьте права на папку: `chmod 755 downloads`
|
||||
2. Проверьте, что файл существует
|
||||
3. Проверьте, что URL в `download_url` правильный
|
||||
|
||||
### Проблема: "API возвращает ошибку 500"
|
||||
|
||||
**Решение:**
|
||||
1. Проверьте PHP логи на сервере
|
||||
2. Убедитесь, что PHP версии 7.4+
|
||||
3. Проверьте права на файл `latest.json`: `chmod 644 latest.json`
|
||||
|
||||
---
|
||||
|
||||
## 📞 Поддержка
|
||||
|
||||
Если что-то не работает:
|
||||
|
||||
1. Проверьте логи: `/var/www/updates/logs/access.log`
|
||||
2. Проверьте PHP логи на сервере
|
||||
3. Напишите в поддержку хостинга
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Дополнительная информация
|
||||
|
||||
### Полезные команды для сервера:
|
||||
|
||||
```bash
|
||||
# Посмотреть последние запросы
|
||||
tail -f /var/www/updates/logs/access.log
|
||||
|
||||
# Проверить размер APK файлов
|
||||
du -h /var/www/updates/downloads/*
|
||||
|
||||
# Очистить старые APK (оставить последние 3)
|
||||
ls -t /var/www/updates/downloads/*.apk | tail -n +4 | xargs rm
|
||||
|
||||
# Проверить права доступа
|
||||
ls -la /var/www/updates/
|
||||
```
|
||||
|
||||
### Тестирование API через curl:
|
||||
|
||||
```bash
|
||||
# Проверить API
|
||||
curl https://api.umbrix.net/api/latest
|
||||
|
||||
# Проверить с бета-версиями
|
||||
curl "https://api.umbrix.net/api/latest?include_prerelease=true"
|
||||
|
||||
# Скачать APK
|
||||
curl -O https://api.umbrix.net/downloads/umbrix-2.5.8.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Чеклист перед запуском
|
||||
|
||||
- [ ] PHP 7.4+ установлен
|
||||
- [ ] Папка `/var/www/updates` создана
|
||||
- [ ] Файлы `api.php`, `latest.json`, `.htaccess` загружены
|
||||
- [ ] Папка `downloads/` создана с правами 755
|
||||
- [ ] Домен `api.umbrix.net` настроен
|
||||
- [ ] SSL сертификат установлен
|
||||
- [ ] URL в `constants.dart` обновлен
|
||||
- [ ] Приложение пересобрано
|
||||
- [ ] API отвечает в браузере
|
||||
- [ ] APK скачивается по ссылке
|
||||
- [ ] Проверка обновлений работает в приложении
|
||||
|
||||
---
|
||||
|
||||
**🎉 Готово! Теперь вы можете выкатывать обновления без магазинов!**
|
||||
187
update-server/README_DESKTOP.md
Normal file
187
update-server/README_DESKTOP.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# 🖥️ Сервер Обновлений Umbrix для Desktop Платформ
|
||||
|
||||
## 📋 Что это?
|
||||
|
||||
Система автоматических обновлений для **настольных версий** Umbrix (Windows, macOS, Linux).
|
||||
|
||||
> **⚠️ Важно:** Для Android используется Google Play Store. Этот сервер только для Desktop!
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Как это работает?
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────────┐ ┌─────────────┐
|
||||
│ Desktop App │ -------> │ Ваш сервер │ <------- │ Вы загружаете│
|
||||
│ Windows/Mac/ │ запрос │ (PHP API) │ файлы │ новую версию │
|
||||
│ Linux │ │ │ │ .exe/.dmg │
|
||||
└──────────────┘ └──────────────────┘ └─────────────┘
|
||||
│ │
|
||||
│ ответ JSON │
|
||||
│ + скачивание │
|
||||
│ с прогресс-баром │
|
||||
└──────────────────────────>│
|
||||
```
|
||||
|
||||
**Процесс:**
|
||||
1. **Desktop приложение** проверяет сервер на наличие обновлений
|
||||
2. **Сервер** возвращает информацию о последней версии
|
||||
3. **Приложение** скачивает обновление с прогресс-баром
|
||||
4. **Пользователь** запускает установщик
|
||||
|
||||
**Для Android:** Обновления через Google Play Store (автоматически)
|
||||
|
||||
---
|
||||
|
||||
## 📦 Требования
|
||||
|
||||
- **PHP 7.4+** с веб-сервером (Apache/Nginx) или встроенный сервер PHP
|
||||
- Доступ к файловой системе для хранения файлов обновлений
|
||||
- (Опционально) Docker для production деплоя
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### 1. Локальный запуск (для разработки)
|
||||
|
||||
```bash
|
||||
cd update-server
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
Откройте: http://localhost:8000/admin/
|
||||
|
||||
### 2. Загрузка файла обновления
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
cp umbrix-1.7.3-setup.exe downloads/windows/
|
||||
|
||||
# macOS
|
||||
cp umbrix-1.7.3.dmg downloads/macos/
|
||||
|
||||
# Linux
|
||||
cp umbrix-1.7.3.AppImage downloads/linux/
|
||||
```
|
||||
|
||||
### 3. Обновление версии через Web-панель
|
||||
|
||||
1. Откройте http://localhost:8000/admin/
|
||||
2. Введите новую версию (например: 1.7.3)
|
||||
3. Укажите путь к файлу (например: `http://your-server.com/downloads/windows/umbrix-1.7.3.exe`)
|
||||
4. Нажмите "Сохранить"
|
||||
|
||||
---
|
||||
|
||||
## 📁 Структура
|
||||
|
||||
```
|
||||
update-server/
|
||||
├── api.php # REST API для проверки обновлений
|
||||
├── latest.json # Информация о последней версии
|
||||
├── admin/
|
||||
│ ├── index.html # Web-панель управления
|
||||
│ ├── save.php # Сохранение новой версии
|
||||
│ ├── history.php # История версий
|
||||
│ └── restore.php # Откат на предыдущую версию
|
||||
├── downloads/ # Файлы обновлений
|
||||
│ ├── windows/ # .exe, .msi
|
||||
│ ├── macos/ # .dmg, .pkg
|
||||
│ ├── linux/ # .AppImage, .deb, .rpm
|
||||
│ └── android/ # (только для тестирования)
|
||||
└── backups/ # Автоматические резервные копии
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 API Endpoints
|
||||
|
||||
### `GET /api.php` - Проверка обновлений
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"version": "1.7.3",
|
||||
"build_number": "173",
|
||||
"is_prerelease": false,
|
||||
"download_url": "http://server.com/downloads/windows/umbrix-1.7.3.exe",
|
||||
"release_notes": "Новые возможности...",
|
||||
"published_at": "2026-01-17T12:00:00.000Z",
|
||||
"min_required_version": "1.0.0",
|
||||
"file_size_bytes": 95000000,
|
||||
"file_checksum_sha256": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Docker Development
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Сервер будет доступен на http://localhost:8000
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Production деплой
|
||||
|
||||
### Вариант 1: Обычный веб-хостинг
|
||||
|
||||
1. Загрузите файлы на сервер
|
||||
2. Настройте веб-сервер (Apache/Nginx)
|
||||
3. Установите права доступа:
|
||||
```bash
|
||||
chmod 755 update-server/
|
||||
chmod 644 update-server/*.php
|
||||
chmod 755 update-server/downloads/
|
||||
```
|
||||
|
||||
### Вариант 2: Docker
|
||||
|
||||
См. [DOCKER_STORAGE.md](DOCKER_STORAGE.md) для настройки production окружения.
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Безопасность
|
||||
|
||||
- ✅ Rate limiting в API (10 запросов в минуту с одного IP)
|
||||
- ✅ Валидация входных данных
|
||||
- ✅ Автоматические бэкапы перед изменениями
|
||||
- ⚠️ **Рекомендуется:** HTTPS для production
|
||||
- ⚠️ **Рекомендуется:** Базовая HTTP авторизация для /admin/
|
||||
|
||||
---
|
||||
|
||||
## 📚 Дополнительная документация
|
||||
|
||||
- [UPLOAD_FILES.txt](UPLOAD_FILES.txt) - Как загружать файлы обновлений
|
||||
- [DOCKER_STORAGE.md](DOCKER_STORAGE.md) - Настройка storage для Docker
|
||||
- [DOCKER_QUICKSTART.md](DOCKER_QUICKSTART.md) - Быстрый запуск с Docker
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Поддержка
|
||||
|
||||
Если приложение не видит обновления:
|
||||
1. Проверьте доступность API: `curl http://your-server.com/api.php`
|
||||
2. Убедитесь, что latest.json содержит актуальные данные
|
||||
3. Проверьте логи: `cat logs/access.log`
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Настройка в приложении
|
||||
|
||||
В `lib/core/model/constants.dart`:
|
||||
|
||||
```dart
|
||||
// Включить/выключить custom update server
|
||||
static const bool useCustomUpdateServer = true;
|
||||
|
||||
// URL вашего сервера обновлений (только для Desktop)
|
||||
static const String customUpdateServerUrl = "https://your-server.com/api.php";
|
||||
```
|
||||
|
||||
**Примечание:** Для Android эта настройка игнорируется, используется Google Play.
|
||||
246
update-server/TESTING.md
Normal file
246
update-server/TESTING.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# 🎯 Тестирование обновлений в эмуляторе
|
||||
|
||||
## Как проверить систему обновлений
|
||||
|
||||
### Подготовка (разовая настройка)
|
||||
|
||||
1. **Запустите эмулятор:**
|
||||
```bash
|
||||
flutter emulators --launch UmbrixTest
|
||||
```
|
||||
|
||||
2. **Установите текущую версию:**
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
3. **Настройте тестовый сервер** (выберите один из вариантов):
|
||||
|
||||
#### Вариант А: Локальный PHP сервер (проще)
|
||||
|
||||
```bash
|
||||
# Перейдите в папку с сервером
|
||||
cd update-server
|
||||
|
||||
# Запустите встроенный PHP сервер
|
||||
php -S localhost:8000
|
||||
|
||||
# Сервер будет доступен по адресу: http://localhost:8000
|
||||
```
|
||||
|
||||
Затем в `constants.dart` укажите:
|
||||
```dart
|
||||
static const customUpdateServerUrl = "http://10.0.2.2:8000/api.php";
|
||||
// 10.0.2.2 - это localhost для Android эмулятора
|
||||
static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
#### Вариант Б: Ngrok (если нужен HTTPS)
|
||||
|
||||
```bash
|
||||
# В одном терминале запустите PHP
|
||||
cd update-server
|
||||
php -S localhost:8000
|
||||
|
||||
# В другом терминале запустите ngrok
|
||||
ngrok http 8000
|
||||
|
||||
# Скопируйте HTTPS URL (например: https://abc123.ngrok.io)
|
||||
```
|
||||
|
||||
Затем в `constants.dart`:
|
||||
```dart
|
||||
static const customUpdateServerUrl = "https://abc123.ngrok.io/api.php";
|
||||
static const useCustomUpdateServer = true;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Тестирование обновления
|
||||
|
||||
#### 1. Установите старую версию
|
||||
|
||||
В `pubspec.yaml` установите версию `2.5.6`:
|
||||
```yaml
|
||||
version: 2.5.6+256
|
||||
```
|
||||
|
||||
Пересоберите и установите:
|
||||
```bash
|
||||
flutter build apk --release
|
||||
flutter install
|
||||
```
|
||||
|
||||
#### 2. Настройте сервер на новую версию
|
||||
|
||||
Отредактируйте `update-server/latest.json`:
|
||||
```json
|
||||
{
|
||||
"version": "2.5.7",
|
||||
"build_number": "257",
|
||||
"download_url": "http://10.0.2.2:8000/downloads/umbrix-2.5.7.apk"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Создайте APK новой версии
|
||||
|
||||
Вернитесь к версии `2.5.7` в `pubspec.yaml`:
|
||||
```yaml
|
||||
version: 2.5.7+257
|
||||
```
|
||||
|
||||
Соберите APK:
|
||||
```bash
|
||||
flutter build apk --release
|
||||
```
|
||||
|
||||
Скопируйте APK в папку downloads:
|
||||
```bash
|
||||
cp build/app/outputs/flutter-apk/app-release.apk \
|
||||
update-server/downloads/umbrix-2.5.7.apk
|
||||
```
|
||||
|
||||
#### 4. Проверьте обновление
|
||||
|
||||
1. Откройте приложение (версия 2.5.6)
|
||||
2. Зайдите в **Настройки → О программе**
|
||||
3. Нажмите **"Проверить обновления"**
|
||||
4. Должно появиться окно с предложением обновиться до 2.5.7
|
||||
5. Нажмите **"Обновить сейчас"**
|
||||
6. Скачается и установится новая версия
|
||||
|
||||
---
|
||||
|
||||
### Отладка
|
||||
|
||||
#### Проверить API в браузере:
|
||||
|
||||
```bash
|
||||
# Если используете локальный сервер
|
||||
curl http://localhost:8000/api.php
|
||||
|
||||
# Должны увидеть JSON:
|
||||
{
|
||||
"version": "2.5.7",
|
||||
"build_number": "257",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
#### Проверить из эмулятора:
|
||||
|
||||
```bash
|
||||
# Подключитесь к эмулятору через adb
|
||||
adb shell
|
||||
|
||||
# Проверьте доступность сервера
|
||||
curl http://10.0.2.2:8000/api.php
|
||||
```
|
||||
|
||||
#### Смотреть логи приложения:
|
||||
|
||||
```bash
|
||||
adb logcat | grep -i "update\|umbrix"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Частые проблемы
|
||||
|
||||
**Проблема:** "Не удается подключиться к серверу"
|
||||
|
||||
**Решение:**
|
||||
- Используйте `10.0.2.2` вместо `localhost` для эмулятора
|
||||
- Проверьте, что PHP сервер запущен
|
||||
- Проверьте firewall
|
||||
|
||||
---
|
||||
|
||||
**Проблема:** "Обновление не отображается"
|
||||
|
||||
**Решение:**
|
||||
- Убедитесь, что версия в `latest.json` больше текущей
|
||||
- Проверьте `useCustomUpdateServer = true` в `constants.dart`
|
||||
- Пересоберите приложение после изменения констант
|
||||
|
||||
---
|
||||
|
||||
**Проблема:** "Ошибка при скачивании APK"
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что файл `umbrix-2.5.7.apk` существует в папке `downloads/`
|
||||
- Проверьте права доступа: `chmod 644 umbrix-2.5.7.apk`
|
||||
- Убедитесь, что URL правильный
|
||||
|
||||
---
|
||||
|
||||
### Пример полного цикла тестирования
|
||||
|
||||
```bash
|
||||
# 1. Запустить PHP сервер
|
||||
cd update-server
|
||||
php -S localhost:8000 &
|
||||
|
||||
# 2. Изменить версию на старую
|
||||
sed -i 's/version: 2.5.7/version: 2.5.6/' pubspec.yaml
|
||||
|
||||
# 3. Установить старую версию
|
||||
flutter build apk --release
|
||||
flutter install
|
||||
|
||||
# 4. Вернуть новую версию
|
||||
sed -i 's/version: 2.5.6/version: 2.5.7/' pubspec.yaml
|
||||
|
||||
# 5. Собрать новый APK
|
||||
flutter build apk --release
|
||||
cp build/app/outputs/flutter-apk/app-release.apk \
|
||||
update-server/downloads/umbrix-2.5.7.apk
|
||||
|
||||
# 6. Проверить API
|
||||
curl http://localhost:8000/api.php
|
||||
|
||||
# 7. Открыть приложение и проверить обновления
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Готовые команды
|
||||
|
||||
Сохраните в `test_update.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "🚀 Тестирование системы обновлений"
|
||||
|
||||
# Запуск PHP сервера
|
||||
cd update-server
|
||||
php -S localhost:8000 > /dev/null 2>&1 &
|
||||
PHP_PID=$!
|
||||
echo "✅ PHP сервер запущен (PID: $PHP_PID)"
|
||||
|
||||
# Ждем запуска
|
||||
sleep 2
|
||||
|
||||
# Проверка API
|
||||
echo "🔍 Проверка API..."
|
||||
curl -s http://localhost:8000/api.php | jq .
|
||||
|
||||
echo ""
|
||||
echo "📱 Теперь:"
|
||||
echo "1. Откройте приложение"
|
||||
echo "2. Зайдите в Настройки → О программе"
|
||||
echo "3. Нажмите 'Проверить обновления'"
|
||||
echo ""
|
||||
echo "Для остановки сервера: kill $PHP_PID"
|
||||
```
|
||||
|
||||
Сделайте исполняемым и запустите:
|
||||
```bash
|
||||
chmod +x test_update.sh
|
||||
./test_update.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**✅ Готово! Теперь вы можете полностью протестировать систему обновлений!**
|
||||
230
update-server/TESTING_v1.1.md
Normal file
230
update-server/TESTING_v1.1.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# ✅ Тестирование системы обновлений v1.1
|
||||
|
||||
## Что было сделано
|
||||
|
||||
### 1. Упрощение кода
|
||||
- ✅ Android: Просто открывает браузер (как было изначально)
|
||||
- ✅ Desktop: Загрузка с прогресс-баром
|
||||
- ✅ Удалены все сложные Android permissions и handlers
|
||||
|
||||
### 2. Удалённый код
|
||||
- ❌ `InstallHandler.kt` - файл удалён
|
||||
- ❌ `REQUEST_INSTALL_PACKAGES` permission - убран из манифеста
|
||||
- ❌ `MethodChannel` для Android permissions - удалён
|
||||
- ❌ Регистрация InstallHandler в MainActivity - удалена
|
||||
|
||||
### 3. Обновлённая документация
|
||||
- ✅ `README.md` - предупреждение о Desktop-only
|
||||
- ✅ `README_DESKTOP.md` - новая документация
|
||||
- ✅ `CHANGELOG_DESKTOP.md` - полная история изменений
|
||||
- ✅ `api.php` - обновлены комментарии
|
||||
|
||||
---
|
||||
|
||||
## Текущее состояние
|
||||
|
||||
### Сервер
|
||||
```bash
|
||||
# Запущен на:
|
||||
php -S localhost:8000 -t /home/vodorod/dorod/hiddify-umbrix-v1.7.0/update-server
|
||||
|
||||
# Доступен по:
|
||||
http://localhost:8000/api.php (API)
|
||||
http://localhost:8000/admin.php (Admin Panel)
|
||||
|
||||
# Текущая версия на сервере: 1.7.3
|
||||
```
|
||||
|
||||
### Приложение
|
||||
```bash
|
||||
# Установлено на эмуляторе:
|
||||
com.umbrix.app (v1.7.0, build 170)
|
||||
|
||||
# Путь к APK:
|
||||
/home/vodorod/dorod/hiddify-umbrix-v1.7.0/build/app/outputs/flutter-apk/app-debug.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Как протестировать
|
||||
|
||||
### На Android (эмулятор)
|
||||
|
||||
1. **Откройте приложение Umbrix**
|
||||
|
||||
2. **НЕ заходите в "О программе"** → кнопка "Проверить обновления" теперь **скрыта для Android**
|
||||
|
||||
3. **Как проверить?** Нужно вызвать проверку программно или через debug mode
|
||||
|
||||
4. **Ожидаемое поведение:**
|
||||
- Обнаружит версию 1.7.3 на сервере
|
||||
- Покажет диалог с информацией
|
||||
- Кнопка "Обновить" откроет **браузер** (не скачивание!)
|
||||
- URL: `http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk`
|
||||
|
||||
### На Desktop (когда соберёте)
|
||||
|
||||
1. **Windows:**
|
||||
```bash
|
||||
flutter build windows --release
|
||||
# Установщик откроется автоматически после загрузки
|
||||
```
|
||||
|
||||
2. **macOS:**
|
||||
```bash
|
||||
flutter build macos --release
|
||||
# .dmg откроется автоматически
|
||||
```
|
||||
|
||||
3. **Linux:**
|
||||
```bash
|
||||
flutter build linux --release
|
||||
# .AppImage откроется для запуска
|
||||
```
|
||||
|
||||
**Ожидаемое поведение для Desktop:**
|
||||
- Зайти в "О программе" → "Проверить обновления"
|
||||
- Обнаружит версию 1.7.3
|
||||
- Покажет диалог с прогресс-баром
|
||||
- Скачает файл в `/tmp/umbrix-1.7.3.exe` (или .dmg/.AppImage)
|
||||
- Автоматически откроет установщик
|
||||
- Пользователь запустит установку вручную
|
||||
|
||||
---
|
||||
|
||||
## Проверка кода
|
||||
|
||||
### new_version_dialog.dart
|
||||
```dart
|
||||
// Для Android - просто браузер
|
||||
if (Platform.isAndroid) {
|
||||
await UriUtils.tryLaunch(Uri.parse(newVersion.url));
|
||||
if (context.mounted) context.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Для Desktop - скачивание с прогресс-баром
|
||||
try {
|
||||
isDownloading.value = true;
|
||||
downloadProgress.value = 0.0;
|
||||
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
String fileExt = '';
|
||||
if (Platform.isWindows) fileExt = '.exe';
|
||||
else if (Platform.isMacOS) fileExt = '.dmg';
|
||||
else if (Platform.isLinux) fileExt = '.AppImage';
|
||||
|
||||
// ... скачивание с прогресс-баром ...
|
||||
await OpenFile.open(savePath);
|
||||
}
|
||||
```
|
||||
|
||||
### about_page.dart
|
||||
```dart
|
||||
// Кнопка видна ТОЛЬКО на Desktop
|
||||
if (PlatformUtils.isDesktop)
|
||||
FilledButton(
|
||||
onPressed: () => ref.read(appUpdateNotifierProvider.notifier).checkForUpdate(context),
|
||||
child: Text(t.about.checkForUpdateButtonTxt),
|
||||
),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Что дальше?
|
||||
|
||||
### Immediate (сейчас)
|
||||
1. ✅ Код упрощён и скомпилирован
|
||||
2. ✅ APK установлен на эмулятор
|
||||
3. ⏳ Протестировать на Android → должен открыть браузер
|
||||
4. ⏳ Убедиться, что кнопка "Проверить обновления" скрыта
|
||||
|
||||
### Short-term (ближайшее время)
|
||||
1. Собрать Windows .exe
|
||||
2. Собрать macOS .dmg
|
||||
3. Собрать Linux .AppImage
|
||||
4. Загрузить файлы в `update-server/downloads/`
|
||||
5. Протестировать на реальном Desktop
|
||||
|
||||
### Long-term (production)
|
||||
1. Опубликовать в Google Play Store
|
||||
2. Удалить Android поддержку из update-server
|
||||
3. Настроить production сервер (не localhost)
|
||||
4. Добавить SSL сертификат
|
||||
5. Настроить CDN для быстрой загрузки
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Проблема: Кнопка "Проверить обновления" всё ещё видна на Android
|
||||
|
||||
**Решение:** Проверьте `PlatformUtils.isDesktop`:
|
||||
```dart
|
||||
// Должно быть:
|
||||
if (PlatformUtils.isDesktop) // только Desktop
|
||||
|
||||
// НЕ должно быть:
|
||||
if (!Platform.isIOS) // все кроме iOS
|
||||
```
|
||||
|
||||
### Проблема: На Desktop не скачивается файл
|
||||
|
||||
**Проверьте:**
|
||||
1. Интернет соединение
|
||||
2. URL в `latest.json` правильный
|
||||
3. Файл существует на сервере
|
||||
4. CORS настройки в `api.php`
|
||||
|
||||
### Проблема: Прогресс-бар не движется
|
||||
|
||||
**Проверьте:**
|
||||
1. Сервер возвращает `Content-Length` header
|
||||
2. `dio` версия ^5.4.1
|
||||
3. `onReceiveProgress` callback работает
|
||||
|
||||
---
|
||||
|
||||
## Файлы для проверки
|
||||
|
||||
```bash
|
||||
# Код приложения
|
||||
lib/features/app_update/widget/new_version_dialog.dart ← УПРОЩЁН
|
||||
lib/features/settings/about/about_page.dart ← УСЛОВИЕ ДОБАВЛЕНО
|
||||
android/app/src/main/AndroidManifest.xml ← PERMISSION УДАЛЁН
|
||||
android/app/src/main/kotlin/com/umbrix/app/MainActivity.kt ← HANDLER УДАЛЁН
|
||||
|
||||
# Документация
|
||||
update-server/README.md ← ОБНОВЛЁН
|
||||
update-server/README_DESKTOP.md ← СОЗДАН
|
||||
update-server/CHANGELOG_DESKTOP.md ← СОЗДАН
|
||||
update-server/api.php ← КОММЕНТАРИИ ОБНОВЛЕНЫ
|
||||
|
||||
# Удалённые файлы
|
||||
android/app/src/main/kotlin/com/umbrix/app/InstallHandler.kt ← УДАЛЁН
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Статистика изменений
|
||||
|
||||
- **Файлов изменено:** 5
|
||||
- **Файлов создано:** 3
|
||||
- **Файлов удалено:** 1
|
||||
- **Строк кода удалено:** ~150 (Android permissions logic)
|
||||
- **Строк кода добавлено:** ~50 (Desktop download logic)
|
||||
- **Упрощение:** 67% меньше кода для Android
|
||||
|
||||
---
|
||||
|
||||
## Заключение
|
||||
|
||||
Система обновлений теперь:
|
||||
- ✅ Проще и понятнее
|
||||
- ✅ Разделена по платформам
|
||||
- ✅ Android → Google Play Store (standard way)
|
||||
- ✅ Desktop → Custom update server (flexibility)
|
||||
- ✅ Лучший UX для пользователей
|
||||
- ✅ Меньше кода для поддержки
|
||||
|
||||
**Готово к тестированию! 🚀**
|
||||
128
update-server/UPLOAD_FILES.txt
Normal file
128
update-server/UPLOAD_FILES.txt
Normal file
@@ -0,0 +1,128 @@
|
||||
╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
║ 📦 ШПАРГАЛКА: ДОБАВЛЕНИЕ ОБНОВЛЕНИЙ ║
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
┌─ 1️⃣ СОБЕРИТЕ ПРИЛОЖЕНИЕ ──────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 🤖 Android: │
|
||||
│ flutter build apk --release │
|
||||
│ → build/app/outputs/flutter-apk/app-release.apk │
|
||||
│ │
|
||||
│ 🪟 Windows: │
|
||||
│ flutter build windows --release │
|
||||
│ → Создайте инсталлятор (Inno Setup, MSIX) │
|
||||
│ │
|
||||
│ 🍎 iOS: │
|
||||
│ flutter build ipa --release │
|
||||
│ → build/ios/ipa/*.ipa (требуется Apple Developer) │
|
||||
│ │
|
||||
│ 🐧 Linux: │
|
||||
│ flutter build linux --release │
|
||||
│ → Упакуйте в AppImage │
|
||||
│ │
|
||||
│ 🖥️ macOS: │
|
||||
│ flutter build macos --release │
|
||||
│ → Создайте DMG образ │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 2️⃣ СКОПИРУЙТЕ ФАЙЛЫ В ПАПКИ ────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ update-server/downloads/ │
|
||||
│ ├── android/umbrix-2.5.8.apk ← APK файл │
|
||||
│ ├── windows/umbrix-2.5.8-setup.exe ← EXE инсталлятор │
|
||||
│ ├── ios/umbrix-2.5.8.ipa ← IPA файл │
|
||||
│ ├── linux/umbrix-2.5.8.AppImage ← AppImage │
|
||||
│ └── macos/umbrix-2.5.8.dmg ← DMG образ │
|
||||
│ │
|
||||
│ 💡 Совет: Используйте номер версии в имени файла! │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 3️⃣ ЗАГРУЗИТЕ НА СЕРВЕР ─────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 🔸 Локальная разработка (копирование): │
|
||||
│ cp build/app/outputs/flutter-apk/app-release.apk \ │
|
||||
│ update-server/downloads/android/umbrix-2.5.8.apk │
|
||||
│ │
|
||||
│ 🔸 Продакшен сервер (SCP): │
|
||||
│ scp -r downloads/ user@server.com:/path/to/update-server/ │
|
||||
│ │
|
||||
│ 🔸 Через FTP/SFTP: │
|
||||
│ FileZilla, WinSCP, Cyberduck │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 4️⃣ УКАЖИТЕ URL В ВЕБ-ПАНЕЛИ ────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 🌐 Откройте: http://localhost:8000/admin/ │
|
||||
│ │
|
||||
│ 📝 Заполните форму: │
|
||||
│ • Версия: 2.5.8 │
|
||||
│ • Build Number: 258 │
|
||||
│ • URL: https://your-server.com/downloads/android/umbrix-2.5.8.apk │
|
||||
│ • Описание: Что нового в версии │
|
||||
│ │
|
||||
│ 💾 Нажмите "Сохранить обновление" │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 📋 ПРИМЕРЫ URL ДЛЯ РАЗНЫХ ПЛАТФОРМ ──────────────────────────────────────┐
|
||||
│ │
|
||||
│ 🤖 Android: │
|
||||
│ https://api.umbrix.net/downloads/android/umbrix-2.5.8.apk │
|
||||
│ │
|
||||
│ 🪟 Windows: │
|
||||
│ https://api.umbrix.net/downloads/windows/umbrix-2.5.8-setup.exe │
|
||||
│ │
|
||||
│ 🍎 iOS: │
|
||||
│ https://api.umbrix.net/downloads/ios/umbrix-2.5.8.ipa │
|
||||
│ │
|
||||
│ 🐧 Linux: │
|
||||
│ https://api.umbrix.net/downloads/linux/umbrix-2.5.8.AppImage │
|
||||
│ │
|
||||
│ 🖥️ macOS: │
|
||||
│ https://api.umbrix.net/downloads/macos/umbrix-2.5.8.dmg │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ ⚡ БЫСТРЫЙ СТАРТ ──────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ # 1. Соберите APK │
|
||||
│ flutter build apk --release │
|
||||
│ │
|
||||
│ # 2. Скопируйте файл │
|
||||
│ cp build/app/outputs/flutter-apk/app-release.apk \ │
|
||||
│ update-server/downloads/android/umbrix-2.5.8.apk │
|
||||
│ │
|
||||
│ # 3. Откройте веб-панель │
|
||||
│ xdg-open http://localhost:8000/admin/ │
|
||||
│ │
|
||||
│ # 4. Заполните форму и сохраните! │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 🔒 ВАЖНО ДЛЯ ПРОДАКШЕНА ──────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ ✓ Используйте HTTPS (обязательно!) │
|
||||
│ ✓ Настройте CORS правильно │
|
||||
│ ✓ Ограничьте доступ к /admin/ │
|
||||
│ ✓ Делайте бэкапы (автоматические) │
|
||||
│ ✓ Храните 2-3 последние версии │
|
||||
│ ✓ Тестируйте перед публикацией │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 📊 ТИПИЧНЫЕ РАЗМЕРЫ ФАЙЛОВ ───────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Android APK: 30-70 MB (обычно 40-60 MB с Flutter) │
|
||||
│ Windows EXE: 50-100 MB │
|
||||
│ iOS IPA: 50-80 MB │
|
||||
│ Linux AppImage: 70-120 MB │
|
||||
│ macOS DMG: 60-100 MB │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
║ 💡 Подробнее: update-server/downloads/README.md ║
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
33
update-server/admin/.htaccess
Normal file
33
update-server/admin/.htaccess
Normal file
@@ -0,0 +1,33 @@
|
||||
# Umbrix Admin Panel - Защита доступа
|
||||
|
||||
# Базовая аутентификация
|
||||
AuthType Basic
|
||||
AuthName "Umbrix Update Manager"
|
||||
# Путь к файлу паролей (создайте командой: htpasswd -c .htpasswd admin)
|
||||
AuthUserFile /var/www/updates/admin/.htpasswd
|
||||
Require valid-user
|
||||
|
||||
# Блокировка прямого доступа к PHP файлам из браузера (опционально)
|
||||
# <FilesMatch "save\.php$">
|
||||
# Order deny,allow
|
||||
# Deny from all
|
||||
# </FilesMatch>
|
||||
|
||||
# CORS для локальных запросов
|
||||
<IfModule mod_headers.c>
|
||||
Header set Access-Control-Allow-Origin "*"
|
||||
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
|
||||
Header set Access-Control-Allow-Headers "Content-Type, X-Admin-Password"
|
||||
</IfModule>
|
||||
|
||||
# Запрет доступа к бэкапам
|
||||
<FilesMatch "\.backup.*$">
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Запрет доступа к логам
|
||||
<FilesMatch "\.log$">
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
305
update-server/admin/README.md
Normal file
305
update-server/admin/README.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# 🎨 Веб-панель управления обновлениями
|
||||
|
||||
## 📋 Что это?
|
||||
|
||||
Простой веб-интерфейс для управления обновлениями Umbrix без редактирования JSON вручную!
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ 🚀 Umbrix Update Manager │
|
||||
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
|
||||
│ │
|
||||
│ 📦 Текущая версия: 2.5.7 │
|
||||
│ │
|
||||
│ Версия: [2.5.8____________] │
|
||||
│ Build: [258______________] │
|
||||
│ URL: [https://...] │
|
||||
│ Описание: [Что нового...] │
|
||||
│ │
|
||||
│ [🔄 Загрузить] [💾 Сохранить обновление] │
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Установка
|
||||
|
||||
### Шаг 1: Загрузите файлы
|
||||
|
||||
Загрузите на сервер папку `admin/`:
|
||||
|
||||
```
|
||||
update-server/
|
||||
├── admin/ ← загрузите эту папку
|
||||
│ ├── index.html ← веб-интерфейс
|
||||
│ ├── save.php ← скрипт сохранения
|
||||
│ └── .htaccess ← защита (опционально)
|
||||
├── api.php
|
||||
└── latest.json
|
||||
```
|
||||
|
||||
### Шаг 2: Настройте права доступа
|
||||
|
||||
```bash
|
||||
# Права на папку admin
|
||||
chmod 755 admin/
|
||||
|
||||
# Права на файлы
|
||||
chmod 644 admin/index.html
|
||||
chmod 644 admin/save.php
|
||||
|
||||
# latest.json должен быть доступен для записи
|
||||
chmod 666 latest.json
|
||||
```
|
||||
|
||||
### Шаг 3: Откройте в браузере
|
||||
|
||||
Перейдите по адресу:
|
||||
```
|
||||
https://api.umbrix.net/admin/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Как пользоваться?
|
||||
|
||||
### 1. Просмотр текущей версии
|
||||
|
||||
В верхней части автоматически отображается:
|
||||
- ✅ Текущая версия
|
||||
- ✅ Build number
|
||||
- ✅ Статус (STABLE/BETA)
|
||||
- ✅ Дата публикации
|
||||
|
||||
### 2. Создание нового обновления
|
||||
|
||||
1. Заполните форму:
|
||||
- **Версия** (обязательно): `2.5.8`
|
||||
- **Build Number** (обязательно): `258`
|
||||
- **URL APK** (обязательно): `https://api.umbrix.net/downloads/umbrix-2.5.8.apk`
|
||||
- **Описание**: Что нового в версии
|
||||
- **Дата**: Автоматически или выберите
|
||||
- **Мин. версия**: С какой версии можно обновляться
|
||||
- **Бета**: Поставьте галочку для предварительных релизов
|
||||
|
||||
2. Нажмите **"💾 Сохранить обновление"**
|
||||
|
||||
3. Готово! Файл `latest.json` обновлен
|
||||
|
||||
### 3. Загрузка существующих данных
|
||||
|
||||
Нажмите **"🔄 Загрузить текущую"** чтобы заполнить форму данными из `latest.json`
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Безопасность
|
||||
|
||||
### Вариант 1: Защита паролем через .htaccess
|
||||
|
||||
Создайте файл `admin/.htaccess`:
|
||||
|
||||
```apache
|
||||
AuthType Basic
|
||||
AuthName "Umbrix Admin Panel"
|
||||
AuthUserFile /var/www/updates/admin/.htpasswd
|
||||
Require valid-user
|
||||
```
|
||||
|
||||
Создайте пароль:
|
||||
|
||||
```bash
|
||||
cd /var/www/updates/admin
|
||||
htpasswd -c .htpasswd admin
|
||||
# Введите пароль
|
||||
```
|
||||
|
||||
### Вариант 2: Защита через PHP
|
||||
|
||||
Раскомментируйте строки в `save.php`:
|
||||
|
||||
```php
|
||||
// РАСКОММЕНТИРУЙТЕ ЭТИ СТРОКИ:
|
||||
$provided_password = $_SERVER['HTTP_X_ADMIN_PASSWORD'] ?? '';
|
||||
if ($provided_password !== $admin_password) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['success' => false, 'message' => 'Неверный пароль']);
|
||||
exit();
|
||||
}
|
||||
```
|
||||
|
||||
Затем в `index.html` добавьте в fetch:
|
||||
|
||||
```javascript
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Admin-Password': 'umbrix2024' // ваш пароль
|
||||
}
|
||||
```
|
||||
|
||||
### Вариант 3: Скрыть папку admin
|
||||
|
||||
Переименуйте папку в что-то секретное:
|
||||
|
||||
```bash
|
||||
mv admin secret-panel-f7a8e2b9
|
||||
```
|
||||
|
||||
Адрес будет: `https://api.umbrix.net/secret-panel-f7a8e2b9/`
|
||||
|
||||
---
|
||||
|
||||
## 📱 Использование с телефона
|
||||
|
||||
Интерфейс адаптивный - можно управлять с телефона!
|
||||
|
||||
1. Откройте в браузере
|
||||
2. Сохраните на главный экран
|
||||
3. Готово - полноценное PWA приложение
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Тестирование локально
|
||||
|
||||
```bash
|
||||
# Запустите PHP сервер
|
||||
cd update-server
|
||||
php -S localhost:8000
|
||||
|
||||
# Откройте в браузере:
|
||||
http://localhost:8000/admin/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ Возможности
|
||||
|
||||
✅ **Красивый интерфейс** - современный дизайн
|
||||
✅ **Без кода** - просто заполните форму
|
||||
✅ **Валидация** - проверка всех полей
|
||||
✅ **Автобэкап** - старые версии сохраняются
|
||||
✅ **Логирование** - все действия записываются
|
||||
✅ **Мобильный** - работает на телефоне
|
||||
✅ **Безопасность** - защита паролем
|
||||
|
||||
---
|
||||
|
||||
## 📝 Пример использования
|
||||
|
||||
### Сценарий: Выкатка новой версии
|
||||
|
||||
1. **Соберите APK:**
|
||||
```bash
|
||||
flutter build apk --release
|
||||
```
|
||||
|
||||
2. **Загрузите APK на сервер** в `downloads/umbrix-2.5.8.apk`
|
||||
|
||||
3. **Откройте админ-панель** в браузере
|
||||
|
||||
4. **Заполните форму:**
|
||||
- Версия: `2.5.8`
|
||||
- Build: `258`
|
||||
- URL: `https://api.umbrix.net/downloads/umbrix-2.5.8.apk`
|
||||
- Описание: `🎉 Исправлены ошибки, улучшена стабильность`
|
||||
|
||||
5. **Нажмите "Сохранить"**
|
||||
|
||||
6. **Готово!** Пользователи получат уведомление
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Решение проблем
|
||||
|
||||
### Ошибка "Permission denied"
|
||||
|
||||
```bash
|
||||
# Дайте права на запись
|
||||
chmod 666 latest.json
|
||||
chmod 777 logs/
|
||||
```
|
||||
|
||||
### Ошибка "Method Not Allowed"
|
||||
|
||||
Проверьте, что файл `save.php` доступен:
|
||||
```bash
|
||||
curl -X POST https://api.umbrix.net/admin/save.php
|
||||
```
|
||||
|
||||
### Не загружается current version
|
||||
|
||||
Проверьте путь к `latest.json` в `save.php`:
|
||||
```php
|
||||
$json_file = __DIR__ . '/../latest.json';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Структура файлов
|
||||
|
||||
```
|
||||
update-server/
|
||||
├── admin/
|
||||
│ ├── index.html ← Веб-интерфейс
|
||||
│ ├── save.php ← Скрипт сохранения
|
||||
│ ├── .htaccess ← Защита (опционально)
|
||||
│ └── README.md ← Эта инструкция
|
||||
│
|
||||
├── api.php ← API для приложения
|
||||
├── latest.json ← Текущая версия
|
||||
├── latest.json.backup.* ← Автобэкапы
|
||||
│
|
||||
├── downloads/ ← APK файлы
|
||||
│ └── umbrix-*.apk
|
||||
│
|
||||
└── logs/
|
||||
├── access.log ← Логи API
|
||||
└── admin.log ← Логи админки
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Дополнительные возможности
|
||||
|
||||
### Добавить подтверждение
|
||||
|
||||
В `index.html` перед сохранением:
|
||||
|
||||
```javascript
|
||||
if (!confirm('Точно сохранить обновление v' + formData.version + '?')) {
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### Показать историю версий
|
||||
|
||||
Добавьте в `save.php`:
|
||||
|
||||
```php
|
||||
// Сохранение в историю
|
||||
$history_file = __DIR__ . '/../history.json';
|
||||
$history = file_exists($history_file)
|
||||
? json_decode(file_get_contents($history_file), true)
|
||||
: [];
|
||||
$history[] = array_merge($update_data, ['saved_at' => date('c')]);
|
||||
file_put_contents($history_file, json_encode($history, JSON_PRETTY_PRINT));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Готово!
|
||||
|
||||
Теперь у вас есть удобная панель управления обновлениями!
|
||||
|
||||
**Не нужно:**
|
||||
- ❌ Редактировать JSON вручную
|
||||
- ❌ Подключаться через SSH
|
||||
- ❌ Помнить формат файлов
|
||||
|
||||
**Просто:**
|
||||
- ✅ Открыли браузер
|
||||
- ✅ Заполнили форму
|
||||
- ✅ Нажали "Сохранить"
|
||||
|
||||
---
|
||||
|
||||
**🎉 Приятного использования!**
|
||||
67
update-server/admin/history.php
Normal file
67
update-server/admin/history.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* Umbrix Update Manager - Version History API
|
||||
* Получение списка всех сохранённых версий (бэкапов)
|
||||
*/
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$backups_dir = __DIR__ . '/../';
|
||||
$versions = [];
|
||||
|
||||
// Сканируем директорию на наличие бэкапов
|
||||
$files = glob($backups_dir . 'latest.json.backup.*');
|
||||
|
||||
// Также добавляем текущую версию
|
||||
if (file_exists($backups_dir . 'latest.json')) {
|
||||
$current = json_decode(file_get_contents($backups_dir . 'latest.json'), true);
|
||||
if ($current) {
|
||||
$versions[] = [
|
||||
'filename' => 'latest.json',
|
||||
'version' => $current['version'] ?? 'unknown',
|
||||
'build_number' => $current['build_number'] ?? 0,
|
||||
'published_at' => $current['published_at'] ?? null,
|
||||
'is_prerelease' => $current['is_prerelease'] ?? false,
|
||||
'is_current' => true,
|
||||
'timestamp' => file_exists($backups_dir . 'latest.json') ? filemtime($backups_dir . 'latest.json') : time(),
|
||||
'size' => filesize($backups_dir . 'latest.json')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем все бэкапы
|
||||
foreach ($files as $file) {
|
||||
$content = json_decode(file_get_contents($file), true);
|
||||
if ($content) {
|
||||
$filename = basename($file);
|
||||
|
||||
// Извлекаем дату из имени файла (формат: latest.json.backup.2026-01-17_08-30-45)
|
||||
preg_match('/backup\.(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})/', $filename, $matches);
|
||||
$backup_date = $matches[1] ?? null;
|
||||
|
||||
$versions[] = [
|
||||
'filename' => $filename,
|
||||
'version' => $content['version'] ?? 'unknown',
|
||||
'build_number' => $content['build_number'] ?? 0,
|
||||
'published_at' => $content['published_at'] ?? null,
|
||||
'is_prerelease' => $content['is_prerelease'] ?? false,
|
||||
'is_current' => false,
|
||||
'timestamp' => filemtime($file),
|
||||
'backup_date' => $backup_date,
|
||||
'size' => filesize($file),
|
||||
'release_notes' => $content['release_notes'] ?? ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Сортируем по времени (новые сверху)
|
||||
usort($versions, function($a, $b) {
|
||||
return $b['timestamp'] - $a['timestamp'];
|
||||
});
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'count' => count($versions),
|
||||
'versions' => $versions
|
||||
]);
|
||||
653
update-server/admin/index.html
Normal file
653
update-server/admin/index.html
Normal file
@@ -0,0 +1,653 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>🚀 Umbrix Update Manager</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: #1a1f2e;
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.5em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: #b4bcc9;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: #252d3d;
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.4);
|
||||
border: 1px solid #2d3548;
|
||||
}
|
||||
|
||||
.current-version {
|
||||
background: #1e2533;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
border-left: 4px solid #4ade80;
|
||||
border: 1px solid #2d3548;
|
||||
}
|
||||
|
||||
.current-version h3 {
|
||||
margin-bottom: 12px;
|
||||
color: #4ade80;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.version-info {
|
||||
display: grid;
|
||||
grid-template-columns: 150px 1fr;
|
||||
gap: 10px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.version-info strong {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.version-info span {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 5px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.8em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge.beta {
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
color: #ef4444;
|
||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
|
||||
.badge.stable {
|
||||
background: rgba(74, 222, 128, 0.15);
|
||||
color: #4ade80;
|
||||
border: 1px solid rgba(74, 222, 128, 0.3);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group h3 {
|
||||
color: #ffffff;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: #ffffff;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 0.85em;
|
||||
color: #9ca3af;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="url"],
|
||||
input[type="datetime-local"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid #2d3548;
|
||||
border-radius: 12px;
|
||||
font-size: 1em;
|
||||
transition: all 0.3s;
|
||||
background: #1e2533;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
border-color: #4ade80;
|
||||
background: #252d3d;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
accent-color: #4ade80;
|
||||
}
|
||||
|
||||
.checkbox-group label {
|
||||
color: #e5e7eb;
|
||||
font-weight: 400;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #4ade80;
|
||||
color: #1a1f2e;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(74, 222, 128, 0.3);
|
||||
background: #5ef590;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #2d3548;
|
||||
color: #ffffff;
|
||||
border: 1px solid #3d4658;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #363f54;
|
||||
border-color: #4ade80;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
display: none;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.status.success {
|
||||
background: rgba(74, 222, 128, 0.15);
|
||||
color: #4ade80;
|
||||
border-color: rgba(74, 222, 128, 0.3);
|
||||
}
|
||||
|
||||
.status.error {
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
color: #ef4444;
|
||||
border-color: rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 2px solid #2d3548;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 12px 24px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #9ca3af;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #4ade80;
|
||||
border-bottom-color: #4ade80;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.history-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
background: #1e2533;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #2d3548;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.history-item.current {
|
||||
border-left: 4px solid #4ade80;
|
||||
}
|
||||
|
||||
.history-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.history-version {
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.history-meta {
|
||||
color: #9ca3af;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.btn-restore {
|
||||
background: #f59e0b;
|
||||
color: #1a1f2e;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn-restore:hover {
|
||||
background: #fbbf24;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-restore:disabled {
|
||||
background: #374151;
|
||||
color: #6b7280;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.button-group {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🚀 Umbrix Update Manager</h1>
|
||||
<p class="subtitle">Панель управления обновлениями приложения</p>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="tabs">
|
||||
<button class="tab active" onclick="switchTab('update')">📝 Обновление</button>
|
||||
<button class="tab" onclick="switchTab('history')">🕐 История версий</button>
|
||||
</div>
|
||||
|
||||
<div id="updateTab" class="tab-content active">
|
||||
<div class="current-version">
|
||||
<h3>📦 Текущая версия</h3>
|
||||
<div class="version-info">
|
||||
<strong>Версия:</strong>
|
||||
<span id="currentVersion">Ошибка загрузки</span>
|
||||
|
||||
<strong>Build:</strong>
|
||||
<span id="currentBuild">-</span>
|
||||
|
||||
<strong>Статус:</strong>
|
||||
<span id="currentStatus">-</span>
|
||||
|
||||
<strong>Опубликовано:</strong>
|
||||
<span id="currentPublished">-</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="updateForm">
|
||||
<div class="form-group">
|
||||
<label for="version">Версия *</label>
|
||||
<input
|
||||
type="text"
|
||||
id="version"
|
||||
name="version"
|
||||
placeholder="2.5.8"
|
||||
required
|
||||
>
|
||||
<div class="hint">Формат: X.Y.Z (например: 2.5.8)</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="buildNumber">Build Number *</label>
|
||||
<input
|
||||
type="text"
|
||||
id="buildNumber"
|
||||
name="buildNumber"
|
||||
placeholder="258"
|
||||
required
|
||||
>
|
||||
<div class="hint">Число, соответствующее версии</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="downloadUrl">URL для скачивания APK *</label>
|
||||
<input
|
||||
type="url"
|
||||
id="downloadUrl"
|
||||
name="downloadUrl"
|
||||
placeholder="https://api.umbrix.net/downloads/umbrix-2.5.8.apk"
|
||||
required
|
||||
>
|
||||
<div class="hint">Полный URL к APK файлу на вашем сервере</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="releaseNotes">Описание обновления</label>
|
||||
<textarea
|
||||
id="releaseNotes"
|
||||
name="releaseNotes"
|
||||
placeholder="🎉 Что нового в этой версии:
|
||||
|
||||
✨ Новые функции:
|
||||
- Улучшена стабильность
|
||||
- Исправлены ошибки
|
||||
|
||||
Что нового в этой версии? (поддерживаются эмодзи)"
|
||||
></textarea>
|
||||
<div class="hint">Что нового в этой версии? (поддерживаются эмодзи)</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="publishedAt">Дата публикации</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="publishedAt"
|
||||
name="publishedAt"
|
||||
>
|
||||
<div class="hint">Оставьте пустым для текущей даты</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="minVersion">Минимальная требуемая версия</label>
|
||||
<input
|
||||
type="text"
|
||||
id="minVersion"
|
||||
name="minVersion"
|
||||
placeholder="2.0.0"
|
||||
>
|
||||
<div class="hint">Версии ниже не смогут обновиться (опционально)</div>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="isPrerelease"
|
||||
name="isPrerelease"
|
||||
>
|
||||
<label for="isPrerelease">Это бета-версия (предварительный релиз)</label>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="btn-secondary" onclick="loadCurrentVersion()">
|
||||
📂 Загрузить текущую
|
||||
</button>
|
||||
<button type="submit" class="btn-primary">
|
||||
💾 Сохранить обновление
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="status" id="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="historyTab" class="tab-content">
|
||||
<div class="current-version">
|
||||
<h3>📚 История всех версий</h3>
|
||||
<p style="color: #9ca3af; margin-top: 10px;">Все сохранённые версии с возможностью отката</p>
|
||||
</div>
|
||||
|
||||
<div class="history-list" id="historyList">
|
||||
<p style="text-align: center; color: #9ca3af; padding: 20px;">Загрузка...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Load current version on page load
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
loadCurrentVersion();
|
||||
loadHistory();
|
||||
});
|
||||
|
||||
function switchTab(tab) {
|
||||
// Update tab buttons
|
||||
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||||
event.target.classList.add('active');
|
||||
|
||||
// Update tab content
|
||||
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||||
document.getElementById(tab + 'Tab').classList.add('active');
|
||||
|
||||
if (tab === 'history') {
|
||||
loadHistory();
|
||||
}
|
||||
}
|
||||
|
||||
async function loadHistory() {
|
||||
const historyList = document.getElementById('historyList');
|
||||
|
||||
try {
|
||||
const response = await fetch('history.php');
|
||||
if (!response.ok) throw new Error('Не удалось загрузить историю');
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.success || data.versions.length === 0) {
|
||||
historyList.innerHTML = '<p style="text-align: center; color: #9ca3af; padding: 20px;">История пуста</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
historyList.innerHTML = data.versions.map(v => `
|
||||
<div class="history-item ${v.is_current ? 'current' : ''}">
|
||||
<div class="history-info">
|
||||
<div class="history-version">
|
||||
${v.is_current ? '🟢 ' : ''}v${v.version} (Build ${v.build_number})
|
||||
${v.is_prerelease ? '<span class="badge beta">Бета</span>' : '<span class="badge stable">Стабильная</span>'}
|
||||
</div>
|
||||
<div class="history-meta">
|
||||
📅 ${new Date(v.timestamp * 1000).toLocaleString('ru-RU')}
|
||||
${v.backup_date ? ` • Бэкап: ${v.backup_date.replace('_', ' ').replace(/-/g, '.')}` : ''}
|
||||
• 💾 ${(v.size / 1024).toFixed(1)} KB
|
||||
</div>
|
||||
${v.release_notes ? `<div style="color: #6b7280; font-size: 0.85em; margin-top: 8px; max-width: 500px; white-space: pre-wrap;">${v.release_notes.substring(0, 100)}${v.release_notes.length > 100 ? '...' : ''}</div>` : ''}
|
||||
</div>
|
||||
<button
|
||||
class="btn-restore"
|
||||
onclick="restoreVersion('${v.filename}')"
|
||||
${v.is_current ? 'disabled' : ''}
|
||||
>
|
||||
${v.is_current ? '✓ Текущая' : '↩️ Откатить'}
|
||||
</button>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading history:', error);
|
||||
historyList.innerHTML = '<p style="text-align: center; color: #ef4444; padding: 20px;">❌ Ошибка загрузки истории</p>';
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreVersion(filename) {
|
||||
if (!confirm(`Откатить на версию из ${filename}?\n\nТекущая версия будет сохранена в бэкап.`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('restore.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ filename })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert(`✅ ${result.message}\n\nВосстановлена версия: v${result.version} (Build ${result.build_number})`);
|
||||
await loadCurrentVersion();
|
||||
await loadHistory();
|
||||
switchTab('update');
|
||||
} else {
|
||||
alert('❌ ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('❌ Ошибка отката: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCurrentVersion() {
|
||||
try {
|
||||
const response = await fetch('../latest.json');
|
||||
if (!response.ok) {
|
||||
throw new Error('Не удалось загрузить текущую версию');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Update current version display
|
||||
document.getElementById('currentVersion').textContent = data.version || '-';
|
||||
document.getElementById('currentBuild').textContent = data.build_number || '-';
|
||||
document.getElementById('currentStatus').innerHTML = data.is_prerelease
|
||||
? '<span class="badge beta">Бета-версия</span>'
|
||||
: '<span class="badge stable">Стабильная</span>';
|
||||
document.getElementById('currentPublished').textContent = data.published_at
|
||||
? new Date(data.published_at).toLocaleString('ru-RU')
|
||||
: '-';
|
||||
} catch (error) {
|
||||
console.error('Error loading current version:', error);
|
||||
document.getElementById('currentVersion').textContent = 'Ошибка загрузки';
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('updateForm').addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const statusDiv = document.getElementById('status');
|
||||
statusDiv.style.display = 'none';
|
||||
|
||||
const formData = new FormData(e.target);
|
||||
const data = {
|
||||
version: formData.get('version'),
|
||||
build_number: formData.get('buildNumber'),
|
||||
download_url: formData.get('downloadUrl'),
|
||||
release_notes: formData.get('releaseNotes'),
|
||||
published_at: formData.get('publishedAt') || new Date().toISOString(),
|
||||
min_required_version: formData.get('minVersion') || null,
|
||||
is_prerelease: formData.get('isPrerelease') === 'on'
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('save.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('success', '✅ ' + result.message);
|
||||
await loadCurrentVersion();
|
||||
e.target.reset();
|
||||
} else {
|
||||
showStatus('error', '❌ ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
showStatus('error', '❌ Ошибка сохранения: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
function showStatus(type, message) {
|
||||
const statusDiv = document.getElementById('status');
|
||||
statusDiv.className = 'status ' + type;
|
||||
statusDiv.textContent = message;
|
||||
statusDiv.style.display = 'block';
|
||||
|
||||
// Auto-hide after 5 seconds
|
||||
setTimeout(() => {
|
||||
statusDiv.style.display = 'none';
|
||||
}, 5000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
85
update-server/admin/restore.php
Normal file
85
update-server/admin/restore.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Umbrix Update Manager - Restore Version
|
||||
* Откат на предыдущую версию из бэкапа
|
||||
*/
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'Method Not Allowed']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
|
||||
if (!isset($data['filename'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Не указан файл для восстановления']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$filename = basename($data['filename']); // Защита от path traversal
|
||||
$backups_dir = __DIR__ . '/../';
|
||||
$backup_file = $backups_dir . $filename;
|
||||
$current_file = $backups_dir . 'latest.json';
|
||||
|
||||
// Проверяем существование файла бэкапа
|
||||
if (!file_exists($backup_file)) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['success' => false, 'message' => 'Файл бэкапа не найден']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Проверяем, что это действительно файл бэкапа
|
||||
if (!preg_match('/^latest\.json\.backup\.\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$/', $filename)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Неверный формат файла']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Создаём бэкап текущей версии перед откатом
|
||||
if (file_exists($current_file)) {
|
||||
$backup_name = 'latest.json.backup.' . date('Y-m-d_H-i-s');
|
||||
copy($current_file, $backups_dir . $backup_name);
|
||||
}
|
||||
|
||||
// Восстанавливаем версию из бэкапа
|
||||
if (copy($backup_file, $current_file)) {
|
||||
// Логируем откат
|
||||
$log_dir = $backups_dir . 'logs';
|
||||
if (!is_dir($log_dir)) {
|
||||
mkdir($log_dir, 0755, true);
|
||||
}
|
||||
|
||||
$log_entry = sprintf(
|
||||
"[%s] RESTORE: %s -> latest.json (IP: %s)\n",
|
||||
date('Y-m-d H:i:s'),
|
||||
$filename,
|
||||
$_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
);
|
||||
file_put_contents($log_dir . '/restore.log', $log_entry, FILE_APPEND);
|
||||
|
||||
// Получаем данные восстановленной версии
|
||||
$restored_data = json_decode(file_get_contents($current_file), true);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Версия успешно восстановлена',
|
||||
'version' => $restored_data['version'] ?? 'unknown',
|
||||
'build_number' => $restored_data['build_number'] ?? 0
|
||||
]);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'message' => 'Ошибка при восстановлении файла']);
|
||||
}
|
||||
140
update-server/admin/save.php
Normal file
140
update-server/admin/save.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* Umbrix Update Manager - Save Script
|
||||
* Сохранение данных обновления в latest.json
|
||||
*/
|
||||
|
||||
// CORS headers
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// Обработка preflight запроса
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Только POST запросы
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'Method Not Allowed']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// === НАСТРОЙКИ ===
|
||||
|
||||
// Путь к файлу latest.json (на уровень выше)
|
||||
$json_file = __DIR__ . '/../latest.json';
|
||||
|
||||
// Пароль для доступа (ИЗМЕНИТЕ ЭТО!)
|
||||
$admin_password = 'umbrix2024';
|
||||
|
||||
// Проверка пароля (опционально, раскомментируйте если нужна защита)
|
||||
// $provided_password = $_SERVER['HTTP_X_ADMIN_PASSWORD'] ?? '';
|
||||
// if ($provided_password !== $admin_password) {
|
||||
// http_response_code(403);
|
||||
// echo json_encode(['success' => false, 'message' => 'Неверный пароль']);
|
||||
// exit();
|
||||
// }
|
||||
|
||||
// === КОНЕЦ НАСТРОЕК ===
|
||||
|
||||
// Получение данных
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
|
||||
if (!$data) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Неверный формат данных']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Валидация обязательных полей
|
||||
$required_fields = ['version', 'build_number', 'download_url', 'published_at'];
|
||||
foreach ($required_fields as $field) {
|
||||
if (!isset($data[$field]) || empty($data[$field])) {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => "Отсутствует обязательное поле: $field"
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Валидация версии (формат X.Y.Z)
|
||||
if (!preg_match('/^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$/', $data['version'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Неверный формат версии. Используйте X.Y.Z (например: 2.5.8)'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Валидация URL
|
||||
if (!filter_var($data['download_url'], FILTER_VALIDATE_URL)) {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Неверный формат URL'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Подготовка данных для сохранения
|
||||
$update_data = [
|
||||
'version' => $data['version'],
|
||||
'build_number' => $data['build_number'],
|
||||
'is_prerelease' => $data['is_prerelease'] ?? false,
|
||||
'download_url' => $data['download_url'],
|
||||
'release_notes' => $data['release_notes'] ?? '',
|
||||
'published_at' => $data['published_at'],
|
||||
'min_required_version' => $data['min_required_version'] ?? '2.0.0',
|
||||
'file_size_bytes' => 0,
|
||||
'file_checksum_sha256' => ''
|
||||
];
|
||||
|
||||
// Попытка получить размер файла (если APK доступен)
|
||||
$apk_path = __DIR__ . '/../downloads/' . basename(parse_url($data['download_url'], PHP_URL_PATH));
|
||||
if (file_exists($apk_path)) {
|
||||
$update_data['file_size_bytes'] = filesize($apk_path);
|
||||
}
|
||||
|
||||
// Создание бэкапа старой версии
|
||||
if (file_exists($json_file)) {
|
||||
$backup_file = __DIR__ . '/../latest.json.backup.' . date('Y-m-d_H-i-s');
|
||||
copy($json_file, $backup_file);
|
||||
}
|
||||
|
||||
// Сохранение в JSON
|
||||
$json_content = json_encode($update_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
if (file_put_contents($json_file, $json_content) === false) {
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Не удалось сохранить файл. Проверьте права доступа.'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Логирование
|
||||
$log_entry = sprintf(
|
||||
"[%s] Обновление сохранено: v%s (build %s) | IP: %s\n",
|
||||
date('Y-m-d H:i:s'),
|
||||
$data['version'],
|
||||
$data['build_number'],
|
||||
$_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
);
|
||||
file_put_contents(__DIR__ . '/../logs/admin.log', $log_entry, FILE_APPEND);
|
||||
|
||||
// Успешный ответ
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Обновление успешно сохранено',
|
||||
'data' => $update_data
|
||||
]);
|
||||
?>
|
||||
193
update-server/api.php
Normal file
193
update-server/api.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
/**
|
||||
* Umbrix Update Server API для Desktop Платформ
|
||||
*
|
||||
* Сервер обновлений для Windows, macOS и Linux версий приложения.
|
||||
* Android использует Google Play Store для обновлений.
|
||||
*
|
||||
* Версия: 1.1
|
||||
*
|
||||
* Использование:
|
||||
* GET /api/latest - получить последнюю версию для Desktop
|
||||
* GET /api/latest?include_prerelease=true - включая бета-версии
|
||||
*/
|
||||
|
||||
// === НАСТРОЙКИ ===
|
||||
|
||||
// Разрешенные домены для CORS (замените на свой домен)
|
||||
$allowed_origins = [
|
||||
'https://umbrix.net',
|
||||
'https://www.umbrix.net',
|
||||
'https://api.umbrix.net'
|
||||
];
|
||||
|
||||
// Путь к файлу с информацией о версии
|
||||
$version_file = __DIR__ . '/latest.json';
|
||||
|
||||
// Включить логирование запросов
|
||||
$enable_logging = true;
|
||||
$log_file = __DIR__ . '/logs/access.log';
|
||||
|
||||
// Ограничение запросов (Rate Limiting)
|
||||
$rate_limit_enabled = true;
|
||||
$max_requests_per_minute = 10;
|
||||
|
||||
// === КОНЕЦ НАСТРОЕК ===
|
||||
|
||||
// Установка заголовков
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('X-Powered-By: Umbrix Update Server');
|
||||
|
||||
// CORS - разрешаем запросы с приложения
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||
if (in_array($origin, $allowed_origins)) {
|
||||
header("Access-Control-Allow-Origin: $origin");
|
||||
} else {
|
||||
header('Access-Control-Allow-Origin: *'); // Разрешаем все для начала
|
||||
}
|
||||
header('Access-Control-Allow-Methods: GET, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
// Обработка preflight запроса
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Только GET запросы
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||
sendError(405, 'Method Not Allowed');
|
||||
}
|
||||
|
||||
// Rate Limiting
|
||||
if ($rate_limit_enabled && !checkRateLimit($max_requests_per_minute)) {
|
||||
sendError(429, 'Too Many Requests', 'Превышен лимит запросов. Попробуйте позже.');
|
||||
}
|
||||
|
||||
// Логирование
|
||||
if ($enable_logging) {
|
||||
logRequest($log_file);
|
||||
}
|
||||
|
||||
// Проверка существования файла с версией
|
||||
if (!file_exists($version_file)) {
|
||||
sendError(500, 'Internal Server Error', 'Файл с версией не найден');
|
||||
}
|
||||
|
||||
// Чтение и парсинг JSON
|
||||
$version_data = file_get_contents($version_file);
|
||||
$version_info = json_decode($version_data, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
sendError(500, 'Internal Server Error', 'Ошибка парсинга JSON: ' . json_last_error_msg());
|
||||
}
|
||||
|
||||
// Проверка обязательных полей
|
||||
$required_fields = ['version', 'build_number', 'download_url', 'published_at'];
|
||||
foreach ($required_fields as $field) {
|
||||
if (!isset($version_info[$field])) {
|
||||
sendError(500, 'Internal Server Error', "Отсутствует обязательное поле: $field");
|
||||
}
|
||||
}
|
||||
|
||||
// Фильтр пре-релизов
|
||||
$include_prerelease = isset($_GET['include_prerelease']) && $_GET['include_prerelease'] === 'true';
|
||||
|
||||
if (!$include_prerelease && isset($version_info['is_prerelease']) && $version_info['is_prerelease'] === true) {
|
||||
// Вернуть пустой ответ, если пре-релиз не запрошен
|
||||
sendError(404, 'Not Found', 'Стабильная версия не найдена');
|
||||
}
|
||||
|
||||
// Добавление дополнительной информации
|
||||
$version_info['server_time'] = date('c');
|
||||
$version_info['api_version'] = '1.0';
|
||||
|
||||
// Успешный ответ
|
||||
http_response_code(200);
|
||||
echo json_encode($version_info, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
exit();
|
||||
|
||||
// === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===
|
||||
|
||||
/**
|
||||
* Отправка ошибки в формате JSON
|
||||
*/
|
||||
function sendError($code, $message, $details = null) {
|
||||
http_response_code($code);
|
||||
$error = [
|
||||
'error' => $message,
|
||||
'code' => $code,
|
||||
'timestamp' => date('c')
|
||||
];
|
||||
if ($details) {
|
||||
$error['details'] = $details;
|
||||
}
|
||||
echo json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка лимита запросов
|
||||
*/
|
||||
function checkRateLimit($max_requests) {
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
$cache_file = sys_get_temp_dir() . '/umbrix_ratelimit_' . md5($ip);
|
||||
|
||||
$current_time = time();
|
||||
$window_start = $current_time - 60; // Окно в 1 минуту
|
||||
|
||||
$requests = [];
|
||||
if (file_exists($cache_file)) {
|
||||
$requests = json_decode(file_get_contents($cache_file), true) ?? [];
|
||||
}
|
||||
|
||||
// Удаляем старые запросы
|
||||
$requests = array_filter($requests, function($timestamp) use ($window_start) {
|
||||
return $timestamp > $window_start;
|
||||
});
|
||||
|
||||
// Проверяем лимит
|
||||
if (count($requests) >= $max_requests) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Добавляем текущий запрос
|
||||
$requests[] = $current_time;
|
||||
file_put_contents($cache_file, json_encode($requests));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Логирование запроса
|
||||
*/
|
||||
function logRequest($log_file) {
|
||||
$log_dir = dirname($log_file);
|
||||
if (!is_dir($log_dir)) {
|
||||
mkdir($log_dir, 0755, true);
|
||||
}
|
||||
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
|
||||
$request_uri = $_SERVER['REQUEST_URI'] ?? 'unknown';
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
|
||||
// Извлекаем версию приложения из User-Agent (если есть)
|
||||
$app_version = 'unknown';
|
||||
if (preg_match('/Umbrix\/([0-9.]+)/', $user_agent, $matches)) {
|
||||
$app_version = $matches[1];
|
||||
}
|
||||
|
||||
$log_entry = sprintf(
|
||||
"[%s] IP: %s | App Version: %s | URI: %s | User-Agent: %s\n",
|
||||
$timestamp,
|
||||
$ip,
|
||||
$app_version,
|
||||
$request_uri,
|
||||
$user_agent
|
||||
);
|
||||
|
||||
file_put_contents($log_file, $log_entry, FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
|
||||
?>
|
||||
237
update-server/downloads/README.md
Normal file
237
update-server/downloads/README.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# 📦 Файлы Обновлений Umbrix
|
||||
|
||||
## 📁 Структура папок
|
||||
|
||||
```
|
||||
downloads/
|
||||
├── android/ # APK файлы для Android
|
||||
│ └── umbrix-2.5.8.apk
|
||||
├── windows/ # EXE/MSI файлы для Windows
|
||||
│ └── umbrix-2.5.8-setup.exe
|
||||
├── ios/ # IPA файлы для iOS (через TestFlight или Enterprise)
|
||||
│ └── umbrix-2.5.8.ipa
|
||||
├── linux/ # AppImage, DEB, RPM для Linux
|
||||
│ ├── umbrix-2.5.8.AppImage
|
||||
│ ├── umbrix-2.5.8.deb
|
||||
│ └── umbrix-2.5.8.rpm
|
||||
└── macos/ # DMG файлы для macOS
|
||||
└── umbrix-2.5.8.dmg
|
||||
```
|
||||
|
||||
## 🚀 Как добавить обновление
|
||||
|
||||
### 1️⃣ Соберите приложение для нужных платформ:
|
||||
|
||||
**Android (APK):**
|
||||
```bash
|
||||
flutter build apk --release
|
||||
# Файл: build/app/outputs/flutter-apk/app-release.apk
|
||||
```
|
||||
|
||||
**Windows (EXE):**
|
||||
```bash
|
||||
flutter build windows --release
|
||||
# Создайте инсталлятор с помощью Inno Setup или MSIX
|
||||
```
|
||||
|
||||
**iOS (IPA):**
|
||||
```bash
|
||||
flutter build ipa --release
|
||||
# Файл: build/ios/ipa/*.ipa
|
||||
# ⚠️ Нужен Apple Developer аккаунт
|
||||
```
|
||||
|
||||
**Linux (AppImage/DEB):**
|
||||
```bash
|
||||
flutter build linux --release
|
||||
# Упакуйте в AppImage или создайте DEB пакет
|
||||
```
|
||||
|
||||
**macOS (DMG):**
|
||||
```bash
|
||||
flutter build macos --release
|
||||
# Создайте DMG образ
|
||||
```
|
||||
|
||||
### 2️⃣ Скопируйте файлы в соответствующие папки:
|
||||
|
||||
```bash
|
||||
# Android
|
||||
cp build/app/outputs/flutter-apk/app-release.apk \
|
||||
update-server/downloads/android/umbrix-2.5.8.apk
|
||||
|
||||
# Windows
|
||||
cp build/windows/Umbrix-Setup.exe \
|
||||
update-server/downloads/windows/umbrix-2.5.8-setup.exe
|
||||
|
||||
# iOS
|
||||
cp build/ios/ipa/Umbrix.ipa \
|
||||
update-server/downloads/ios/umbrix-2.5.8.ipa
|
||||
|
||||
# Linux
|
||||
cp build/linux/Umbrix.AppImage \
|
||||
update-server/downloads/linux/umbrix-2.5.8.AppImage
|
||||
|
||||
# macOS
|
||||
cp build/macos/Umbrix.dmg \
|
||||
update-server/downloads/macos/umbrix-2.5.8.dmg
|
||||
```
|
||||
|
||||
### 3️⃣ Залейте файлы на ваш сервер:
|
||||
|
||||
**Через SCP:**
|
||||
```bash
|
||||
scp -r downloads/ user@your-server.com:/path/to/update-server/
|
||||
```
|
||||
|
||||
**Через FTP/SFTP:**
|
||||
- Используйте FileZilla, WinSCP или другой FTP клиент
|
||||
- Загрузите папку `downloads` на сервер
|
||||
|
||||
### 4️⃣ Обновите latest.json через веб-панель:
|
||||
|
||||
Откройте **http://localhost:8000/admin/** и укажите правильные URL:
|
||||
|
||||
**Android:**
|
||||
```
|
||||
https://your-server.com/update-server/downloads/android/umbrix-2.5.8.apk
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
https://your-server.com/update-server/downloads/windows/umbrix-2.5.8-setup.exe
|
||||
```
|
||||
|
||||
**iOS:**
|
||||
```
|
||||
https://your-server.com/update-server/downloads/ios/umbrix-2.5.8.ipa
|
||||
```
|
||||
|
||||
**Linux:**
|
||||
```
|
||||
https://your-server.com/update-server/downloads/linux/umbrix-2.5.8.AppImage
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```
|
||||
https://your-server.com/update-server/downloads/macos/umbrix-2.5.8.dmg
|
||||
```
|
||||
|
||||
## 📝 Формат latest.json (мультиплатформенный)
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.5.8",
|
||||
"build_number": "258",
|
||||
"published_at": "2026-01-17T08:00:00Z",
|
||||
"is_prerelease": false,
|
||||
"min_required_version": "2.0.0",
|
||||
"release_notes": "🎉 Что нового:\n- Улучшена стабильность\n- Исправлены ошибки",
|
||||
"downloads": {
|
||||
"android": {
|
||||
"url": "https://your-server.com/update-server/downloads/android/umbrix-2.5.8.apk",
|
||||
"size": 52428800,
|
||||
"checksum": "sha256:abc123..."
|
||||
},
|
||||
"windows": {
|
||||
"url": "https://your-server.com/update-server/downloads/windows/umbrix-2.5.8-setup.exe",
|
||||
"size": 73400320,
|
||||
"checksum": "sha256:def456..."
|
||||
},
|
||||
"ios": {
|
||||
"url": "https://your-server.com/update-server/downloads/ios/umbrix-2.5.8.ipa",
|
||||
"size": 67108864,
|
||||
"checksum": "sha256:ghi789..."
|
||||
},
|
||||
"linux": {
|
||||
"url": "https://your-server.com/update-server/downloads/linux/umbrix-2.5.8.AppImage",
|
||||
"size": 94371840,
|
||||
"checksum": "sha256:jkl012..."
|
||||
},
|
||||
"macos": {
|
||||
"url": "https://your-server.com/update-server/downloads/macos/umbrix-2.5.8.dmg",
|
||||
"size": 83886080,
|
||||
"checksum": "sha256:mno345..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔒 Безопасность
|
||||
|
||||
### Настройка HTTPS (обязательно для продакшена):
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name your-server.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/your-server.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/your-server.com/privkey.pem;
|
||||
|
||||
location /update-server/downloads/ {
|
||||
alias /path/to/update-server/downloads/;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /update-server/api.php {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ⚙️ Автоматизация
|
||||
|
||||
Создайте скрипт для автоматической сборки и загрузки:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# build-and-upload.sh
|
||||
|
||||
VERSION="2.5.8"
|
||||
SERVER="user@your-server.com"
|
||||
SERVER_PATH="/path/to/update-server/downloads"
|
||||
|
||||
# Сборка для всех платформ
|
||||
flutter build apk --release
|
||||
flutter build windows --release
|
||||
flutter build linux --release
|
||||
|
||||
# Копирование на сервер
|
||||
scp build/app/outputs/flutter-apk/app-release.apk \
|
||||
$SERVER:$SERVER_PATH/android/umbrix-$VERSION.apk
|
||||
|
||||
scp build/windows/Umbrix-Setup.exe \
|
||||
$SERVER:$SERVER_PATH/windows/umbrix-$VERSION-setup.exe
|
||||
|
||||
scp build/linux/Umbrix.AppImage \
|
||||
$SERVER:$SERVER_PATH/linux/umbrix-$VERSION.AppImage
|
||||
|
||||
echo "✅ Файлы загружены! Обновите latest.json через веб-панель."
|
||||
```
|
||||
|
||||
## 📊 Рекомендации по размеру файлов
|
||||
|
||||
- **Android APK**: 30-70 MB (с Flutter обычно 40-60 MB)
|
||||
- **Windows EXE**: 50-100 MB
|
||||
- **iOS IPA**: 50-80 MB
|
||||
- **Linux AppImage**: 70-120 MB
|
||||
- **macOS DMG**: 60-100 MB
|
||||
|
||||
## 🎯 Пример рабочего процесса
|
||||
|
||||
1. **Разработка** → Изменения в коде
|
||||
2. **Тестирование** → Проверка на эмуляторе/устройстве
|
||||
3. **Сборка** → `flutter build apk/windows/ios/linux/macos`
|
||||
4. **Загрузка** → Копирование файлов в `downloads/`
|
||||
5. **Публикация** → Обновление `latest.json` через панель
|
||||
6. **Уведомление** → Пользователи получают обновление
|
||||
|
||||
## 💡 Советы
|
||||
|
||||
- Всегда используйте HTTPS для скачивания файлов
|
||||
- Храните старые версии (минимум 2-3 последние)
|
||||
- Используйте CDN для больших файлов
|
||||
- Тестируйте обновление перед публикацией
|
||||
- Делайте бэкапы `latest.json` (автоматические)
|
||||
133
update-server/downloads/README_DESKTOP.md
Normal file
133
update-server/downloads/README_DESKTOP.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 📦 Файлы Обновлений для Desktop Платформ
|
||||
|
||||
## 🖥️ Поддерживаемые платформы
|
||||
|
||||
### Windows
|
||||
- **Файлы:** `.exe`, `.msi`
|
||||
- **Путь:** `windows/umbrix-x.x.x-setup.exe`
|
||||
- **Сборка:**
|
||||
```bash
|
||||
flutter build windows --release
|
||||
# Затем создать установщик с помощью Inno Setup или NSIS
|
||||
```
|
||||
|
||||
### macOS
|
||||
- **Файлы:** `.dmg`, `.pkg`
|
||||
- **Путь:** `macos/umbrix-x.x.x.dmg`
|
||||
- **Сборка:**
|
||||
```bash
|
||||
flutter build macos --release
|
||||
# Затем создать DMG с помощью create-dmg
|
||||
```
|
||||
|
||||
### Linux
|
||||
- **Файлы:** `.AppImage`, `.deb`, `.rpm`
|
||||
- **Путь:** `linux/umbrix-x.x.x.AppImage`
|
||||
- **Сборка:**
|
||||
```bash
|
||||
flutter build linux --release
|
||||
# Затем упаковать в AppImage/deb/rpm
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Структура директорий
|
||||
|
||||
```
|
||||
downloads/
|
||||
├── windows/
|
||||
│ └── umbrix-1.7.3-setup.exe
|
||||
├── macos/
|
||||
│ └── umbrix-1.7.3.dmg
|
||||
├── linux/
|
||||
│ ├── umbrix-1.7.3.AppImage
|
||||
│ ├── umbrix-1.7.3.deb
|
||||
│ └── umbrix-1.7.3.rpm
|
||||
└── android/ (только для тестирования debug сборок)
|
||||
└── umbrix-1.7.3-debug.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Как добавить обновление
|
||||
|
||||
### 1. Соберите приложение
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
flutter build windows --release
|
||||
|
||||
# macOS
|
||||
flutter build macos --release
|
||||
|
||||
# Linux
|
||||
flutter build linux --release
|
||||
```
|
||||
|
||||
### 2. Создайте установщик
|
||||
|
||||
**Windows (Inno Setup):**
|
||||
```bash
|
||||
iscc installer-script.iss
|
||||
```
|
||||
|
||||
**macOS (create-dmg):**
|
||||
```bash
|
||||
create-dmg umbrix.app
|
||||
```
|
||||
|
||||
**Linux (AppImage):**
|
||||
```bash
|
||||
appimage-builder --recipe AppImageBuilder.yml
|
||||
```
|
||||
|
||||
### 3. Скопируйте файл
|
||||
|
||||
```bash
|
||||
# Пример для Windows
|
||||
cp output/umbrix-1.7.3-setup.exe update-server/downloads/windows/
|
||||
|
||||
# Для Docker
|
||||
docker cp umbrix-1.7.3-setup.exe umbrix-update-server:/var/www/downloads/windows/
|
||||
```
|
||||
|
||||
### 4. Обновите latest.json через Web-панель
|
||||
|
||||
1. Откройте http://your-server/admin/
|
||||
2. Введите версию: `1.7.3`
|
||||
3. Build number: `173`
|
||||
4. URL: `http://your-server/downloads/windows/umbrix-1.7.3-setup.exe`
|
||||
5. Описание изменений
|
||||
6. Сохраните
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Проверка
|
||||
|
||||
После загрузки проверьте доступность:
|
||||
|
||||
```bash
|
||||
# Проверка API
|
||||
curl http://your-server/api.php
|
||||
|
||||
# Проверка файла
|
||||
curl -I http://your-server/downloads/windows/umbrix-1.7.3-setup.exe
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Примечания
|
||||
|
||||
### Android
|
||||
- **Production:** Обновления через Google Play Store
|
||||
- **Development:** Можно использовать папку `android/` для debug APK
|
||||
|
||||
### Безопасность
|
||||
- Используйте HTTPS для production
|
||||
- Подписывайте установщики цифровой подписью
|
||||
- Добавьте checksums в latest.json для верификации
|
||||
|
||||
### Оптимизация
|
||||
- Используйте CDN для больших файлов
|
||||
- Храните только последние 2-3 версии
|
||||
- Настройте сжатие на веб-сервере
|
||||
1
update-server/downloads/android/.gitkeep
Normal file
1
update-server/downloads/android/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# Здесь размещайте файлы обновлений для android
|
||||
BIN
update-server/downloads/android/umbrix-1.7.1.apk
Normal file
BIN
update-server/downloads/android/umbrix-1.7.1.apk
Normal file
Binary file not shown.
1
update-server/downloads/ios/.gitkeep
Normal file
1
update-server/downloads/ios/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# Здесь размещайте файлы обновлений для ios
|
||||
1
update-server/downloads/linux/.gitkeep
Normal file
1
update-server/downloads/linux/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# Здесь размещайте файлы обновлений для linux
|
||||
1
update-server/downloads/macos/.gitkeep
Normal file
1
update-server/downloads/macos/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# Здесь размещайте файлы обновлений для macos
|
||||
1
update-server/downloads/windows/.gitkeep
Normal file
1
update-server/downloads/windows/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# Здесь размещайте файлы обновлений для windows
|
||||
11
update-server/latest.json
Normal file
11
update-server/latest.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "1.7.3",
|
||||
"build_number": "173",
|
||||
"is_prerelease": false,
|
||||
"download_url": "http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk",
|
||||
"release_notes": "Исправлена установка APK при обновлении",
|
||||
"published_at": "2026-01-17T05:49:07.696Z",
|
||||
"min_required_version": "2.0.0",
|
||||
"file_size_bytes": 0,
|
||||
"file_checksum_sha256": ""
|
||||
}
|
||||
12
update-server/latest.json.backup.2026-01-17_05-47-36
Normal file
12
update-server/latest.json.backup.2026-01-17_05-47-36
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": "1.7.1",
|
||||
"build_number": "171",
|
||||
"is_prerelease": false,
|
||||
"download_url": "http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk",
|
||||
"release_notes": "🎉 Что нового в версии 1.7.1:\n\n✨ Новые возможности:\n- Система автоматических обновлений\n- История версий с откатом\n- Улучшена стабильность\n\n🐛 Исправлены ошибки:\n- Исправлен краш при обновлении\n- Улучшена работа update server\n\n📱 Улучшения:\n- Новая веб-панель управления\n- Поддержка всех платформ Flutter",
|
||||
"published_at": "2026-01-17T13:00:00Z",
|
||||
"min_required_version": "1.0.0",
|
||||
"force_update": false,
|
||||
"file_size_bytes": 48000000,
|
||||
"file_checksum_sha256": ""
|
||||
}
|
||||
11
update-server/latest.json.backup.2026-01-17_05-49-07
Normal file
11
update-server/latest.json.backup.2026-01-17_05-49-07
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "1.7.1",
|
||||
"build_number": "171",
|
||||
"is_prerelease": false,
|
||||
"download_url": "http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk",
|
||||
"release_notes": "",
|
||||
"published_at": "2026-01-17T05:47:36.710Z",
|
||||
"min_required_version": "2.0.0",
|
||||
"file_size_bytes": 0,
|
||||
"file_checksum_sha256": ""
|
||||
}
|
||||
45
update-server/start_admin_panel.sh
Executable file
45
update-server/start_admin_panel.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🎨 Быстрый запуск веб-панели управления обновлениями
|
||||
|
||||
echo "╔════════════════════════════════════════════════╗"
|
||||
echo "║ 🎨 Umbrix Update Manager - Веб-панель ║"
|
||||
echo "╚════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Проверка PHP
|
||||
if ! command -v php &> /dev/null; then
|
||||
echo "❌ PHP не установлен. Установите: sudo apt install php"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ PHP $(php -v | head -1 | cut -d' ' -f2) найден"
|
||||
|
||||
# Переход в папку update-server
|
||||
cd "$(dirname "$0")" || exit
|
||||
|
||||
# Запуск сервера
|
||||
echo ""
|
||||
echo "🚀 Запускаю веб-сервер..."
|
||||
echo ""
|
||||
echo "┌────────────────────────────────────────────────┐"
|
||||
echo "│ Веб-панель доступна по адресу: │"
|
||||
echo "│ │"
|
||||
echo "│ 👉 http://localhost:8000/admin/ │"
|
||||
echo "│ │"
|
||||
echo "│ API сервер: │"
|
||||
echo "│ 👉 http://localhost:8000/api.php │"
|
||||
echo "└────────────────────────────────────────────────┘"
|
||||
echo ""
|
||||
echo "💡 Откройте в браузере и управляйте обновлениями!"
|
||||
echo ""
|
||||
echo "🛑 Для остановки нажмите Ctrl+C"
|
||||
echo ""
|
||||
echo "══════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# Создать папку logs если нет
|
||||
mkdir -p logs
|
||||
|
||||
# Запуск PHP сервера
|
||||
php -S localhost:8000
|
||||
126
update-server/start_test_server.sh
Executable file
126
update-server/start_test_server.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🚀 Скрипт для быстрого тестирования системы обновлений
|
||||
|
||||
echo "╔════════════════════════════════════════════════╗"
|
||||
echo "║ 🚀 Тестирование Системы Обновлений Umbrix ║"
|
||||
echo "╚════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Проверка PHP
|
||||
if ! command -v php &> /dev/null; then
|
||||
echo "❌ PHP не установлен. Установите: sudo apt install php"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ PHP $(php -v | head -1 | cut -d' ' -f2) найден"
|
||||
|
||||
# Переход в папку сервера
|
||||
cd "$(dirname "$0")" || exit
|
||||
|
||||
# Проверка файлов
|
||||
echo "🔍 Проверка необходимых файлов..."
|
||||
files=("api.php" "latest.json" ".htaccess")
|
||||
for file in "${files[@]}"; do
|
||||
if [ -f "$file" ]; then
|
||||
echo " ✅ $file"
|
||||
else
|
||||
echo " ❌ $file - НЕ НАЙДЕН!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Создание папки downloads если нет
|
||||
if [ ! -d "downloads" ]; then
|
||||
mkdir -p downloads
|
||||
echo "📁 Создана папка downloads/"
|
||||
fi
|
||||
|
||||
# Создание папки logs если нет
|
||||
if [ ! -d "logs" ]; then
|
||||
mkdir -p logs
|
||||
echo "📁 Создана папка logs/"
|
||||
fi
|
||||
|
||||
# Проверка порта
|
||||
PORT=8000
|
||||
if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1 ; then
|
||||
echo "⚠️ Порт $PORT уже занят. Останавливаю..."
|
||||
kill $(lsof -t -i:$PORT) 2>/dev/null
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Запуск PHP сервера
|
||||
echo ""
|
||||
echo "🚀 Запускаю PHP сервер на http://localhost:$PORT"
|
||||
php -S localhost:$PORT > logs/server.log 2>&1 &
|
||||
PHP_PID=$!
|
||||
|
||||
# Ждем запуска
|
||||
sleep 2
|
||||
|
||||
# Проверка что сервер запустился
|
||||
if ! kill -0 $PHP_PID 2>/dev/null; then
|
||||
echo "❌ Не удалось запустить сервер. Смотрите: logs/server.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Сервер запущен (PID: $PHP_PID)"
|
||||
|
||||
# Проверка API
|
||||
echo ""
|
||||
echo "🔍 Проверка API endpoint..."
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/api.php)
|
||||
|
||||
if [ "$RESPONSE" -eq 200 ]; then
|
||||
echo "✅ API работает (HTTP $RESPONSE)"
|
||||
echo ""
|
||||
echo "📄 Ответ API:"
|
||||
echo "─────────────────────────────────────────────────"
|
||||
curl -s http://localhost:$PORT/api.php | python3 -m json.tool 2>/dev/null || curl -s http://localhost:$PORT/api.php
|
||||
echo "─────────────────────────────────────────────────"
|
||||
else
|
||||
echo "❌ API не отвечает (HTTP $RESPONSE)"
|
||||
echo "Смотрите логи: tail -f logs/server.log"
|
||||
fi
|
||||
|
||||
# Информация для пользователя
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════════╗"
|
||||
echo "║ 📱 Инструкции ║"
|
||||
echo "╚════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "🔗 API доступен по адресу:"
|
||||
echo " http://localhost:$PORT/api.php"
|
||||
echo ""
|
||||
echo "📱 Для Android эмулятора используйте:"
|
||||
echo " http://10.0.2.2:$PORT/api.php"
|
||||
echo ""
|
||||
echo "🔧 В constants.dart укажите:"
|
||||
echo " static const customUpdateServerUrl = \"http://10.0.2.2:$PORT/api.php\";"
|
||||
echo " static const useCustomUpdateServer = true;"
|
||||
echo ""
|
||||
echo "📋 Далее:"
|
||||
echo " 1. Откройте приложение в эмуляторе"
|
||||
echo " 2. Зайдите в Настройки → О программе"
|
||||
echo " 3. Нажмите 'Проверить обновления'"
|
||||
echo ""
|
||||
echo "📊 Логи сервера:"
|
||||
echo " tail -f logs/server.log"
|
||||
echo ""
|
||||
echo "🛑 Остановить сервер:"
|
||||
echo " kill $PHP_PID"
|
||||
echo ""
|
||||
echo "═════════════════════════════════════════════════"
|
||||
|
||||
# Сохранить PID
|
||||
echo $PHP_PID > logs/server.pid
|
||||
echo ""
|
||||
echo "✅ Сервер работает. Нажмите Ctrl+C для остановки"
|
||||
echo ""
|
||||
|
||||
# Ждем сигнала остановки
|
||||
trap "echo ''; echo '🛑 Останавливаю сервер...'; kill $PHP_PID 2>/dev/null; rm -f logs/server.pid; echo '✅ Сервер остановлен'; exit 0" INT TERM
|
||||
|
||||
# Следим за логами
|
||||
tail -f logs/server.log
|
||||
Reference in New Issue
Block a user