- 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
375 lines
10 KiB
Markdown
375 lines
10 KiB
Markdown
# 🚀 Настройка собственного сервера обновлений для Umbrix
|
||
|
||
Это руководство поможет вам настроить систему обновлений для приватного распространения APK/IPA файлов до публикации в магазинах.
|
||
|
||
## 📋 Варианты реализации
|
||
|
||
### Вариант 1: Простой JSON файл на хостинге (самое простое)
|
||
|
||
Создайте файл `latest.json` на любом веб-сервере:
|
||
|
||
```json
|
||
{
|
||
"version": "2.5.8",
|
||
"build_number": "258",
|
||
"is_prerelease": false,
|
||
"download_url": "https://your-server.com/downloads/umbrix-2.5.8.apk",
|
||
"release_notes": "Что нового:\n- Исправлены ошибки подключения\n- Улучшена стабильность\n- Новый дизайн главной страницы",
|
||
"published_at": "2026-01-16T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
**Где разместить:**
|
||
- ✅ Netlify / Vercel (бесплатно)
|
||
- ✅ GitHub Pages (можно сделать приватный репозиторий)
|
||
- ✅ Ваш VPS сервер
|
||
- ✅ Firebase Hosting
|
||
|
||
**В constants.dart установите:**
|
||
```dart
|
||
static const customUpdateServerUrl = "https://your-site.netlify.app/latest.json";
|
||
static const useCustomUpdateServer = true;
|
||
```
|
||
|
||
---
|
||
|
||
### Вариант 2: Node.js API сервер (рекомендуемый)
|
||
|
||
#### Установка
|
||
|
||
```bash
|
||
mkdir umbrix-update-server
|
||
cd umbrix-update-server
|
||
npm init -y
|
||
npm install express cors
|
||
```
|
||
|
||
#### server.js
|
||
|
||
```javascript
|
||
const express = require('express');
|
||
const cors = require('cors');
|
||
const app = express();
|
||
|
||
app.use(cors());
|
||
app.use(express.json());
|
||
|
||
// Конфигурация версий
|
||
const releases = {
|
||
stable: {
|
||
version: "2.5.8",
|
||
build_number: "258",
|
||
is_prerelease: false,
|
||
download_url: "https://your-storage.com/umbrix-2.5.8.apk",
|
||
release_notes: "Стабильная версия с исправлениями",
|
||
published_at: new Date().toISOString()
|
||
},
|
||
beta: {
|
||
version: "2.6.0-beta.1",
|
||
build_number: "260",
|
||
is_prerelease: true,
|
||
download_url: "https://your-storage.com/umbrix-2.6.0-beta.1.apk",
|
||
release_notes: "Бета-версия с новыми функциями",
|
||
published_at: new Date().toISOString()
|
||
}
|
||
};
|
||
|
||
// Endpoint для получения последней версии
|
||
app.get('/api/updates/latest', (req, res) => {
|
||
const includePrerelease = req.query.include_prerelease === 'true';
|
||
const release = includePrerelease ? releases.beta : releases.stable;
|
||
|
||
console.log(`Update check: prerelease=${includePrerelease}`);
|
||
res.json(release);
|
||
});
|
||
|
||
// Аналитика (опционально)
|
||
app.post('/api/updates/analytics', (req, res) => {
|
||
const { current_version, device_info } = req.body;
|
||
console.log('Update analytics:', { current_version, device_info });
|
||
res.json({ success: true });
|
||
});
|
||
|
||
const PORT = process.env.PORT || 3000;
|
||
app.listen(PORT, () => {
|
||
console.log(`Update server running on port ${PORT}`);
|
||
});
|
||
```
|
||
|
||
#### Запуск
|
||
|
||
```bash
|
||
node server.js
|
||
```
|
||
|
||
#### Deploy на Render.com (бесплатно)
|
||
|
||
1. Создайте аккаунт на [Render.com](https://render.com)
|
||
2. Подключите GitHub репозиторий
|
||
3. Создайте Web Service
|
||
4. Render автоматически задеплоит ваш сервер
|
||
|
||
**В constants.dart установите:**
|
||
```dart
|
||
static const customUpdateServerUrl = "https://your-app.onrender.com/api/updates/latest";
|
||
static const useCustomUpdateServer = true;
|
||
```
|
||
|
||
---
|
||
|
||
### Вариант 3: Firebase Cloud Functions (продвинутый)
|
||
|
||
#### functions/index.js
|
||
|
||
```javascript
|
||
const functions = require('firebase-functions');
|
||
const admin = require('firebase-admin');
|
||
|
||
admin.initializeApp();
|
||
|
||
exports.getLatestVersion = functions.https.onRequest(async (req, res) => {
|
||
// CORS
|
||
res.set('Access-Control-Allow-Origin', '*');
|
||
|
||
try {
|
||
const db = admin.firestore();
|
||
const doc = await db.collection('app_updates').doc('latest').get();
|
||
|
||
if (!doc.exists) {
|
||
return res.status(404).json({ error: 'Version not found' });
|
||
}
|
||
|
||
res.json(doc.data());
|
||
} catch (error) {
|
||
console.error('Error:', error);
|
||
res.status(500).json({ error: 'Internal server error' });
|
||
}
|
||
});
|
||
```
|
||
|
||
**Плюсы Firebase:**
|
||
- ✅ Автоматическое масштабирование
|
||
- ✅ Бесплатный SSL
|
||
- ✅ Встроенная аналитика
|
||
- ✅ База данных Firestore для хранения версий
|
||
|
||
---
|
||
|
||
## 📦 Где хранить APK файлы
|
||
|
||
### 1. Firebase Storage (рекомендуемый)
|
||
|
||
```bash
|
||
# Установка Firebase CLI
|
||
npm install -g firebase-tools
|
||
firebase login
|
||
|
||
# Загрузка APK
|
||
firebase storage:upload umbrix-2.5.8.apk /releases/umbrix-2.5.8.apk
|
||
```
|
||
|
||
**Получение публичной ссылки:**
|
||
```javascript
|
||
// Генерация signed URL (действителен 7 дней)
|
||
const { getStorage } = require('firebase-admin/storage');
|
||
const bucket = getStorage().bucket();
|
||
const file = bucket.file('releases/umbrix-2.5.8.apk');
|
||
const [url] = await file.getSignedUrl({
|
||
action: 'read',
|
||
expires: Date.now() + 7 * 24 * 60 * 60 * 1000
|
||
});
|
||
```
|
||
|
||
### 2. AWS S3 / DigitalOcean Spaces
|
||
|
||
```bash
|
||
# Пример с AWS CLI
|
||
aws s3 cp umbrix-2.5.8.apk s3://your-bucket/releases/umbrix-2.5.8.apk --acl public-read
|
||
```
|
||
|
||
### 3. Собственный сервер
|
||
|
||
```bash
|
||
# Nginx конфигурация
|
||
location /downloads/ {
|
||
alias /var/www/downloads/;
|
||
autoindex off;
|
||
|
||
# Защита паролем (опционально)
|
||
auth_basic "Restricted";
|
||
auth_basic_user_file /etc/nginx/.htpasswd;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 Безопасность
|
||
|
||
### 1. Базовая аутентификация (Basic Auth)
|
||
|
||
```dart
|
||
// В DioHttpClient добавьте заголовки
|
||
final response = await httpClient.get<Map<String, dynamic>>(
|
||
url,
|
||
options: Options(
|
||
headers: {
|
||
'Authorization': 'Basic ${base64Encode(utf8.encode('username:password'))}',
|
||
},
|
||
),
|
||
);
|
||
```
|
||
|
||
### 2. API ключ
|
||
|
||
```dart
|
||
// В constants.dart
|
||
static const updateServerApiKey = "your-secret-api-key";
|
||
|
||
// В запросе
|
||
headers: {
|
||
'X-API-Key': Constants.updateServerApiKey,
|
||
}
|
||
```
|
||
|
||
### 3. JWT токен (самый безопасный)
|
||
|
||
```javascript
|
||
// На сервере
|
||
const jwt = require('jsonwebtoken');
|
||
|
||
function verifyToken(req, res, next) {
|
||
const token = req.headers['authorization']?.split(' ')[1];
|
||
if (!token) return res.status(403).json({ error: 'No token' });
|
||
|
||
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
|
||
if (err) return res.status(401).json({ error: 'Invalid token' });
|
||
req.userId = decoded.userId;
|
||
next();
|
||
});
|
||
}
|
||
|
||
app.get('/api/updates/latest', verifyToken, (req, res) => {
|
||
// ...
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Пошаговая инструкция (быстрый старт)
|
||
|
||
### Шаг 1: Создайте JSON файл
|
||
|
||
Создайте файл `latest.json`:
|
||
```json
|
||
{
|
||
"version": "2.5.8",
|
||
"build_number": "258",
|
||
"is_prerelease": false,
|
||
"download_url": "https://github.com/your-org/your-repo/releases/download/v2.5.8/umbrix-2.5.8.apk",
|
||
"release_notes": "Первая версия",
|
||
"published_at": "2026-01-16T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
### Шаг 2: Разместите на GitHub Pages
|
||
|
||
```bash
|
||
# В приватном репозитории создайте ветку gh-pages
|
||
git checkout -b gh-pages
|
||
git add latest.json
|
||
git commit -m "Add update info"
|
||
git push origin gh-pages
|
||
|
||
# В Settings → Pages включите GitHub Pages для ветки gh-pages
|
||
```
|
||
|
||
### Шаг 3: Обновите константы в приложении
|
||
|
||
В файле `lib/core/model/constants.dart`:
|
||
```dart
|
||
static const customUpdateServerUrl = "https://your-username.github.io/your-repo/latest.json";
|
||
static const useCustomUpdateServer = true;
|
||
```
|
||
|
||
### Шаг 4: Соберите и протестируйте
|
||
|
||
```bash
|
||
flutter build apk --release
|
||
# Установите на устройство и проверьте обновления в разделе "О программе"
|
||
```
|
||
|
||
---
|
||
|
||
## 📱 Автоматизация через GitHub Actions
|
||
|
||
Создайте `.github/workflows/release.yml`:
|
||
|
||
```yaml
|
||
name: Build and Deploy APK
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- 'v*'
|
||
|
||
jobs:
|
||
build:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
|
||
- name: Setup Flutter
|
||
uses: subosito/flutter-action@v2
|
||
|
||
- name: Build APK
|
||
run: flutter build apk --release
|
||
|
||
- name: Upload to storage
|
||
run: |
|
||
# Загрузка APK на ваш сервер
|
||
curl -X POST -F "file=@build/app/outputs/flutter-apk/app-release.apk" \
|
||
https://your-server.com/api/upload
|
||
|
||
- name: Update version info
|
||
run: |
|
||
# Обновление latest.json
|
||
echo '{
|
||
"version": "${{ github.ref_name }}",
|
||
"build_number": "${{ github.run_number }}",
|
||
"download_url": "https://your-server.com/downloads/${{ github.ref_name }}.apk",
|
||
"published_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
|
||
}' > latest.json
|
||
|
||
# Загрузка на сервер
|
||
curl -X PUT -d @latest.json https://your-server.com/api/latest
|
||
```
|
||
|
||
---
|
||
|
||
## ❓ FAQ
|
||
|
||
**Q: Как переключиться обратно на GitHub?**
|
||
A: В `constants.dart` установите `useCustomUpdateServer = false`
|
||
|
||
**Q: Можно ли использовать оба варианта?**
|
||
A: Да, можно добавить fallback логику в `app_update_repository.dart`
|
||
|
||
**Q: Как защитить от несанкционированного доступа?**
|
||
A: Используйте API ключи, JWT токены или базовую аутентификацию
|
||
|
||
**Q: Нужен ли HTTPS?**
|
||
A: Да, обязательно! Иначе Android не разрешит загрузку
|
||
|
||
---
|
||
|
||
## 🎉 Готово!
|
||
|
||
Теперь у вас есть полностью функциональная система обновлений для приватного распространения APK файлов.
|
||
|
||
**Следующие шаги:**
|
||
1. ✅ Выберите вариант размещения
|
||
2. ✅ Обновите `Constants.customUpdateServerUrl`
|
||
3. ✅ Загрузите APK на сервер
|
||
4. ✅ Протестируйте обновление
|
||
5. ✅ Настройте автоматизацию через CI/CD
|