From 033579249dcea2215425f8fb2b45bed4c8237f15 Mon Sep 17 00:00:00 2001
From: hiddify <114227601+hiddify-com@users.noreply.github.com>
Date: Sat, 25 Oct 2025 21:00:23 +0200
Subject: [PATCH] update release files
---
.github/ISSUE_TEMPLATE/bug_report.yaml | 2 +-
.github/release_message.md | 26 +-
.github/workflows/build.yml | 3 +-
CONTRIBUTING.md | 8 +-
README.md | 42 +-
README_br.md | 42 +-
README_cn.md | 40 +-
README_fa.md | 42 +-
README_ja.md | 42 +-
README_ru.md | 40 +-
.../com/hiddify/hiddify/bg/BoxService.kt | 16 +-
appcast.xml | 13 +-
ios/Podfile.lock | 36 +-
.../xcshareddata/xcschemes/Runner.xcscheme | 3 +
lib/bootstrap.dart | 120 ++----
lib/core/analytics/analytics_controller.dart | 34 +-
lib/core/model/constants.dart | 36 +-
lib/core/utils/preferences_utils.dart | 60 +--
lib/hiddifycore/hiddify_core_service.dart | 398 ++++++++----------
linux/packaging/app.hiddify.com.appdata.xml | 90 ++++
linux/packaging/appimage/make_config.yaml | 2 +
linux/packaging/deb/make_config.yaml | 2 +
linux/packaging/rpm/make_config.yaml | 4 +-
macos/packaging/pkg/make_config.yaml | 2 +-
windows/packaging/exe/make_config.yaml | 2 +-
25 files changed, 517 insertions(+), 588 deletions(-)
create mode 100644 linux/packaging/app.hiddify.com.appdata.xml
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 665eb9a1..d49fa914 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -15,7 +15,7 @@ body:
id: confirm-search
attributes:
label: Search first
- description: Please search [existing issues](https://github.com/hiddify/hiddify-next/issues) before reporting.
+ description: Please search [existing issues](https://github.com/hiddify/hiddify-app/issues) before reporting.
options:
- label: I searched and no similar issues were found
required: true
diff --git a/.github/release_message.md b/.github/release_message.md
index eb0a0c86..428d3ab6 100644
--- a/.github/release_message.md
+++ b/.github/release_message.md
@@ -25,29 +25,29 @@
| Android |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| Windows |
- 
- 
-
+ 
+ 
+
|
| macOS (v10.15+) |
- 
-  |
+ 
+  |
| Linux |
-
-
- |
+
+
+ |
@@ -57,6 +57,6 @@
-**List of all changes:** [ChangeLog](https://github.com/hiddify/hiddify-next/blob/main/HISTORY.md)
+**List of all changes:** [ChangeLog](https://github.com/hiddify/hiddify-app/blob/main/HISTORY.md)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0e116feb..0f40082d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -106,6 +106,7 @@ jobs:
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
echo "${{secrets.APPLE_MOBILE_PROVISIONING_PROFILES_TARGZ_BASE64}}"|base64 --decode | tar xz -C ~/Library/MobileDevice/Provisioning\ Profiles
ls ~/Library/MobileDevice/Provisioning\ Profiles
+ security find-identity -v -p codesigning
# ls ~/Library/MobileDevice/Provisioning\ Profiles
# echo "${{secrets.NEW_APPLE_MOBILE_PROVISIONING_PROFILES_TARXZ_BASE64}}"|base64 --decode | tar xJ -C ~/Library/MobileDevice/Provisioning\ Profiles
# # echo "${{secrets.NEW_APPLE_MOBILE_PROVISIONING_PROFILES_TARGZ_BASE64_2}}"|base64 --decode | tar xz -C ~/Library/MobileDevice/Provisioning\ Profiles
@@ -333,7 +334,7 @@ jobs:
- name: Create or Update Draft Release
uses: softprops/action-gh-release@v1
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.TOKEN_FOR_HIDDIFY_APP_REPO }}
GITHUB_REPOSITORY: hiddify/hiddify-app
with:
files: ./out/*
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fab673f0..87f98c14 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,7 @@
Every contribution to HiddifyApp is welcome, whether it is reporting a bug, submitting a fix, proposing new features, or just asking a question. To make contributing to HiddifyApp as easy as possible, you will find more details for the development flow in this documentation. [Basic tutorial on how to contribute to HiddifyApp](https://hiddify.com/app/How-to-contribute-to-this-project/)
-Please note, we have a [Code of Conduct](https://github.com/hiddify/hiddify-next/blob/main/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
+Please note, we have a [Code of Conduct](https://github.com/hiddify/hiddify-app/blob/main/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
- [Feedback, Issues and Questions](#feedback-issues-and-questions)
- [Adding new Features](#adding-new-features)
@@ -18,8 +18,8 @@ Please note, we have a [Code of Conduct](https://github.com/hiddify/hiddify-next
If you encounter any issue, or you have an idea to improve, please:
-- Search through [existing open and closed GitHub Issues](https://github.com/hiddify/hiddify-next/issues) for the answer first. If you find a relevant topic, please comment on the issue.
-- If none of the issues are relevant, please add a new [issue](https://github.com/hiddify/hiddify-next/issues/new/choose) following the templates and provide as much relevant information as possible.
+- Search through [existing open and closed GitHub Issues](https://github.com/hiddify/hiddify-app/issues) for the answer first. If you find a relevant topic, please comment on the issue.
+- If none of the issues are relevant, please add a new [issue](https://github.com/hiddify/hiddify-app/issues/new/choose) following the templates and provide as much relevant information as possible.
## Adding new Features
@@ -93,7 +93,7 @@ flutter run --device-id=35492ae2
## Release
-We use [flutter_distributor](https://github.com/leanflutter/flutter_distributor) for packaging. [GitHub action](https://github.com/hiddify/hiddify-next/blob/main/.github/workflows/build.yml) is triggered on every release tag and will create a new GitHub release.
+We use [flutter_distributor](https://github.com/leanflutter/flutter_distributor) for packaging. [GitHub action](https://github.com/hiddify/hiddify-app/blob/main/.github/workflows/build.yml) is triggered on every release tag and will create a new GitHub release.
After setting up the environment, use the following make commands to build the release version:
- `make windows-release`
diff --git a/README.md b/README.md
index 10eb5b93..f83b81a4 100644
--- a/README.md
+++ b/README.md
@@ -5,16 +5,16 @@
-
+
-[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/)
+[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/)
[](https://www.youtube.com/@hiddify)[](https://telegram.dog/hiddify)[](https://telegram.dog/hiddify_board/5)
@@ -27,7 +27,7 @@
A multi-platform proxy client based on Sing-box universal proxy tool-chain. Hiddify offers a wide range of capabilities, like automatic node selection, TUN mode, remote profiles etc. Hiddify is ad-free and open-source. With support for a wide range of protocols, it provides a secure and private way for accessing free internet.
-

+
@@ -59,8 +59,8 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH etc.
📱 Available on official stores
## 🛍️ Get It On Stores
-
-
+
+
## 📥 Direct Download
@@ -77,39 +77,39 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH etc.
| iOS |
-
+
|
| Android |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| Windows |
- 
- 
-
+ 
+ 
+
|
| macOS |
- 
-
+ 
+
|
| Linux |
-
-
-
+
+
+
|
@@ -124,7 +124,7 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH etc.
-[](https://hiddify.com/app/)
+[](https://hiddify.com/app/)
@@ -184,7 +184,7 @@ Hiddify is a community driven project. If you're interested in contributing, ple
-
+
diff --git a/README_br.md b/README_br.md
index 2153b958..e7bd704f 100644
--- a/README_br.md
+++ b/README_br.md
@@ -6,16 +6,16 @@
-
+
-[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/)
+[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/)
[](https://www.youtube.com/@hiddify)[](https://telegram.dog/hiddify)[](https://telegram.dog/hiddify_board/5)
@@ -27,7 +27,7 @@
Um cliente de proxy multiplataforma baseado na ferramenta de proxy universal Sing-box. O Hiddify oferece uma ampla gama de recursos, como seleção automática de nós, modo TUN, perfis remotos, etc. O Hiddify é livre de anúncios e de código aberto. Com suporte para uma ampla variedade de protocolos, ele oferece uma maneira segura e privada de acessar a internet gratuitamente.
-

+
@@ -59,8 +59,8 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
📱 Disponível nas lojas oficiais
## 🛍️ Obtenha nas lojas
-
-
+
+
## 📥 Download direto
@@ -77,38 +77,38 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
| iOS |
-
+
|
| Android |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| Windows |
- 
- 
-
+ 
+ 
+
|
| macOS |
- 
-
+ 
+
|
| Linux |
-
-
-
+
+
+
|
@@ -123,7 +123,7 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
-[](https://hiddify.com/app/)
+[](https://hiddify.com/app/)
@@ -183,7 +183,7 @@ Agradecemos a todas as pessoas que estão participando deste projeto. Algumas pe
-
+
diff --git a/README_cn.md b/README_cn.md
index 65cf08d0..8c69bad6 100644
--- a/README_cn.md
+++ b/README_cn.md
@@ -4,12 +4,12 @@
-
+
-[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/)
+[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/)
[](https://www.youtube.com/@hiddify)[](https://telegram.dog/hiddify)[](https://telegram.dog/hiddify_board/5)
@@ -22,7 +22,7 @@
一款基于 Sing-box 通用代理工具的跨平台代理客户端。Hiddify 提供了较全面的代理功能,例如自动选择节点、TUN 模式、使用远程配置文件等。Hiddify 无广告,并且代码开源。它为大家自由访问互联网提供了一个支持多种协议的、安全且私密的工具。
-

+
@@ -53,8 +53,8 @@
📱 官方商店有售
## 🛍️ 在商店购买
-
-
+
+
## 📥 直接下载
@@ -71,39 +71,39 @@
| iOS |
-
+
|
| Android |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| Windows |
- 
- 
-
+ 
+ 
+
|
| macOS |
- 
-
+ 
+
|
| Linux |
-
-
-
+
+
+
|
@@ -118,7 +118,7 @@
-[](https://hiddify.com/app/)
+[](https://hiddify.com/app/)
@@ -179,7 +179,7 @@ Hiddify 是一个由社区驱动的项目。如果您有兴趣为本项目做出
-
+
diff --git a/README_fa.md b/README_fa.md
index a9346f4f..5d93562d 100644
--- a/README_fa.md
+++ b/README_fa.md
@@ -5,12 +5,12 @@
-
+
-[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/)
+[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/)
[](https://www.youtube.com/@hiddify)[](https://telegram.dog/hiddify)[](https://telegram.dog/hiddify_board/5)
@@ -23,7 +23,7 @@
-

+
@@ -62,8 +62,8 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
## 🛍️ دریافت از استورها
@@ -81,38 +81,38 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
| iOS |
-
+
|
| اندروید |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| ویندوز |
- 
- 
-
+ 
+ 
+
|
| مک |
- 
-
+ 
+
|
| لینوکس |
-
-
-
+
+
+
|
@@ -123,7 +123,7 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
-[](https://hiddify.com/fa/app/)
+[](https://hiddify.com/fa/app/)
@@ -132,7 +132,7 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
## 🌎 ترجمهها
-
+
با ویرایش دستی فایلهای JSON در assets/translations/ یا با استفاده از [ویرایشگر آنلاین Inlang](https://inlang.com/editor/github.com/hiddify/hiddify-next)، زبانهای موجود را بهبود بدهید و یا زبانهای جدید اضافه کنید.
@@ -183,7 +183,7 @@ Vless, Vmess, Reality, TUIC, Hysteria, Wireguard, SSH, etc.
-
+
diff --git a/README_ja.md b/README_ja.md
index 256f7faf..120470ae 100644
--- a/README_ja.md
+++ b/README_ja.md
@@ -6,16 +6,16 @@
-
+
-[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/)
+[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/)
[](https://www.youtube.com/@hiddify)[](https://telegram.dog/hiddify)[](https://telegram.dog/hiddify_board/5)
@@ -28,7 +28,7 @@
Sing-box ユニバーサルプロキシツールチェーンに基づくマルチプラットフォームプロキシクライアントです。Hiddify は、自動ノード選択、TUN モード、リモートプロファイルなど、幅広い機能を提供します。Hiddify は無料でオープンソースです。幅広いプロトコルをサポートし、無料インターネットにアクセスするための安全でプライベートな方法を提供します。
-

+
@@ -60,8 +60,8 @@ Vless、Vmess、Reality、TUIC、Hysteria、Wireguard、SSH など。
📱公式ストアで購入可能
## 🛍️ 店舗で入手
-
-
+
+
## 📥 直接ダウンロード
@@ -78,39 +78,39 @@ Vless、Vmess、Reality、TUIC、Hysteria、Wireguard、SSH など。
| iOS |
-
+
|
| Android |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| Windows |
- 
- 
-
+ 
+ 
+
|
| macOS |
- 
-
+ 
+
|
| Linux |
-
-
-
+
+
+
|
@@ -125,7 +125,7 @@ Vless、Vmess、Reality、TUIC、Hysteria、Wireguard、SSH など。
-[](https://hiddify.com/app/)
+[](https://hiddify.com/app/)
@@ -185,7 +185,7 @@ Hiddify はコミュニティドリブンのプロジェクトです。コント
-
+
diff --git a/README_ru.md b/README_ru.md
index 62cc0bc0..2bfc27b7 100644
--- a/README_ru.md
+++ b/README_ru.md
@@ -6,12 +6,12 @@
-
+
-[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/releases/)[](https://github.com/hiddify/hiddify-next/)
+[](https://play.google.com/store/apps/details?id=app.hiddify.com) [](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/releases/)[](https://github.com/hiddify/hiddify-app/)
[](https://www.youtube.com/@hiddify)[](https://telegram.dog/hiddify)[](https://telegram.dog/hiddify_board/5)
@@ -20,7 +20,7 @@
Кроссплатформенный прокси-клиент на основе ядра [Sing-box](https://github.com/SagerNet/sing-box). Hiddify предлагает широкий спектр возможностей, таких как автоматический выбор узла, режим TUN, удалённые конфигурации (подписки). Приложение с открытым исходным кодом, без рекламы. Поддерживая широкий спектр протоколов, мы обеспечиваем безопасный и конфиденциальный доступ к свободному интернету.
-

+
## 🚀 Основные особенности
@@ -49,8 +49,8 @@
📱Доступно в официальных магазинах.
## 🛍️ Приобретите в магазинах
-
-
+
+
## 📥 Прямая загрузка
@@ -66,39 +66,39 @@
| iOS |
-
+
|
| Android |
- 
- 
- 
-
+ 
+ 
+ 
+
|
| Windows |
- 
- 
-
+ 
+ 
+
|
| MacOS |
- 
-
+ 
+
|
| Linux |
-
-
-
+
+
+
|
@@ -110,7 +110,7 @@
-[](https://hiddify.com/app/)
+[](https://hiddify.com/app/)
@@ -170,7 +170,7 @@ Hiddify - это проект, развиваемый сообществом. Е
-
+
diff --git a/android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt b/android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt
index b19c41b7..39852182 100644
--- a/android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt
+++ b/android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt
@@ -254,14 +254,14 @@ class BoxService(
fileDescriptor = null
}
// commandServer?.setService(null)
-// boxService?.apply {
-// runCatching {
-// close()
-// }.onFailure {
-// writeLog("service: error when closing: $it")
-// }
-// Seq.destroyRef(refnum)
-// }
+ boxService?.apply {
+ runCatching {
+ close()
+ }.onFailure {
+ writeLog("service: error when closing: $it")
+ }
+ Seq.destroyRef(refnum)
+ }
Mobile.close(4L)
// boxService = null
Libbox.registerLocalDNSTransport(null)
diff --git a/appcast.xml b/appcast.xml
index 130c64ad..6dbecd88 100644
--- a/appcast.xml
+++ b/appcast.xml
@@ -13,21 +13,28 @@
Version 0.13.6
Sun, 7 Jan 2024 22:00:00 +0000
+
+ -
+ Version 0.13.6
+ Sun, 7 Jan 2024 22:00:00 +0000
+
-
Version 0.13.6
Sun, 7 Jan 2024 22:00:00 +0000
-
Version 0.13.6
Sun, 7 Jan 2024 22:00:00 +0000
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index d49e6d87..989be98c 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -61,13 +61,13 @@ PODS:
- GoogleToolboxForMac/Defines (= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (4.2.1)":
- GoogleToolboxForMac/Defines (= 4.2.1)
- - GoogleUtilities/Environment (8.0.2):
+ - GoogleUtilities/Environment (8.1.0):
- GoogleUtilities/Privacy
- - GoogleUtilities/Logger (8.0.2):
+ - GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- - GoogleUtilities/Privacy (8.0.2)
- - GoogleUtilities/UserDefaults (8.0.2):
+ - GoogleUtilities/Privacy (8.1.0)
+ - GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMSessionFetcher/Core (3.5.0)
@@ -110,9 +110,9 @@ PODS:
- pointer_interceptor_ios (0.0.1):
- Flutter
- PromisesObjC (2.4.0)
- - SDWebImage (5.21.0):
- - SDWebImage/Core (= 5.21.0)
- - SDWebImage/Core (5.21.0)
+ - SDWebImage (5.21.3):
+ - SDWebImage/Core (= 5.21.3)
+ - SDWebImage/Core (5.21.3)
- Sentry/HybridSDK (8.46.0)
- sentry_flutter (8.14.0):
- Flutter
@@ -123,16 +123,16 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- - sqlite3 (3.49.1):
- - sqlite3/common (= 3.49.1)
- - sqlite3/common (3.49.1)
- - sqlite3/dbstatvtab (3.49.1):
+ - sqlite3 (3.49.2):
+ - sqlite3/common (= 3.49.2)
+ - sqlite3/common (3.49.2)
+ - sqlite3/dbstatvtab (3.49.2):
- sqlite3/common
- - sqlite3/fts5 (3.49.1):
+ - sqlite3/fts5 (3.49.2):
- sqlite3/common
- - sqlite3/perf-threadsafe (3.49.1):
+ - sqlite3/perf-threadsafe (3.49.2):
- sqlite3/common
- - sqlite3/rtree (3.49.1):
+ - sqlite3/rtree (3.49.2):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
@@ -240,14 +240,14 @@ SPEC CHECKSUMS:
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
EasyPermissionX: ff4c438f6ee80488f873b4cb921e32d982523067
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
- Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29
flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
- GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
+ GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
@@ -262,12 +262,12 @@ SPEC CHECKSUMS:
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
pointer_interceptor_ios: 508241697ff0947f853c061945a8b822463947c1
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
- SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
+ SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
sentry_flutter: 187f9b6b06f00f36b4930ec7ea9f34c254095d15
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
- sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
+ sqlite3: 3c950dc86011117c307eb0b28c4a7bb449dce9f1
sqlite3_flutter_libs: cc304edcb8e1d8c595d1b08c7aeb46a47691d9db
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 680a732e..8d290abd 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart
index 6bdc68d0..a49111bd 100644
--- a/lib/bootstrap.dart
+++ b/lib/bootstrap.dart
@@ -30,10 +30,7 @@ import 'package:hiddify/utils/utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
-Future lazyBootstrap(
- WidgetsBinding widgetsBinding,
- Environment env,
-) async {
+Future lazyBootstrap(WidgetsBinding widgetsBinding, Environment env) async {
if (!kIsWeb) {
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
}
@@ -43,48 +40,28 @@ Future lazyBootstrap(
final stopWatch = Stopwatch()..start();
- final container = ProviderContainer(
- overrides: [
- environmentProvider.overrideWithValue(env),
- ],
- );
+ final container = ProviderContainer(overrides: [environmentProvider.overrideWithValue(env)]);
- await _init(
- "directories",
- () => container.read(appDirectoriesProvider.future),
- );
+ await _init("directories", () => container.read(appDirectoriesProvider.future));
LoggerController.init(container.read(logPathResolverProvider).appFile().path);
- final appInfo = await _init(
- "app info",
- () => container.read(appInfoProvider.future),
- );
- await _init(
- "preferences",
- () => container.read(sharedPreferencesProvider.future),
- );
+ final appInfo = await _init("app info", () => container.read(appInfoProvider.future));
+ await _init("preferences", () => container.read(sharedPreferencesProvider.future));
final enableAnalytics = await container.read(analyticsControllerProvider.future);
if (enableAnalytics) {
- await _init(
- "analytics",
- () => container.read(analyticsControllerProvider.notifier).enableAnalytics(),
- );
+ await _init("analytics", () => container.read(analyticsControllerProvider.notifier).enableAnalytics());
}
- await _init(
- "preferences migration",
- () async {
- try {
- await PreferencesMigration(
- sharedPreferences: container.read(sharedPreferencesProvider).requireValue,
- ).migrate();
- } catch (e, stackTrace) {
- Logger.bootstrap.error("preferences migration failed", e, stackTrace);
- if (env == Environment.dev) rethrow;
- Logger.bootstrap.info("clearing preferences");
- await container.read(sharedPreferencesProvider).requireValue.clear();
- }
+ await _init("preferences migration", () async {
+ try {
+ await PreferencesMigration(sharedPreferences: container.read(sharedPreferencesProvider).requireValue).migrate();
+ } catch (e, stackTrace) {
+ Logger.bootstrap.error("preferences migration failed", e, stackTrace);
+ if (env == Environment.dev) rethrow;
+ Logger.bootstrap.info("clearing preferences");
+ await container.read(sharedPreferencesProvider).requireValue.clear();
+ }
});
await _init("db migration from v1 to v2", () async {
@@ -107,10 +84,7 @@ Future lazyBootstrap(
final debug = container.read(debugModeNotifierProvider) || kDebugMode;
if (PlatformUtils.isDesktop) {
- await _init(
- "window controller",
- () => container.read(windowNotifierProvider.future),
- );
+ await _init("window controller", () => container.read(windowNotifierProvider.future));
final silentStart = container.read(Preferences.silentStart);
Logger.bootstrap.debug("silent start [${silentStart ? "Enabled" : "Disabled"}]");
@@ -119,38 +93,19 @@ Future lazyBootstrap(
} else {
Logger.bootstrap.debug("silent start, remain hidden accessible via tray");
}
- await _init(
- "auto start service",
- () => container.read(autoStartNotifierProvider.future),
- );
+ await _init("auto start service", () => container.read(autoStartNotifierProvider.future));
}
- await _init(
- "logs repository",
- () => container.read(logRepositoryProvider.future),
- );
+ await _init("logs repository", () => container.read(logRepositoryProvider.future));
await _init("logger controller", () => LoggerController.postInit(debug));
Logger.bootstrap.info(appInfo.format());
- await _init(
- "profile repository",
- () => container.read(profileRepositoryProvider.future),
- );
+ await _init("profile repository", () => container.read(profileRepositoryProvider.future));
- await _init(
- "translations",
- () => container.read(translationsProvider.future),
- );
+ await _init("translations", () => container.read(translationsProvider.future));
- await _safeInit(
- "active profile",
- () => container.read(activeProfileProvider.future),
- timeout: 1000,
- );
- await _init(
- "sing-box",
- () => container.read(hiddifyCoreServiceProvider).init(ref: container),
- );
+ await _safeInit("active profile", () => container.read(activeProfileProvider.future), timeout: 1000);
+ await _init("hiddify-core", () => container.read(hiddifyCoreServiceProvider).init(ref: container));
if (!kIsWeb) {
// await _safeInit(
// "deep link service",
@@ -167,12 +122,9 @@ Future lazyBootstrap(
// }
if (Platform.isAndroid) {
- await _safeInit(
- "android display mode",
- () async {
- await FlutterDisplayMode.setHighRefreshRate();
- },
- );
+ await _safeInit("android display mode", () async {
+ await FlutterDisplayMode.setHighRefreshRate();
+ });
}
}
Logger.bootstrap.info("bootstrap took [${stopWatch.elapsedMilliseconds}ms]");
@@ -181,26 +133,18 @@ Future lazyBootstrap(
runApp(
ProviderScope(
parent: container,
- observers: [
- RiverpodObserver(),
- ],
- child: SentryUserInteractionWidget(
- child: const App(),
- ),
+ observers: [RiverpodObserver()],
+ child: SentryUserInteractionWidget(child: const App()),
),
);
if (!kIsWeb) {
FlutterNativeSplash.remove();
}
- SentryFlutter.setAppStartEnd(DateTime.now().toUtc());
+ // SentryFlutter.setAppStartEnd(DateTime.now().toUtc());
}
-Future _init(
- String name,
- Future Function() initializer, {
- int? timeout,
-}) async {
+Future _init(String name, Future Function() initializer, {int? timeout}) async {
final stopWatch = Stopwatch()..start();
Logger.bootstrap.info("initializing [$name]");
Future func() => timeout != null ? initializer().timeout(Duration(milliseconds: timeout)) : initializer();
@@ -216,11 +160,7 @@ Future _init(
}
}
-Future _safeInit(
- String name,
- Future Function() initializer, {
- int? timeout,
-}) async {
+Future _safeInit(String name, Future Function() initializer, {int? timeout}) async {
try {
return await _init(name, initializer, timeout: timeout);
} catch (e) {
diff --git a/lib/core/analytics/analytics_controller.dart b/lib/core/analytics/analytics_controller.dart
index 7e69e8b0..67ed17bc 100644
--- a/lib/core/analytics/analytics_controller.dart
+++ b/lib/core/analytics/analytics_controller.dart
@@ -39,24 +39,22 @@ class AnalyticsController extends _$AnalyticsController with AppLogger {
final sentryLogger = SentryLoggyIntegration();
LoggerController.instance.addPrinter("analytics", sentryLogger);
- await SentryFlutter.init(
- (options) {
- options.dsn = dsn;
- // options.environment = env.name;
- // options.dist = appInfo.release.name;
- options.debug = kDebugMode;
- options.enableNativeCrashHandling = true;
- options.enableNdkScopeSync = true;
- options.autoAppStart = false;
- // options.attachScreenshot = true;
- options.serverName = "";
- options.attachThreads = true;
- options.tracesSampleRate = 0.20;
- options.enableUserInteractionTracing = true;
- options.addIntegration(sentryLogger);
- options.beforeSend = sentryBeforeSend;
- },
- );
+ await SentryFlutter.init((options) {
+ options.dsn = dsn;
+ // options.environment = env.name;
+ // options.dist = appInfo.release.name;
+ options.debug = kDebugMode;
+ options.enableNativeCrashHandling = true;
+ options.enableNdkScopeSync = true;
+ options.autoAppStart = false;
+ // options.attachScreenshot = true;
+ options.serverName = "";
+ options.attachThreads = true;
+ options.tracesSampleRate = 0.20;
+ options.enableUserInteractionTracing = true;
+ options.addIntegration(sentryLogger);
+ options.beforeSend = sentryBeforeSend;
+ });
state = const AsyncData(true);
}
diff --git a/lib/core/model/constants.dart b/lib/core/model/constants.dart
index f1646143..fc101a98 100644
--- a/lib/core/model/constants.dart
+++ b/lib/core/model/constants.dart
@@ -6,7 +6,7 @@ abstract class Constants {
static const githubUrl = "https://github.com/hiddify/hiddify-next";
static const licenseUrl = "https://github.com/hiddify/hiddify-next?tab=License-1-ov-file#readme";
static const githubReleasesApiUrl = "https://api.github.com/repos/hiddify/hiddify-next/releases";
- static const githubLatestReleaseUrl = "https://github.com/hiddify/hiddify-next/releases/latest";
+ static const githubLatestReleaseUrl = "https://github.com/hiddify/hiddify-app/releases/latest";
static const appCastUrl = "https://raw.githubusercontent.com/hiddify/hiddify-next/main/appcast.xml";
static const telegramChannelUrl = "https://t.me/hiddify";
static const privacyPolicyUrl = "https://hiddify.com/privacy-policy/";
@@ -54,11 +54,7 @@ abstract class IntroConst {
static const termsAndConditionsKey = 'terms-and-conditions';
static const githubKey = 'github';
static const licenseKey = 'license';
- static const url = {
- IntroConst.termsAndConditionsKey: Constants.termsAndConditionsUrl,
- IntroConst.githubKey: Constants.githubUrl,
- IntroConst.licenseKey: Constants.licenseUrl,
- };
+ static const url = {IntroConst.termsAndConditionsKey: Constants.termsAndConditionsUrl, IntroConst.githubKey: Constants.githubUrl, IntroConst.licenseKey: Constants.licenseUrl};
}
abstract class WarpConst {
@@ -67,30 +63,12 @@ abstract class WarpConst {
static const warpConsentGiven = "warp-consent-given";
static const warpTermsOfServiceKey = 'warp-terms-of-service';
static const warpPrivacyPolicyKey = 'warp-privacy-policy';
- static const url = {
- WarpConst.warpTermsOfServiceKey: Constants.cfWarpTermsOfService,
- WarpConst.warpPrivacyPolicyKey: Constants.cfWarpPrivacyPolicy,
- };
+ static const url = {WarpConst.warpTermsOfServiceKey: Constants.cfWarpTermsOfService, WarpConst.warpPrivacyPolicyKey: Constants.cfWarpPrivacyPolicy};
}
abstract class KeyboardConst {
- static final allArrows = {
- LogicalKeyboardKey.arrowUp,
- LogicalKeyboardKey.arrowDown,
- LogicalKeyboardKey.arrowLeft,
- LogicalKeyboardKey.arrowRight,
- };
- static final horizontalArrows = {
- LogicalKeyboardKey.arrowLeft,
- LogicalKeyboardKey.arrowRight,
- };
- static final verticalArrows = {
- LogicalKeyboardKey.arrowUp,
- LogicalKeyboardKey.arrowDown,
- };
- static final select = {
- LogicalKeyboardKey.select,
- LogicalKeyboardKey.enter,
- LogicalKeyboardKey.tab,
- };
+ static final allArrows = {LogicalKeyboardKey.arrowUp, LogicalKeyboardKey.arrowDown, LogicalKeyboardKey.arrowLeft, LogicalKeyboardKey.arrowRight};
+ static final horizontalArrows = {LogicalKeyboardKey.arrowLeft, LogicalKeyboardKey.arrowRight};
+ static final verticalArrows = {LogicalKeyboardKey.arrowUp, LogicalKeyboardKey.arrowDown};
+ static final select = {LogicalKeyboardKey.select, LogicalKeyboardKey.enter, LogicalKeyboardKey.tab};
}
diff --git a/lib/core/utils/preferences_utils.dart b/lib/core/utils/preferences_utils.dart
index 18abc1c4..8efc4798 100644
--- a/lib/core/utils/preferences_utils.dart
+++ b/lib/core/utils/preferences_utils.dart
@@ -4,14 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
class PreferencesEntry with InfraLogger {
- PreferencesEntry({
- required this.preferences,
- required this.key,
- required this.defaultValue,
- this.mapFrom,
- this.mapTo,
- this.validator,
- });
+ PreferencesEntry({required this.preferences, required this.key, required this.defaultValue, this.mapFrom, this.mapTo, this.validator});
final SharedPreferences preferences;
final String key;
@@ -22,7 +15,7 @@ class PreferencesEntry with InfraLogger {
T read() {
try {
- loggy.debug("getting persisted preference [$key]($T)");
+ // loggy.debug("getting persisted preference [$key]($T)");
final T value;
if (mapFrom != null) {
final persisted = preferences.get(key) as P?;
@@ -93,55 +86,36 @@ class PreferencesEntry with InfraLogger {
}
class PreferencesNotifier extends StateNotifier {
- PreferencesNotifier._({
- required Ref ref,
- required this.entry,
- this.overrideValue,
- this.possibleValues,
- }) : _ref = ref,
- super(overrideValue ?? entry.read());
+ PreferencesNotifier._({required Ref ref, required this.entry, this.overrideValue, this.possibleValues}) : _ref = ref, super(overrideValue ?? entry.read());
final Ref _ref;
final PreferencesEntry entry;
final T? overrideValue;
final List? possibleValues;
- static StateNotifierProvider, T> create(String key, T defaultValue,
- {T Function(Ref ref)? defaultValueFunction, T Function(P value)? mapFrom, P Function(T value)? mapTo, bool Function(T value)? validator, T? overrideValue, List? possibleValues}) =>
- StateNotifierProvider(
- (ref) => PreferencesNotifier._(
- ref: ref,
- entry: PreferencesEntry(
- preferences: ref.read(sharedPreferencesProvider).requireValue,
- key: key,
- defaultValue: defaultValueFunction?.call(ref) ?? defaultValue,
- mapFrom: mapFrom,
- mapTo: mapTo,
- validator: validator,
- ),
- overrideValue: overrideValue,
- possibleValues: possibleValues),
- );
-
- static AutoDisposeStateNotifierProvider, T> createAutoDispose(
+ static StateNotifierProvider, T> create(
String key,
T defaultValue, {
+ T Function(Ref ref)? defaultValueFunction,
T Function(P value)? mapFrom,
P Function(T value)? mapTo,
bool Function(T value)? validator,
T? overrideValue,
- }) =>
+ List? possibleValues,
+ }) => StateNotifierProvider(
+ (ref) => PreferencesNotifier._(
+ ref: ref,
+ entry: PreferencesEntry(preferences: ref.read(sharedPreferencesProvider).requireValue, key: key, defaultValue: defaultValueFunction?.call(ref) ?? defaultValue, mapFrom: mapFrom, mapTo: mapTo, validator: validator),
+ overrideValue: overrideValue,
+ possibleValues: possibleValues,
+ ),
+ );
+
+ static AutoDisposeStateNotifierProvider, T> createAutoDispose(String key, T defaultValue, {T Function(P value)? mapFrom, P Function(T value)? mapTo, bool Function(T value)? validator, T? overrideValue}) =>
StateNotifierProvider.autoDispose(
(ref) => PreferencesNotifier._(
ref: ref,
- entry: PreferencesEntry(
- preferences: ref.read(sharedPreferencesProvider).requireValue,
- key: key,
- defaultValue: defaultValue,
- mapFrom: mapFrom,
- mapTo: mapTo,
- validator: validator,
- ),
+ entry: PreferencesEntry(preferences: ref.read(sharedPreferencesProvider).requireValue, key: key, defaultValue: defaultValue, mapFrom: mapFrom, mapTo: mapTo, validator: validator),
overrideValue: overrideValue,
),
);
diff --git a/lib/hiddifycore/hiddify_core_service.dart b/lib/hiddifycore/hiddify_core_service.dart
index ad8d73ad..e0b9cc78 100644
--- a/lib/hiddifycore/hiddify_core_service.dart
+++ b/lib/hiddifycore/hiddify_core_service.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:io';
import 'package:fpdart/fpdart.dart';
import 'package:grpc/grpc.dart';
@@ -36,12 +37,15 @@ class HiddifyCoreService with InfraLogger {
statusController.add(currentState);
if (ref == null) return;
final dirs = ref.read(appDirectoriesProvider).requireValue;
- setup(dirs, false).mapLeft((e) {
- loggy.error(e);
- ref.read(inAppNotificationControllerProvider).showErrorToast(e);
- }).map((_) {
- loggy.info("Hiddify-core setup done");
- }).run();
+ setup(dirs, false)
+ .mapLeft((e) {
+ loggy.error(e);
+ ref.read(inAppNotificationControllerProvider).showErrorToast(e);
+ })
+ .map((_) {
+ loggy.info("Hiddify-core setup done");
+ })
+ .run();
}
/// validates config by path and save it
@@ -50,198 +54,157 @@ class HiddifyCoreService with InfraLogger {
/// [tempPath] includes base config, possibly invalid
/// [debug] indicates if debug mode (avoid in prod)
- TaskEither validateConfigByPath(
- String path,
- String tempPath,
- bool debug,
- ) {
- return TaskEither(
- () async {
- final response = await core.fgClient.parse(
- ParseRequest(tempPath: tempPath, configPath: path, debug: false),
- );
- if (response.responseCode != ResponseCode.OK) return left("${response.responseCode} ${response.message}");
- return right(unit);
- },
- );
+ TaskEither validateConfigByPath(String path, String tempPath, bool debug) {
+ return TaskEither(() async {
+ final response = await core.fgClient.parse(ParseRequest(tempPath: tempPath, configPath: path, debug: false));
+ if (response.responseCode != ResponseCode.OK) return left("${response.responseCode} ${response.message}");
+ return right(unit);
+ });
}
TaskEither generateFullConfigByPath(String path) {
- return TaskEither(
- () async {
- final response = await core.fgClient.parse(
- ParseRequest(configPath: path, debug: false),
- );
- if (response.responseCode != ResponseCode.OK) return left("${response.responseCode} ${response.message}");
- return right(response.content);
- },
- );
+ return TaskEither(() async {
+ final response = await core.fgClient.parse(ParseRequest(configPath: path, debug: false));
+ if (response.responseCode != ResponseCode.OK) return left("${response.responseCode} ${response.message}");
+ return right(response.content);
+ });
}
TaskEither setup(Directories directories, bool debug) {
- return TaskEither(
- () async {
- try {
- final setupResponse = await core.setup(directories, debug, 3);
+ return TaskEither(() async {
+ try {
+ final setupResponse = await core.setup(directories, debug, 3);
- if (setupResponse.isNotEmpty) {
- return left(setupResponse);
- }
- await startListeningLogs("fg", core.fgClient);
- await startListeningStatus("fg", core.fgClient);
- if (!core.isSingleChannel()) {
- await startListeningLogs("bg", core.bgClient);
- await startListeningStatus("bg", core.bgClient);
- }
-
- return right(unit);
- } catch (e) {
- return left(e.toString());
+ if (setupResponse.isNotEmpty) {
+ return left(setupResponse);
}
- },
- );
- }
-
- TaskEither changeOptions(SingboxConfigOption options) {
- return TaskEither(
- () async {
- loggy.debug("changing options");
- // latestOptions = options;
- try {
- final res = await core.fgClient.changeHiddifySettings(
- ChangeHiddifySettingsRequest(
- hiddifySettingsJson: jsonEncode(options.toJson()),
- ),
- );
- if (res.messageType != MessageType.EMPTY) return left("${res.messageType} ${res.message}");
- await core.bgClient.changeHiddifySettings(
- ChangeHiddifySettingsRequest(
- hiddifySettingsJson: jsonEncode(options.toJson()),
- ),
- );
- } on GrpcError catch (e) {
- if (e.code == StatusCode.unavailable) {
- loggy.debug("background core is not started yet! $e");
- } else {
- rethrow;
- }
- }
-
- return right(unit);
- },
- );
- }
-
- TaskEither start(String path, String name, bool disableMemoryLimit) {
- return TaskEither(
- () async {
- statusController.add(currentState = const SingboxStatus.starting());
- loggy.debug("starting");
-
- if (!await core.start(path, name)) {}
+ await startListeningLogs("fg", core.fgClient);
+ await startListeningStatus("fg", core.fgClient);
if (!core.isSingleChannel()) {
await startListeningLogs("bg", core.bgClient);
await startListeningStatus("bg", core.bgClient);
}
- // if (latestOptions != null) {
- // await core.bgClient.changeHiddifySettings(
- // ChangeHiddifySettingsRequest(
- // hiddifySettingsJson: jsonEncode(latestOptions!.toJson()),
- // ),
- // );
- // }
- // final content = await File(path).readAsString();
- // loggy.debug("starting with content: $content");
- try {
- final res = await core.bgClient.start(
- StartRequest(
- configPath: path,
- configName: name,
- // configContent: content,
- disableMemoryLimit: disableMemoryLimit,
- ),
- );
- if (res.messageType != MessageType.EMPTY) return left("${res.messageType} ${res.message}");
- } on GrpcError catch (e) {
- loggy.error("failed to start bg core: $e");
- if (e.code == StatusCode.unavailable) {
- return left("background core is not started yet!");
- }
- // throw InvalidConfig(e.message);
- // throw DioException.connectionError(requestOptions: RequestOptions(), reason: e.codeName, error: e);
-
- // throw DioException(requestOptions: RequestOptions(), error: e);
- return left("${e.message}");
- }
-
- // if (res.messageType != MessageType.EMPTY) return left(res);
return right(unit);
- },
- );
+ } catch (e) {
+ return left(e.toString());
+ }
+ });
}
- TaskEither stop() {
- return TaskEither(
- () async {
- loggy.debug("stopping");
- try {
- final res = await core.bgClient.stop(Empty());
- } catch (e) {
- loggy.error("failed to stop bg core: $e");
+ TaskEither changeOptions(SingboxConfigOption options) {
+ return TaskEither(() async {
+ loggy.debug("changing options");
+ // latestOptions = options;
+ try {
+ final res = await core.fgClient.changeHiddifySettings(ChangeHiddifySettingsRequest(hiddifySettingsJson: jsonEncode(options.toJson())));
+ if (res.messageType != MessageType.EMPTY) return left("${res.messageType} ${res.message}");
+ await core.bgClient.changeHiddifySettings(ChangeHiddifySettingsRequest(hiddifySettingsJson: jsonEncode(options.toJson())));
+ } on GrpcError catch (e) {
+ if (e.code == StatusCode.unavailable) {
+ loggy.debug("background core is not started yet! $e");
+ } else {
+ rethrow;
}
- if (!await core.stop()) {}
- statusController.add(currentState = const SingboxStatus.stopped());
+ }
- return right(unit);
- },
- );
+ return right(unit);
+ });
}
- TaskEither restart(String path, String name, bool disableMemoryLimit) {
- return TaskEither(
- () async {
- loggy.debug("restarting");
- // if (!await core.restart(path, name)) {
- final res = await core.bgClient.restart(
+ TaskEither start(String path, String name, bool disableMemoryLimit) {
+ return TaskEither(() async {
+ statusController.add(currentState = const SingboxStatus.starting());
+ loggy.debug("starting");
+
+ if (!await core.start(path, name)) {}
+ if (!core.isSingleChannel()) {
+ await startListeningLogs("bg", core.bgClient);
+ await startListeningStatus("bg", core.bgClient);
+ }
+ // if (latestOptions != null) {
+ // await core.bgClient.changeHiddifySettings(
+ // ChangeHiddifySettingsRequest(
+ // hiddifySettingsJson: jsonEncode(latestOptions!.toJson()),
+ // ),
+ // );
+ // }
+ // final content = await File(path).readAsString();
+ // loggy.debug("starting with content: $content");
+ try {
+ final res = await core.bgClient.start(
StartRequest(
configPath: path,
configName: name,
+ // configContent: content,
disableMemoryLimit: disableMemoryLimit,
- delayStart: true,
),
);
if (res.messageType != MessageType.EMPTY) return left("${res.messageType} ${res.message}");
- await stop().run();
- await start(path, name, disableMemoryLimit).run();
- // }
- // if (!core.isSingleChannel()) {
- // await startListeningStatus("bg", core.bgClient);
- // await startListeningLogs("bg", core.bgClient);
- // }
- return right(unit);
- },
- );
+ } on GrpcError catch (e) {
+ loggy.error("failed to start bg core: $e");
+ if (e.code == StatusCode.unavailable) {
+ return left("background core is not started yet!");
+ }
+ // throw InvalidConfig(e.message);
+ // throw DioException.connectionError(requestOptions: RequestOptions(), reason: e.codeName, error: e);
+
+ // throw DioException(requestOptions: RequestOptions(), error: e);
+ return left("${e.message}");
+ }
+
+ // if (res.messageType != MessageType.EMPTY) return left(res);
+
+ return right(unit);
+ });
+ }
+
+ TaskEither stop() {
+ return TaskEither(() async {
+ loggy.debug("stopping");
+ try {
+ final res = await core.bgClient.stop(Empty());
+ } catch (e) {
+ loggy.error("failed to stop bg core: $e");
+ }
+ if (!await core.stop()) {}
+ statusController.add(currentState = const SingboxStatus.stopped());
+
+ return right(unit);
+ });
+ }
+
+ TaskEither restart(String path, String name, bool disableMemoryLimit) {
+ return TaskEither(() async {
+ loggy.debug("restarting");
+ // if (!await core.restart(path, name)) {
+ final res = await core.bgClient.restart(StartRequest(configPath: path, configName: name, disableMemoryLimit: disableMemoryLimit, delayStart: true));
+ if (res.messageType != MessageType.EMPTY) return left("${res.messageType} ${res.message}");
+ await stop().run();
+ await start(path, name, disableMemoryLimit).run();
+ // }
+ // if (!core.isSingleChannel()) {
+ // await startListeningStatus("bg", core.bgClient);
+ // await startListeningLogs("bg", core.bgClient);
+ // }
+ return right(unit);
+ });
}
TaskEither resetTunnel() {
- return TaskEither(
- () async {
- // only available on iOS (and macOS later)
- if (!PlatformUtils.isIOS) {
- throw UnimplementedError(
- "reset tunnel function unavailable on platform",
- );
- }
+ return TaskEither(() async {
+ // only available on iOS (and macOS later)
+ if (!PlatformUtils.isIOS) {
+ throw UnimplementedError("reset tunnel function unavailable on platform");
+ }
- // loggy.debug("resetting tunnel");
- final res = await core.resetTunnel();
- if (res) {
- return right(unit);
- }
- return left("failed to reset tunnel");
- },
- );
+ // loggy.debug("resetting tunnel");
+ final res = await core.resetTunnel();
+ if (res) {
+ return right(unit);
+ }
+ return left("failed to reset tunnel");
+ });
}
// Stream> watchGroups() async* {
@@ -278,35 +241,22 @@ class HiddifyCoreService with InfraLogger {
}
TaskEither selectOutbound(String groupTag, String outboundTag) {
- return TaskEither(
- () async {
- loggy.debug("selecting outbound");
- final res = await core.bgClient.selectOutbound(
- SelectOutboundRequest(
- groupTag: groupTag,
- outboundTag: outboundTag,
- ),
- );
- if (res.code != ResponseCode.OK) return left("${res.code} ${res.message}");
+ return TaskEither(() async {
+ loggy.debug("selecting outbound");
+ final res = await core.bgClient.selectOutbound(SelectOutboundRequest(groupTag: groupTag, outboundTag: outboundTag));
+ if (res.code != ResponseCode.OK) return left("${res.code} ${res.message}");
- return right(unit);
- },
- );
+ return right(unit);
+ });
}
TaskEither urlTest(String groupTag) {
- return TaskEither(
- () async {
- loggy.debug("url test");
- final res = await core.bgClient.urlTest(
- UrlTestRequest(
- groupTag: groupTag,
- ),
- );
- if (res.code != ResponseCode.OK) return left("${res.code} ${res.message}");
- return right(unit);
- },
- );
+ return TaskEither(() async {
+ loggy.debug("url test");
+ final res = await core.bgClient.urlTest(UrlTestRequest(groupTag: groupTag));
+ if (res.code != ResponseCode.OK) return left("${res.code} ${res.message}");
+ return right(unit);
+ });
}
List logBuffer = [];
@@ -335,42 +285,23 @@ class HiddifyCoreService with InfraLogger {
}
TaskEither clearLogs() {
- return TaskEither(
- () async {
- loggy.debug("clearing logs");
- logBuffer.clear();
- // final res = await core.bgClient(Empty());
- // if (res.code != ResponseCode.OK) return left("${res.code} ${res.message}");
- return right(unit);
- },
- );
+ return TaskEither(() async {
+ loggy.debug("clearing logs");
+ logBuffer.clear();
+ // final res = await core.bgClient(Empty());
+ // if (res.code != ResponseCode.OK) return left("${res.code} ${res.message}");
+ return right(unit);
+ });
}
- TaskEither generateWarpConfig({
- required String licenseKey,
- required String previousAccountId,
- required String previousAccessToken,
- }) {
- return TaskEither(
- () async {
- loggy.debug("generating warp config");
- final warpConfig = await core.fgClient.generateWarpConfig(
- GenerateWarpConfigRequest(
- licenseKey: licenseKey,
- accountId: previousAccountId,
- accessToken: previousAccessToken,
- ),
- );
- // if (warpConfig.code != ResponseCode.OK) return left("${warpConfig.code} ${warpConfig.message}");
- final WarpResponse warp = (
- log: warpConfig.log,
- accountId: warpConfig.account.accountId,
- accessToken: warpConfig.account.accessToken,
- wireguardConfig: jsonEncode(warpConfig.config.toProto3Json()),
- );
- return right(warp);
- },
- );
+ TaskEither generateWarpConfig({required String licenseKey, required String previousAccountId, required String previousAccessToken}) {
+ return TaskEither(() async {
+ loggy.debug("generating warp config");
+ final warpConfig = await core.fgClient.generateWarpConfig(GenerateWarpConfigRequest(licenseKey: licenseKey, accountId: previousAccountId, accessToken: previousAccessToken));
+ // if (warpConfig.code != ResponseCode.OK) return left("${warpConfig.code} ${warpConfig.message}");
+ final WarpResponse warp = (log: warpConfig.log, accountId: warpConfig.account.accountId, accessToken: warpConfig.account.accessToken, wireguardConfig: jsonEncode(warpConfig.config.toProto3Json()));
+ return right(warp);
+ });
}
Stream watchStatus() async* {
@@ -380,13 +311,14 @@ class HiddifyCoreService with InfraLogger {
Future startListeningStatus(String key, CoreClient cc) async {
await listenSingle(
"${key}StatusListener",
- () => cc.coreInfoListener(Empty(), options: grpcOptions).map(
- (event) {
- currentState = SingboxStatus.fromCoreInfo(event);
- statusController.add(currentState);
- return currentState;
- },
- ).endWith(const SingboxStatus.stopped()),
+ () => cc
+ .coreInfoListener(Empty(), options: grpcOptions)
+ .map((event) {
+ currentState = SingboxStatus.fromCoreInfo(event);
+ statusController.add(currentState);
+ return currentState;
+ })
+ .endWith(const SingboxStatus.stopped()),
);
}
diff --git a/linux/packaging/app.hiddify.com.appdata.xml b/linux/packaging/app.hiddify.com.appdata.xml
new file mode 100644
index 00000000..bf63da5a
--- /dev/null
+++ b/linux/packaging/app.hiddify.com.appdata.xml
@@ -0,0 +1,90 @@
+
+
+
+ app.hiddify.com
+ CC0-1.0
+ GPL-3.0-or-later
+
+ Hiddify
+ Modern Proxy and VPN Manager for Linux
+
+ Hiddify
+ linux@hiddify.com
+
+
+
+ Hiddify is an advanced proxy and VPN client built for privacy and control.
+ It supports multiple backend protocols including V2Ray, Xray, Clash, and Sing-box,
+ providing flexibility and performance for all kinds of network configurations.
+
+
+ Designed with simplicity in mind, Hiddify helps users connect securely and
+ manage complex proxy configurations through a clean graphical interface.
+
+
+
+
+
+ https://hiddify.com/assets/hiddify-next-mobile.svg
+ Main Interface of Hiddify
+
+
+
+ hiddify.desktop
+
+ ./assets/images/source/ic_launcher_border.png
+
+
+ Network
+
+
+
+ Hiddify
+ Proxy
+ VPN
+ V2Ray
+ Nekoray
+ Xray
+ Psiphon
+ OpenVPN
+
+
+
+ x-scheme-handler/hiddify
+ x-scheme-handler/v2ray
+ x-scheme-handler/v2rayn
+ x-scheme-handler/v2rayng
+ x-scheme-handler/clash
+ x-scheme-handler/clashmeta
+ x-scheme-handler/sing-box
+
+
+ https://hiddify.com
+ https://github.com/hiddify/hiddify-app/issues
+ https://docs.hiddify.com
+
+
+ hiddify
+
+
+
+
+
+ Initial Linux release of Hiddify with multi-protocol support and modern UI.
+
+
+
+
+ hiddify
+
+
+ hiddify
+ optional
+ x11
+ 6604
+ false
+
+
\ No newline at end of file
diff --git a/linux/packaging/appimage/make_config.yaml b/linux/packaging/appimage/make_config.yaml
index 949a5230..25c97181 100644
--- a/linux/packaging/appimage/make_config.yaml
+++ b/linux/packaging/appimage/make_config.yaml
@@ -41,3 +41,5 @@ app_run_file: AppRun
# include:
# - libcurl.so.4
include: []
+
+metainfo: linux/packaging/app.hiddify.com.appdata.xml
\ No newline at end of file
diff --git a/linux/packaging/deb/make_config.yaml b/linux/packaging/deb/make_config.yaml
index c946f92c..f6c59201 100644
--- a/linux/packaging/deb/make_config.yaml
+++ b/linux/packaging/deb/make_config.yaml
@@ -40,3 +40,5 @@ supported_mime_type:
- x-scheme-handler/clash
- x-scheme-handler/clashmeta
- x-scheme-handler/sing-box
+
+metainfo: linux/packaging/app.hiddify.com.appdata.xml
\ No newline at end of file
diff --git a/linux/packaging/rpm/make_config.yaml b/linux/packaging/rpm/make_config.yaml
index 09b3a791..cadc6334 100644
--- a/linux/packaging/rpm/make_config.yaml
+++ b/linux/packaging/rpm/make_config.yaml
@@ -1,5 +1,5 @@
display_name: Hiddify
-url: https://github.com/hiddify/hiddify-next/
+url: https://github.com/hiddify/hiddify-app/
license: Other
packager: hiddify
@@ -35,3 +35,5 @@ supported_mime_type:
- x-scheme-handler/clash
- x-scheme-handler/clashmeta
- x-scheme-handler/sing-box
+
+metainfo: linux/packaging/app.hiddify.com.appdata.xml
\ No newline at end of file
diff --git a/macos/packaging/pkg/make_config.yaml b/macos/packaging/pkg/make_config.yaml
index 0c2b8eaa..4c89b102 100644
--- a/macos/packaging/pkg/make_config.yaml
+++ b/macos/packaging/pkg/make_config.yaml
@@ -1,2 +1,2 @@
install-path: /Applications
-#sign-identity:
+sign-identity: "Apple Development: app hiddify (VS8XK8XGMM)"
diff --git a/windows/packaging/exe/make_config.yaml b/windows/packaging/exe/make_config.yaml
index ebdbe187..fdfe146e 100644
--- a/windows/packaging/exe/make_config.yaml
+++ b/windows/packaging/exe/make_config.yaml
@@ -1,6 +1,6 @@
app_id: 6L903538-42B1-4596-G479-BJ779F21A65D
publisher: Hiddify
-publisher_url: https://github.com/hiddify/hiddify-next
+publisher_url: https://github.com/hiddify/hiddify-app
display_name: Hiddify
executable_name: Hiddify.exe
output_base_file_name: Hiddify.exe