diff --git a/.gitignore b/.gitignore index 59e96fc..6989102 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,11 @@ Navis-pending.exe *.bak Navis.exe.bak +# MSIX staging / local packages +packaging/msix/_staging/ +packaging/msix/Assets/ +*.msix + # Android android/.gradle/ android/local.properties diff --git a/README.md b/README.md index 929408c..e380951 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,19 @@ build.bat go build -ldflags="-H windowsgui -s -w" -o Navis.exe ./cmd/vpnapp ``` +### Microsoft Store (MSIX) + +Navis — Win32 + WebView2 VPN/прокси-клиент (системный прокси, локальные cores). **PWA в Store не подходит** как замена: без Desktop Bridge нельзя дать те же возможности. Для Store используется **MSIX full-trust** поверх того же `Navis.exe`. + +```powershell +build.bat +.\scripts\pack-msix.ps1 +``` + +Нужен Windows SDK (`MakeAppx.exe`). Перед публикацией подставьте Identity Name / Publisher из Partner Center (см. `packaging/msix/AppxManifest.xml` и [packaging/msix/README.md](packaging/msix/README.md)). + +Сборка из Store **не** самообновляется через in-app updater (детект MSIX package identity) — только обновления Microsoft Store. + ## Сборка macOS (кросс с Windows / Linux) ```bat @@ -257,6 +270,10 @@ https://evilfox.win/ Некоторые AV (Bkav, Microsoft Wacapew/Wacatac, Ikarus Trojan.WinGo.Agent, Google, Trapmine) часто помечают **любые** неподписанные Go-бинарники с сетью и сменой системного прокси. +В 2.9.0: +- светлая / тёмная тема с переключателем (preference в localStorage, по умолчанию — системная); +- подготовка к Microsoft Store: MSIX-манифест, `scripts/pack-msix.ps1`, отключение in-app updater в MSIX-сборке. + В 2.8.0: - релизы разложены по папкам `windows/` · `macos/` · `android/`; - обновления строго по платформе (Windows не получит Mac-сборку и наоборот). diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 7c8808e..87209ad 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -13,8 +13,8 @@ android { minSdk = 26 targetSdk = 35 // versionCode = major*1_000_000 + minor*10_000 + patch*100 + build - versionCode = 2_080_001 - versionName = "2.8.0+1" + versionCode = 2_090_001 + versionName = "2.9.0+1" vectorDrawables.useSupportLibrary = true ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") diff --git a/assets/app.manifest b/assets/app.manifest index 84cfd86..2d5ac80 100644 --- a/assets/app.manifest +++ b/assets/app.manifest @@ -1,7 +1,7 @@ diff --git a/build-macos.bat b/build-macos.bat index 0b2d5f1..9c77306 100644 --- a/build-macos.bat +++ b/build-macos.bat @@ -34,11 +34,11 @@ if errorlevel 1 exit /b 1 go build -o "tools\packmac\packmac.exe" .\tools\packmac if errorlevel 1 exit /b 1 -tools\packmac\packmac.exe -bin "dist\navis-release\macos\arm64\Navis" -out "dist\navis-release\macos\arm64" -version 2.8.0 -build 2.8.0.1 -arch arm64 +tools\packmac\packmac.exe -bin "dist\navis-release\macos\arm64\Navis" -out "dist\navis-release\macos\arm64" -version 2.9.0 -build 2.9.0.1 -arch arm64 if errorlevel 1 exit /b 1 -tools\packmac\packmac.exe -bin "dist\navis-release\macos\amd64\Navis" -out "dist\navis-release\macos\amd64" -version 2.8.0 -build 2.8.0.1 -arch amd64 +tools\packmac\packmac.exe -bin "dist\navis-release\macos\amd64\Navis" -out "dist\navis-release\macos\amd64" -version 2.9.0 -build 2.9.0.1 -arch amd64 if errorlevel 1 exit /b 1 -tools\packmac\packmac.exe -bin "dist\navis-release\macos\universal\Navis" -out "dist\navis-release\macos\universal" -version 2.8.0 -build 2.8.0.1 -arch universal +tools\packmac\packmac.exe -bin "dist\navis-release\macos\universal\Navis" -out "dist\navis-release\macos\universal" -version 2.9.0 -build 2.9.0.1 -arch universal if errorlevel 1 exit /b 1 echo Built Mac GUI + CLI: diff --git a/cmd/vpnapp/main_windows.go b/cmd/vpnapp/main_windows.go index 6c9a933..9940536 100644 --- a/cmd/vpnapp/main_windows.go +++ b/cmd/vpnapp/main_windows.go @@ -56,6 +56,7 @@ type uiState struct { Pings []netcheck.Result `json:"pings"` Subscription string `json:"subscription_url"` Hy2 core.Hy2Options `json:"hy2"` + StorePackaged bool `json:"store_packaged,omitempty"` } func main() { @@ -209,6 +210,7 @@ func (a *app) getState() (uiState, error) { Pings: append([]netcheck.Result(nil), a.pings...), Subscription: cfg.SubscriptionURL, Hy2: a.mgr.ActiveHy2Options(), + StorePackaged: update.IsStorePackaged(), } if out.Protocol == "" { if p, err := cfg.ActiveProfile(); err == nil { @@ -428,6 +430,9 @@ func (a *app) checkUpdate() (update.Status, error) { } func (a *app) applyUpdate() (string, error) { + if update.IsStorePackaged() { + return "", fmt.Errorf("обновления устанавливаются через Microsoft Store") + } // Explicit user action only — never called from autoCheckUpdate. st, err := a.checkUpdate() if err != nil { @@ -455,6 +460,17 @@ func (a *app) autoCheckUpdate() { // Only refresh update status for the UI banner — never auto-install. // (Previously auto-apply caused an infinite update loop when the feed version // stayed ahead of the shipped CurrentVersion in the downloaded binary.) + if update.IsStorePackaged() { + a.mu.Lock() + a.updateStatus = update.Status{ + Current: update.DisplayVersion(), + ManifestURL: update.DefaultManifestURL, + StoreManaged: true, + Notes: "Обновления через Microsoft Store", + } + a.mu.Unlock() + return + } time.Sleep(3 * time.Second) _, _ = a.checkUpdate() } diff --git a/internal/apphost/app.go b/internal/apphost/app.go index f33dcb9..a48ed6a 100644 --- a/internal/apphost/app.go +++ b/internal/apphost/app.go @@ -54,6 +54,7 @@ type UIState struct { Pings []netcheck.Result `json:"pings"` Subscription string `json:"subscription_url"` Hy2 core.Hy2Options `json:"hy2"` + StorePackaged bool `json:"store_packaged,omitempty"` } type PingBestResult struct { @@ -130,6 +131,7 @@ func (a *App) GetState() (UIState, error) { Pings: append([]netcheck.Result(nil), a.Pings...), Subscription: cfg.SubscriptionURL, Hy2: a.Mgr.ActiveHy2Options(), + StorePackaged: update.IsStorePackaged(), } if out.Protocol == "" { if p, err := cfg.ActiveProfile(); err == nil { @@ -332,6 +334,9 @@ func (a *App) CheckUpdate() (update.Status, error) { } func (a *App) ApplyUpdate() (string, error) { + if update.IsStorePackaged() { + return "", fmt.Errorf("обновления устанавливаются через Microsoft Store") + } // Explicit user action only — never called from AutoCheckUpdate. st, err := a.CheckUpdate() if err != nil { @@ -361,6 +366,17 @@ func (a *App) ApplyUpdate() (string, error) { func (a *App) AutoCheckUpdate() { // Only check and populate status for the banner — never auto-apply. // Auto-apply previously caused endless download→relaunch loops on Mac/Windows. + if update.IsStorePackaged() { + a.mu.Lock() + a.UpdateStatus = update.Status{ + Current: update.DisplayVersion(), + ManifestURL: update.DefaultManifestURL, + StoreManaged: true, + Notes: "Обновления через Microsoft Store", + } + a.mu.Unlock() + return + } time.Sleep(3 * time.Second) _, _ = a.CheckUpdate() } diff --git a/internal/appui/index.html b/internal/appui/index.html index bbf8723..c0534a5 100644 --- a/internal/appui/index.html +++ b/internal/appui/index.html @@ -4,12 +4,28 @@ Navis +