7
.github/help/linux/آموزش هیدیفاینکست فارسی لینوکس.desktop
vendored
Normal file
7
.github/help/linux/آموزش هیدیفاینکست فارسی لینوکس.desktop
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Icon=text-html
|
||||
Name[en_US]=آموزش هیدیفاینکست فارسی لینوکس
|
||||
Name=آموزش هیدیفاینکست فارسی لینوکس
|
||||
Type=Link
|
||||
URL=https://github.com/hiddify/hiddify-next/wiki/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%86%D8%B5%D8%A8-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%87%DB%8C%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%E2%80%8C%D9%86%DA%A9%D8%B3%D8%AA
|
||||
2
.github/help/mac-windows/آموزش هیدیفاینکست فارسی.url
vendored
Normal file
2
.github/help/mac-windows/آموزش هیدیفاینکست فارسی.url
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/hiddify/hiddify-next/wiki/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%86%D8%B5%D8%A8-%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%87%DB%8C%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%E2%80%8C%D9%86%DA%A9%D8%B3%D8%AA
|
||||
9
Makefile
9
Makefile
@@ -2,11 +2,12 @@ include dependencies.properties
|
||||
|
||||
BINDIR=./libcore/bin
|
||||
ANDROID_OUT=./android/app/libs
|
||||
IOS_OUT=./ios/Pods/Frameworks
|
||||
IOS_OUT=./libcore/bin
|
||||
DESKTOP_OUT=./libcore/bin
|
||||
GEO_ASSETS_DIR=./assets/core
|
||||
|
||||
CORE_NAME=hiddify-libcore
|
||||
CORE_PRODUCT_NAME=libcore
|
||||
CORE_NAME=hiddify-$(CORE_PRODUCT_NAME)
|
||||
ifeq ($(CHANNEL),prod)
|
||||
CORE_URL=https://github.com/hiddify/hiddify-next-core/releases/download/v$(core.version)
|
||||
else
|
||||
@@ -103,8 +104,6 @@ build-macos-libs:
|
||||
|
||||
build-ios-libs:
|
||||
make -C libcore -f Makefile ios && mv $(BINDIR)/$(CORE_NAME)-ios.xcframework $(IOS_OUT)/libcore.xcframework
|
||||
|
||||
|
||||
|
||||
release: # Create a new tag for release.
|
||||
@echo "previous version was $$(git describe --tags $$(git rev-list --tags --max-count=1))"
|
||||
@@ -127,4 +126,4 @@ release: # Create a new tag for release.
|
||||
echo "creating git tag : v$${TAG}" && \
|
||||
git tag v$${TAG} && \
|
||||
git push -u origin HEAD --tags && \
|
||||
echo "Github Actions will detect the new tag and release the new version."'
|
||||
echo "Github Actions will detect the new tag and release the new version."'
|
||||
|
||||
9
ios/Base.xcconfig
Normal file
9
ios/Base.xcconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Base.xcconfig
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 7/24/1402 AP.
|
||||
//
|
||||
|
||||
BASE_BUNDLE_IDENTIFIER=com.hiddify.app
|
||||
DEVELOPMENT_TEAM=XXXXXXXXX
|
||||
@@ -1,2 +1,4 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
#include "Base.xcconfig"
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
#include "Base.xcconfig"
|
||||
|
||||
200
ios/Podfile.lock
Normal file
200
ios/Podfile.lock
Normal file
@@ -0,0 +1,200 @@
|
||||
PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- flutter_native_splash (0.0.1):
|
||||
- Flutter
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- GoogleDataTransport (9.1.4):
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- nanopb (< 2.30910.0, >= 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleMLKit/BarcodeScanning (4.0.0):
|
||||
- GoogleMLKit/MLKitCore
|
||||
- MLKitBarcodeScanning (~> 3.0.0)
|
||||
- GoogleMLKit/MLKitCore (4.0.0):
|
||||
- MLKitCommon (~> 9.0.0)
|
||||
- GoogleToolboxForMac/DebugUtils (2.3.2):
|
||||
- GoogleToolboxForMac/Defines (= 2.3.2)
|
||||
- GoogleToolboxForMac/Defines (2.3.2)
|
||||
- GoogleToolboxForMac/Logger (2.3.2):
|
||||
- GoogleToolboxForMac/Defines (= 2.3.2)
|
||||
- "GoogleToolboxForMac/NSData+zlib (2.3.2)":
|
||||
- GoogleToolboxForMac/Defines (= 2.3.2)
|
||||
- "GoogleToolboxForMac/NSDictionary+URLArguments (2.3.2)":
|
||||
- GoogleToolboxForMac/DebugUtils (= 2.3.2)
|
||||
- GoogleToolboxForMac/Defines (= 2.3.2)
|
||||
- "GoogleToolboxForMac/NSString+URLArguments (= 2.3.2)"
|
||||
- "GoogleToolboxForMac/NSString+URLArguments (2.3.2)"
|
||||
- GoogleUtilities/Environment (7.7.0):
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.7.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/UserDefaults (7.7.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilitiesComponents (1.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMSessionFetcher/Core (2.3.0)
|
||||
- MLImage (1.0.0-beta4)
|
||||
- MLKitBarcodeScanning (3.0.0):
|
||||
- MLKitCommon (~> 9.0)
|
||||
- MLKitVision (~> 5.0)
|
||||
- MLKitCommon (9.0.0):
|
||||
- GoogleDataTransport (~> 9.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
|
||||
- "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)"
|
||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
||||
- GoogleUtilitiesComponents (~> 1.0)
|
||||
- GTMSessionFetcher/Core (< 3.0, >= 1.1)
|
||||
- MLKitVision (5.0.0):
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
|
||||
- GTMSessionFetcher/Core (< 3.0, >= 1.1)
|
||||
- MLImage (= 1.0.0-beta4)
|
||||
- MLKitCommon (~> 9.0)
|
||||
- mobile_scanner (3.2.0):
|
||||
- Flutter
|
||||
- GoogleMLKit/BarcodeScanning (~> 4.0.0)
|
||||
- nanopb (2.30909.0):
|
||||
- nanopb/decode (= 2.30909.0)
|
||||
- nanopb/encode (= 2.30909.0)
|
||||
- nanopb/decode (2.30909.0)
|
||||
- nanopb/encode (2.30909.0)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- PromisesObjC (2.1.1)
|
||||
- protocol_handler (0.0.1):
|
||||
- Flutter
|
||||
- Sentry/HybridSDK (8.11.0):
|
||||
- SentryPrivate (= 8.11.0)
|
||||
- sentry_flutter (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.11.0)
|
||||
- SentryPrivate (8.11.0)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqlite3 (3.43.1):
|
||||
- sqlite3/common (= 3.43.1)
|
||||
- sqlite3/common (3.43.1)
|
||||
- sqlite3/fts5 (3.43.1):
|
||||
- sqlite3/common
|
||||
- sqlite3/perf-threadsafe (3.43.1):
|
||||
- sqlite3/common
|
||||
- sqlite3/rtree (3.43.1):
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
- sqlite3 (~> 3.43.1)
|
||||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
- Toast (4.0.0)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- protocol_handler (from `.symlinks/plugins/protocol_handler/ios`)
|
||||
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- GoogleDataTransport
|
||||
- GoogleMLKit
|
||||
- GoogleToolboxForMac
|
||||
- GoogleUtilities
|
||||
- GoogleUtilitiesComponents
|
||||
- GTMSessionFetcher
|
||||
- MLImage
|
||||
- MLKitBarcodeScanning
|
||||
- MLKitCommon
|
||||
- MLKitVision
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- Sentry
|
||||
- SentryPrivate
|
||||
- sqlite3
|
||||
- Toast
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_local_notifications:
|
||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
flutter_native_splash:
|
||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
mobile_scanner:
|
||||
:path: ".symlinks/plugins/mobile_scanner/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
protocol_handler:
|
||||
:path: ".symlinks/plugins/protocol_handler/ios"
|
||||
sentry_flutter:
|
||||
:path: ".symlinks/plugins/sentry_flutter/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sqlite3_flutter_libs:
|
||||
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
|
||||
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
||||
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
||||
GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b
|
||||
GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e
|
||||
GoogleToolboxForMac: 8bef7c7c5cf7291c687cf5354f39f9db6399ad34
|
||||
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
|
||||
GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe
|
||||
GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2
|
||||
MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b
|
||||
MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505
|
||||
MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390
|
||||
MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49
|
||||
mobile_scanner: 47056db0c04027ea5f41a716385542da28574662
|
||||
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
|
||||
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb
|
||||
protocol_handler: ae9efcf3b307f3fdffcd9d5252775b9f7d9f0d09
|
||||
Sentry: 39d57e691e311bdb73bc1ab5bbebbd6bc890050d
|
||||
sentry_flutter: b2feefdad5b0f06602347172bc7257e8e9da5562
|
||||
SentryPrivate: 48712023cdfd523735c2edb6b06bedf26c4730a3
|
||||
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
sqlite3: e0a0623a33a20a47cb5921552aebc6e9e437dc91
|
||||
sqlite3_flutter_libs: 0d61e18fab1bed977dbd2d2fc76a726044ca00e7
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
|
||||
PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189
|
||||
|
||||
COCOAPODS: 1.13.0
|
||||
@@ -7,16 +7,47 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
032158B82ADDF8BF008D943B /* VPNManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032158B72ADDF8BF008D943B /* VPNManager.swift */; };
|
||||
032158BA2ADDFCC9008D943B /* TrafficReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032158B92ADDFCC9008D943B /* TrafficReader.swift */; };
|
||||
032158BC2ADDFD09008D943B /* SingBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032158BB2ADDFD09008D943B /* SingBox.swift */; };
|
||||
03B516672AE6B93A00EA47E2 /* MethodHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B516662AE6B93A00EA47E2 /* MethodHandler.swift */; };
|
||||
03B516692AE7306B00EA47E2 /* StatusEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B516682AE7306B00EA47E2 /* StatusEventHandler.swift */; };
|
||||
03B5166B2AE7315E00EA47E2 /* AlertsEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B5166A2AE7315E00EA47E2 /* AlertsEventHandler.swift */; };
|
||||
03B5166D2AE7325500EA47E2 /* LogsEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B5166C2AE7325500EA47E2 /* LogsEventHandler.swift */; };
|
||||
03B516712AE74CCD00EA47E2 /* VPNConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B516702AE74CCD00EA47E2 /* VPNConfig.swift */; };
|
||||
03B516742AE74D2200EA47E2 /* Stored.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B516732AE74D2200EA47E2 /* Stored.swift */; };
|
||||
03B516762AE762F700EA47E2 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B516752AE762F700EA47E2 /* Logger.swift */; };
|
||||
03B516772AE7634400EA47E2 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B516752AE762F700EA47E2 /* Logger.swift */; };
|
||||
03B5167B2AE79DB400EA47E2 /* FileMethodHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B5167A2AE79DB400EA47E2 /* FileMethodHandler.swift */; };
|
||||
03B5167D2AE7AC6200EA47E2 /* GroupsEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B5167C2AE7AC6200EA47E2 /* GroupsEventHandler.swift */; };
|
||||
03E392B82ADDA00E000ADF15 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E392B72ADDA00E000ADF15 /* NetworkExtension.framework */; };
|
||||
03E392BB2ADDA00F000ADF15 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E392BA2ADDA00F000ADF15 /* PacketTunnelProvider.swift */; };
|
||||
03E392C02ADDA00F000ADF15 /* SingBoxPacketTunnel.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 03E392B62ADDA00E000ADF15 /* SingBoxPacketTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
03E392C92ADDA713000ADF15 /* libcore.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E392C82ADDA713000ADF15 /* libcore.xcframework */; };
|
||||
03E392CC2ADDE078000ADF15 /* ExtensionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E392CB2ADDE078000ADF15 /* ExtensionProvider.swift */; };
|
||||
03E392CF2ADDEFC8000ADF15 /* FilePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E392CE2ADDEFC8000ADF15 /* FilePath.swift */; };
|
||||
03E392D02ADDF1BD000ADF15 /* FilePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E392CE2ADDEFC8000ADF15 /* FilePath.swift */; };
|
||||
03E392D22ADDF1F4000ADF15 /* ExtensionPlatformInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E392D12ADDF1F4000ADF15 /* ExtensionPlatformInterface.swift */; };
|
||||
03E392D42ADDF262000ADF15 /* Extension+RunBlocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E392D32ADDF262000ADF15 /* Extension+RunBlocking.swift */; };
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
54EA599BF9C050F2827533D5 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDA50BDF2E5E5DDA3995F24D /* Pods_RunnerTests.framework */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
8387F5E3B7CDC68F5506057F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60F1D4AAC33ACF5C8307310D /* Pods_Runner.framework */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
03E392BE2ADDA00F000ADF15 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 03E392B52ADDA00E000ADF15;
|
||||
remoteInfo = SingBoxPacketTunnel;
|
||||
};
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
@@ -27,6 +58,17 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
03E392C12ADDA00F000ADF15 /* Embed Foundation Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
03E392C02ADDA00F000ADF15 /* SingBoxPacketTunnel.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -40,12 +82,43 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
032158B72ADDF8BF008D943B /* VPNManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNManager.swift; sourceTree = "<group>"; };
|
||||
032158B92ADDFCC9008D943B /* TrafficReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrafficReader.swift; sourceTree = "<group>"; };
|
||||
032158BB2ADDFD09008D943B /* SingBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingBox.swift; sourceTree = "<group>"; };
|
||||
03B516662AE6B93A00EA47E2 /* MethodHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MethodHandler.swift; sourceTree = "<group>"; };
|
||||
03B516682AE7306B00EA47E2 /* StatusEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEventHandler.swift; sourceTree = "<group>"; };
|
||||
03B5166A2AE7315E00EA47E2 /* AlertsEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertsEventHandler.swift; sourceTree = "<group>"; };
|
||||
03B5166C2AE7325500EA47E2 /* LogsEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogsEventHandler.swift; sourceTree = "<group>"; };
|
||||
03B516702AE74CCD00EA47E2 /* VPNConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNConfig.swift; sourceTree = "<group>"; };
|
||||
03B516732AE74D2200EA47E2 /* Stored.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stored.swift; sourceTree = "<group>"; };
|
||||
03B516752AE762F700EA47E2 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||
03B5167A2AE79DB400EA47E2 /* FileMethodHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMethodHandler.swift; sourceTree = "<group>"; };
|
||||
03B5167C2AE7AC6200EA47E2 /* GroupsEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupsEventHandler.swift; sourceTree = "<group>"; };
|
||||
03E392B62ADDA00E000ADF15 /* SingBoxPacketTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SingBoxPacketTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
03E392B72ADDA00E000ADF15 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
|
||||
03E392BA2ADDA00F000ADF15 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; };
|
||||
03E392BC2ADDA00F000ADF15 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
03E392BD2ADDA00F000ADF15 /* SingBoxPacketTunnel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SingBoxPacketTunnel.entitlements; sourceTree = "<group>"; };
|
||||
03E392C62ADDA064000ADF15 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
|
||||
03E392C72ADDA26A000ADF15 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
03E392C82ADDA713000ADF15 /* libcore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libcore.xcframework; path = ../libcore/bin/libcore.xcframework; sourceTree = "<group>"; };
|
||||
03E392CB2ADDE078000ADF15 /* ExtensionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionProvider.swift; sourceTree = "<group>"; };
|
||||
03E392CE2ADDEFC8000ADF15 /* FilePath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePath.swift; sourceTree = "<group>"; };
|
||||
03E392D12ADDF1F4000ADF15 /* ExtensionPlatformInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPlatformInterface.swift; sourceTree = "<group>"; };
|
||||
03E392D32ADDF262000ADF15 /* Extension+RunBlocking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extension+RunBlocking.swift"; sourceTree = "<group>"; };
|
||||
0F7E04B7207513677AF77112 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
574F12C7748958784380337F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
60F1D4AAC33ACF5C8307310D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7E8B7AF73AD416B8FAA5E9B0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
90E93DE403BDFA627F3AA51E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -53,30 +126,114 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9A37A927A1A9458918B3C12A /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C20A211B58CE31B2738D133C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
DDA50BDF2E5E5DDA3995F24D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
03E392B32ADDA00E000ADF15 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
03E392C92ADDA713000ADF15 /* libcore.xcframework in Frameworks */,
|
||||
03E392B82ADDA00E000ADF15 /* NetworkExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
531FE8242BCD501C24C8E9FA /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54EA599BF9C050F2827533D5 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8387F5E3B7CDC68F5506057F /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
032158B62ADDF8AF008D943B /* VPN */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
03B516722AE74D1700EA47E2 /* Helpers */,
|
||||
032158B72ADDF8BF008D943B /* VPNManager.swift */,
|
||||
03B516702AE74CCD00EA47E2 /* VPNConfig.swift */,
|
||||
);
|
||||
name = Flutter;
|
||||
path = VPN;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
03B5166E2AE7325D00EA47E2 /* Handlers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03B516662AE6B93A00EA47E2 /* MethodHandler.swift */,
|
||||
03B5167A2AE79DB400EA47E2 /* FileMethodHandler.swift */,
|
||||
03B516682AE7306B00EA47E2 /* StatusEventHandler.swift */,
|
||||
03B5166A2AE7315E00EA47E2 /* AlertsEventHandler.swift */,
|
||||
03B5166C2AE7325500EA47E2 /* LogsEventHandler.swift */,
|
||||
03B5167C2AE7AC6200EA47E2 /* GroupsEventHandler.swift */,
|
||||
);
|
||||
path = Handlers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
03B516722AE74D1700EA47E2 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03B516732AE74D2200EA47E2 /* Stored.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
03E392B92ADDA00F000ADF15 /* SingBoxPacketTunnel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03E392CA2ADDE063000ADF15 /* SingBox */,
|
||||
03E392BA2ADDA00F000ADF15 /* PacketTunnelProvider.swift */,
|
||||
032158B92ADDFCC9008D943B /* TrafficReader.swift */,
|
||||
03B516752AE762F700EA47E2 /* Logger.swift */,
|
||||
03E392BC2ADDA00F000ADF15 /* Info.plist */,
|
||||
03E392BD2ADDA00F000ADF15 /* SingBoxPacketTunnel.entitlements */,
|
||||
);
|
||||
path = SingBoxPacketTunnel;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
03E392CA2ADDE063000ADF15 /* SingBox */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03E392CB2ADDE078000ADF15 /* ExtensionProvider.swift */,
|
||||
03E392D12ADDF1F4000ADF15 /* ExtensionPlatformInterface.swift */,
|
||||
03E392D32ADDF262000ADF15 /* Extension+RunBlocking.swift */,
|
||||
032158BB2ADDFD09008D943B /* SingBox.swift */,
|
||||
);
|
||||
path = SingBox;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
03E392CD2ADDE103000ADF15 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03E392CE2ADDEFC8000ADF15 /* FilePath.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
311A4F4314861E02331B8DAC /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
574F12C7748958784380337F /* Pods-Runner.debug.xcconfig */,
|
||||
90E93DE403BDFA627F3AA51E /* Pods-Runner.release.xcconfig */,
|
||||
C20A211B58CE31B2738D133C /* Pods-Runner.profile.xcconfig */,
|
||||
7E8B7AF73AD416B8FAA5E9B0 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
9A37A927A1A9458918B3C12A /* Pods-RunnerTests.release.xcconfig */,
|
||||
0F7E04B7207513677AF77112 /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
@@ -87,13 +244,29 @@
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
03E392C62ADDA064000ADF15 /* Base.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03E392CD2ADDE103000ADF15 /* Shared */,
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
03E392B92ADDA00F000ADF15 /* SingBoxPacketTunnel */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
311A4F4314861E02331B8DAC /* Pods */,
|
||||
B8133545EEE13EDD5549E6A3 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -102,6 +275,7 @@
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
03E392B62ADDA00E000ADF15 /* SingBoxPacketTunnel.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -109,28 +283,60 @@
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03B5166E2AE7325D00EA47E2 /* Handlers */,
|
||||
032158B62ADDF8AF008D943B /* VPN */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
03E392C72ADDA26A000ADF15 /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B8133545EEE13EDD5549E6A3 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
60F1D4AAC33ACF5C8307310D /* Pods_Runner.framework */,
|
||||
DDA50BDF2E5E5DDA3995F24D /* Pods_RunnerTests.framework */,
|
||||
03E392B72ADDA00E000ADF15 /* NetworkExtension.framework */,
|
||||
03E392C82ADDA713000ADF15 /* libcore.xcframework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
03E392B52ADDA00E000ADF15 /* SingBoxPacketTunnel */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 03E392C52ADDA00F000ADF15 /* Build configuration list for PBXNativeTarget "SingBoxPacketTunnel" */;
|
||||
buildPhases = (
|
||||
03E392B22ADDA00E000ADF15 /* Sources */,
|
||||
03E392B32ADDA00E000ADF15 /* Frameworks */,
|
||||
03E392B42ADDA00E000ADF15 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = SingBoxPacketTunnel;
|
||||
productName = SingBoxPacketTunnel;
|
||||
productReference = 03E392B62ADDA00E000ADF15 /* SingBoxPacketTunnel.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
F63DAC79B8A3B6681959DBC1 /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807E294A63A400263BE5 /* Frameworks */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
531FE8242BCD501C24C8E9FA /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -146,16 +352,20 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
B971F0749B278D190A7A7315 /* [CP] Check Pods Manifest.lock */,
|
||||
03E392C12ADDA00F000ADF15 /* Embed Foundation Extensions */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
FBEFD3291AEA65EDE2F5AEF6 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
03E392BF2ADDA00F000ADF15 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
@@ -168,9 +378,13 @@
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
LastSwiftUpdateCheck = 1500;
|
||||
LastUpgradeCheck = 1430;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
03E392B52ADDA00E000ADF15 = {
|
||||
CreatedOnToolsVersion = 15.0;
|
||||
};
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
@@ -196,11 +410,19 @@
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
03E392B52ADDA00E000ADF15 /* SingBoxPacketTunnel */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
03E392B42ADDA00E000ADF15 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -236,7 +458,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -251,11 +473,87 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
|
||||
};
|
||||
B971F0749B278D190A7A7315 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F63DAC79B8A3B6681959DBC1 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FBEFD3291AEA65EDE2F5AEF6 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
03E392B22ADDA00E000ADF15 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
032158BA2ADDFCC9008D943B /* TrafficReader.swift in Sources */,
|
||||
032158BC2ADDFD09008D943B /* SingBox.swift in Sources */,
|
||||
03E392D22ADDF1F4000ADF15 /* ExtensionPlatformInterface.swift in Sources */,
|
||||
03E392CC2ADDE078000ADF15 /* ExtensionProvider.swift in Sources */,
|
||||
03E392BB2ADDA00F000ADF15 /* PacketTunnelProvider.swift in Sources */,
|
||||
03E392CF2ADDEFC8000ADF15 /* FilePath.swift in Sources */,
|
||||
03E392D42ADDF262000ADF15 /* Extension+RunBlocking.swift in Sources */,
|
||||
03B516762AE762F700EA47E2 /* Logger.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -268,14 +566,30 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
03B516742AE74D2200EA47E2 /* Stored.swift in Sources */,
|
||||
03B5167B2AE79DB400EA47E2 /* FileMethodHandler.swift in Sources */,
|
||||
03B516772AE7634400EA47E2 /* Logger.swift in Sources */,
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
03B516712AE74CCD00EA47E2 /* VPNConfig.swift in Sources */,
|
||||
03B5166B2AE7315E00EA47E2 /* AlertsEventHandler.swift in Sources */,
|
||||
03B516692AE7306B00EA47E2 /* StatusEventHandler.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
032158B82ADDF8BF008D943B /* VPNManager.swift in Sources */,
|
||||
03B516672AE6B93A00EA47E2 /* MethodHandler.swift in Sources */,
|
||||
03B5166D2AE7325500EA47E2 /* LogsEventHandler.swift in Sources */,
|
||||
03E392D02ADDF1BD000ADF15 /* FilePath.swift in Sources */,
|
||||
03B5167D2AE7AC6200EA47E2 /* GroupsEventHandler.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
03E392BF2ADDA00F000ADF15 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 03E392B52ADDA00E000ADF15 /* SingBoxPacketTunnel */;
|
||||
targetProxy = 03E392BE2ADDA00F000ADF15 /* PBXContainerItemProxy */;
|
||||
};
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
@@ -303,6 +617,123 @@
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
03E392C22ADDA00F000ADF15 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 03E392C62ADDA064000ADF15 /* Base.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = SingBoxPacketTunnel/SingBoxPacketTunnel.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SingBoxPacketTunnel/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SingBoxPacketTunnel;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).SingBoxPacketTunnel";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
03E392C32ADDA00F000ADF15 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 03E392C62ADDA064000ADF15 /* Base.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = SingBoxPacketTunnel/SingBoxPacketTunnel.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SingBoxPacketTunnel/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SingBoxPacketTunnel;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).SingBoxPacketTunnel";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
03E392C42ADDA00F000ADF15 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 03E392C62ADDA064000ADF15 /* Base.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = SingBoxPacketTunnel/SingBoxPacketTunnel.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SingBoxPacketTunnel/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SingBoxPacketTunnel;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).SingBoxPacketTunnel";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -344,7 +775,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -357,8 +788,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -366,7 +799,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.hiddify;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -376,14 +809,14 @@
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */;
|
||||
baseConfigurationReference = 7E8B7AF73AD416B8FAA5E9B0 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.hiddify.RunnerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.next.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -394,14 +827,14 @@
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */;
|
||||
baseConfigurationReference = 9A37A927A1A9458918B3C12A /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.hiddify.RunnerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.next.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
@@ -410,14 +843,14 @@
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */;
|
||||
baseConfigurationReference = 0F7E04B7207513677AF77112 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.hiddify.RunnerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.next.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
@@ -471,7 +904,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -520,7 +953,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -535,8 +968,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -544,7 +979,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.hiddify;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -557,8 +992,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -566,7 +1003,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hiddify.hiddify;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -577,6 +1014,16 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
03E392C52ADDA00F000ADF15 /* Build configuration list for PBXNativeTarget "SingBoxPacketTunnel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
03E392C22ADDA00F000ADF15 /* Debug */,
|
||||
03E392C32ADDA00F000ADF15 /* Release */,
|
||||
03E392C42ADDA00F000ADF15 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,13 +1,35 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
import Libcore
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
|
||||
setupFileManager()
|
||||
|
||||
registerHandlers()
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
func setupFileManager() {
|
||||
try? FileManager.default.createDirectory(at: FilePath.workingDirectory, withIntermediateDirectories: true)
|
||||
FileManager.default.changeCurrentDirectoryPath(FilePath.sharedDirectory.path)
|
||||
}
|
||||
|
||||
func registerHandlers() {
|
||||
MethodHandler.register(with: self.registrar(forPlugin: MethodHandler.name)!)
|
||||
FileMethodHandler.register(with: self.registrar(forPlugin: FileMethodHandler.name)!)
|
||||
StatusEventHandler.register(with: self.registrar(forPlugin: StatusEventHandler.name)!)
|
||||
AlertsEventHandler.register(with: self.registrar(forPlugin: AlertsEventHandler.name)!)
|
||||
LogsEventHandler.register(with: self.registrar(forPlugin: LogsEventHandler.name)!)
|
||||
GroupsEventHandler.register(with: self.registrar(forPlugin: GroupsEventHandler.name)!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
@@ -14,13 +16,14 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-26" y="-77"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
||||
45
ios/Runner/Handlers/AlertsEventHandler.swift
Normal file
45
ios/Runner/Handlers/AlertsEventHandler.swift
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// AlertEventHandler.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
public class AlertsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler {
|
||||
static let name = "\(FilePath.packageName)/service.alerts"
|
||||
|
||||
private var channel: FlutterEventChannel?
|
||||
|
||||
private var cancellable: AnyCancellable?
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let instance = AlertsEventHandler()
|
||||
instance.channel = FlutterEventChannel(name: Self.name, binaryMessenger: registrar.messenger())
|
||||
instance.channel?.setStreamHandler(instance)
|
||||
}
|
||||
|
||||
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
||||
cancellable = VPNManager.shared.$alert.sink { [events] alert in
|
||||
var data = [
|
||||
"status": "Stopped",
|
||||
"alert": alert.alert?.rawValue,
|
||||
"message": alert.message,
|
||||
]
|
||||
for key in data.keys {
|
||||
if data[key] == nil {
|
||||
data.removeValue(forKey: key)
|
||||
}
|
||||
}
|
||||
events(data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
||||
cancellable?.cancel()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
35
ios/Runner/Handlers/FileMethodHandler.swift
Normal file
35
ios/Runner/Handlers/FileMethodHandler.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// FileMethodHandler.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class FileMethodHandler: NSObject, FlutterPlugin {
|
||||
|
||||
public static let name = "\(FilePath.packageName)/files.method"
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: Self.name, binaryMessenger: registrar.messenger())
|
||||
let instance = FileMethodHandler()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
instance.channel = channel
|
||||
}
|
||||
|
||||
private var channel: FlutterMethodChannel?
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "get_paths":
|
||||
result([
|
||||
"working": FilePath.workingDirectory.path,
|
||||
"temp": FilePath.cacheDirectory.path,
|
||||
"base": FilePath.sharedDirectory.path
|
||||
])
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
93
ios/Runner/Handlers/GroupsEventHandler.swift
Normal file
93
ios/Runner/Handlers/GroupsEventHandler.swift
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// GroupsEventHandler.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
|
||||
struct SBItem: Codable {
|
||||
let tag: String
|
||||
let type: String
|
||||
let urlTestDelay: Int
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case tag
|
||||
case type
|
||||
case urlTestDelay = "url-test-delay"
|
||||
}
|
||||
}
|
||||
|
||||
struct SBGroup: Codable {
|
||||
let tag: String
|
||||
let type: String
|
||||
let selected: String
|
||||
let items: [SBItem]
|
||||
}
|
||||
|
||||
public class GroupsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler, LibboxCommandClientHandlerProtocol {
|
||||
|
||||
static let name = "\(FilePath.packageName)/groups"
|
||||
|
||||
private var channel: FlutterEventChannel?
|
||||
|
||||
var commandClient: LibboxCommandClient?
|
||||
var events: FlutterEventSink?
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let instance = GroupsEventHandler()
|
||||
instance.channel = FlutterEventChannel(name: Self.name, binaryMessenger: registrar.messenger())
|
||||
instance.channel?.setStreamHandler(instance)
|
||||
}
|
||||
|
||||
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
||||
FileManager.default.changeCurrentDirectoryPath(FilePath.sharedDirectory.path)
|
||||
self.events = events
|
||||
let opts = LibboxCommandClientOptions()
|
||||
opts.command = LibboxCommandGroup
|
||||
opts.statusInterval = 3000
|
||||
commandClient = LibboxCommandClient(self, options: opts)
|
||||
try? commandClient?.connect()
|
||||
return nil
|
||||
}
|
||||
|
||||
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
||||
try? commandClient?.disconnect()
|
||||
return nil
|
||||
}
|
||||
|
||||
public func writeGroups(_ message: LibboxOutboundGroupIteratorProtocol?) {
|
||||
guard let message else { return }
|
||||
var groups = [SBGroup]()
|
||||
while message.hasNext() {
|
||||
let group = message.next()!
|
||||
var items = [SBItem]()
|
||||
var groupItems = group.getItems()
|
||||
while groupItems?.hasNext() ?? false {
|
||||
let item = groupItems?.next()!
|
||||
items.append(SBItem(tag: item!.tag, type: item!.type, urlTestDelay: Int(item!.urlTestDelay)))
|
||||
}
|
||||
groups.append(.init(tag: group.tag, type: group.type, selected: group.selected, items: items))
|
||||
}
|
||||
if
|
||||
let groups = try? JSONEncoder().encode(groups),
|
||||
let groups = String(data: groups, encoding: .utf8)
|
||||
{
|
||||
DispatchQueue.main.async { [events = self.events, groups] () in
|
||||
events?(groups)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension GroupsEventHandler {
|
||||
public func clearLog() {}
|
||||
public func connected() {}
|
||||
public func disconnected(_ message: String?) {}
|
||||
public func initializeClashMode(_ modeList: LibboxStringIteratorProtocol?, currentMode: String?) {}
|
||||
public func updateClashMode(_ newMode: String?) {}
|
||||
public func writeLog(_ message: String?) {}
|
||||
public func writeStatus(_ message: LibboxStatusMessage?) {}
|
||||
}
|
||||
28
ios/Runner/Handlers/LogsEventHandler.swift
Normal file
28
ios/Runner/Handlers/LogsEventHandler.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// LogsEventHandler.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class LogsEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler {
|
||||
static let name = "\(FilePath.packageName)/service.logs"
|
||||
|
||||
private var channel: FlutterEventChannel?
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let instance = LogsEventHandler()
|
||||
instance.channel = FlutterEventChannel(name: Self.name, binaryMessenger: registrar.messenger())
|
||||
instance.channel?.setStreamHandler(instance)
|
||||
}
|
||||
|
||||
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
||||
return nil
|
||||
}
|
||||
|
||||
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
180
ios/Runner/Handlers/MethodHandler.swift
Normal file
180
ios/Runner/Handlers/MethodHandler.swift
Normal file
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// MethodHandler.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/23/23.
|
||||
//
|
||||
|
||||
import Flutter
|
||||
import Combine
|
||||
import Libcore
|
||||
|
||||
public class MethodHandler: NSObject, FlutterPlugin {
|
||||
|
||||
private var cancelBag: Set<AnyCancellable> = []
|
||||
|
||||
public static let name = "\(FilePath.packageName)/method"
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: Self.name, binaryMessenger: registrar.messenger())
|
||||
let instance = MethodHandler()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
instance.channel = channel
|
||||
}
|
||||
|
||||
private var channel: FlutterMethodChannel?
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "parse_config":
|
||||
result(parseConfig(args: call.arguments))
|
||||
case "change_config_options":
|
||||
result(changeConfigOptions(args: call.arguments))
|
||||
case "start":
|
||||
Task { [unowned self] in
|
||||
let res = await start(args: call.arguments)
|
||||
await MainActor.run {
|
||||
result(res)
|
||||
}
|
||||
}
|
||||
case "restart":
|
||||
Task { [unowned self] in
|
||||
let res = await restart(args: call.arguments)
|
||||
await MainActor.run {
|
||||
result(res)
|
||||
}
|
||||
}
|
||||
case "stop":
|
||||
result(stop())
|
||||
case "url_test":
|
||||
result(urlTest(args: call.arguments))
|
||||
case "select_outbound":
|
||||
result(selectOutbound(args: call.arguments))
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
public func parseConfig(args: Any?) -> String {
|
||||
var error: NSError?
|
||||
guard
|
||||
let args = args as? [String:Any?],
|
||||
let path = args["path"] as? String,
|
||||
let tempPath = args["tempPath"] as? String,
|
||||
let debug = (args["debug"] as? NSNumber)?.boolValue
|
||||
else {
|
||||
return "bad method format"
|
||||
}
|
||||
let res = MobileParse(path, tempPath, debug, &error)
|
||||
if let error {
|
||||
return error.localizedDescription
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
public func changeConfigOptions(args: Any?) -> Bool {
|
||||
guard let options = args as? String else {
|
||||
return false
|
||||
}
|
||||
VPNConfig.shared.configOptions = options
|
||||
return true
|
||||
}
|
||||
|
||||
public func start(args: Any?) async -> Bool {
|
||||
guard
|
||||
let args = args as? [String:Any?],
|
||||
let path = args["path"] as? String
|
||||
else {
|
||||
return false
|
||||
}
|
||||
VPNConfig.shared.activeConfigPath = path
|
||||
var error: NSError?
|
||||
let config = MobileBuildConfig(path, VPNConfig.shared.configOptions, &error)
|
||||
if let error {
|
||||
return false
|
||||
}
|
||||
do {
|
||||
try await VPNManager.shared.setup()
|
||||
try await VPNManager.shared.connect(with: config, disableMemoryLimit: VPNConfig.shared.disableMemoryLimit)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public func stop() -> Bool {
|
||||
VPNManager.shared.disconnect()
|
||||
return true
|
||||
}
|
||||
|
||||
private func waitForStop() -> Future<Void, Never> {
|
||||
return Future { promise in
|
||||
var cancellable: AnyCancellable? = nil
|
||||
cancellable = VPNManager.shared.$state
|
||||
.filter { $0 == .disconnected }
|
||||
.first()
|
||||
.delay(for: 0.5, scheduler: RunLoop.current)
|
||||
.sink(receiveValue: { _ in
|
||||
promise(.success(()))
|
||||
cancellable?.cancel()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func restart(args: Any?) async -> Bool {
|
||||
guard
|
||||
let args = args as? [String:Any?],
|
||||
let path = args["path"] as? String
|
||||
else {
|
||||
return false
|
||||
}
|
||||
VPNConfig.shared.activeConfigPath = path
|
||||
VPNManager.shared.disconnect()
|
||||
await waitForStop().value
|
||||
var error: NSError?
|
||||
let config = MobileBuildConfig(path, VPNConfig.shared.configOptions, &error)
|
||||
if let error {
|
||||
return false
|
||||
}
|
||||
do {
|
||||
try await VPNManager.shared.setup()
|
||||
try await VPNManager.shared.connect(with: config, disableMemoryLimit: VPNConfig.shared.disableMemoryLimit)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public func selectOutbound(args: Any?) -> Bool {
|
||||
guard
|
||||
let args = args as? [String:Any?],
|
||||
let group = args["groupTag"] as? String,
|
||||
let outbound = args["outboundTag"] as? String
|
||||
else {
|
||||
return false
|
||||
}
|
||||
FileManager.default.changeCurrentDirectoryPath(FilePath.sharedDirectory.path)
|
||||
do {
|
||||
try LibboxNewStandaloneCommandClient()?.selectOutbound(group, outboundTag: outbound)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public func urlTest(args: Any?) -> Bool {
|
||||
guard
|
||||
let args = args as? [String:Any?]
|
||||
else {
|
||||
return false
|
||||
}
|
||||
let group = args["groupTag"] as? String
|
||||
FileManager.default.changeCurrentDirectoryPath(FilePath.sharedDirectory.path)
|
||||
do {
|
||||
try LibboxNewStandaloneCommandClient()?.urlTest(group)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
46
ios/Runner/Handlers/StatusEventHandler.swift
Normal file
46
ios/Runner/Handlers/StatusEventHandler.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// StatusEventHandler.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
public class StatusEventHandler: NSObject, FlutterPlugin, FlutterStreamHandler {
|
||||
static let name = "\(FilePath.packageName)/service.status"
|
||||
|
||||
private var channel: FlutterEventChannel?
|
||||
|
||||
private var cancellable: AnyCancellable?
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let instance = StatusEventHandler()
|
||||
instance.channel = FlutterEventChannel(name: Self.name, binaryMessenger: registrar.messenger())
|
||||
instance.channel?.setStreamHandler(instance)
|
||||
}
|
||||
|
||||
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
||||
cancellable = VPNManager.shared.$state.sink { [events] status in
|
||||
switch status {
|
||||
case .reasserting, .connecting:
|
||||
events(["status": "Starting"])
|
||||
case .connected:
|
||||
events(["status": "Started"])
|
||||
case .disconnecting:
|
||||
events(["status": "Stopping"])
|
||||
case .disconnected, .invalid:
|
||||
events(["status": "Stopped"])
|
||||
@unknown default:
|
||||
events(["status": "Stopped"])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
||||
cancellable?.cancel()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Hiddify Next</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Hiddify Next</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BASE_BUNDLE_IDENTIFIER</key>
|
||||
<string>$(BASE_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Hiddify Next</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Hiddify Next</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
14
ios/Runner/Runner.entitlements
Normal file
14
ios/Runner/Runner.entitlements
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.$(BASE_BUNDLE_IDENTIFIER)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
86
ios/Runner/VPN/Helpers/Stored.swift
Normal file
86
ios/Runner/VPN/Helpers/Stored.swift
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Stored.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
enum StoredLocation {
|
||||
case standard
|
||||
|
||||
func data(for key: String) -> Data? {
|
||||
switch self {
|
||||
case .standard:
|
||||
return UserDefaults.standard.data(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
func set(_ value: Data, for key: String) {
|
||||
switch self {
|
||||
case .standard:
|
||||
UserDefaults.standard.set(value, forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@propertyWrapper
|
||||
struct Stored<Value: Codable> {
|
||||
let location: StoredLocation
|
||||
let key: String
|
||||
var wrappedValue: Value {
|
||||
willSet { // Before modifying wrappedValue
|
||||
publisher.subject.send(newValue)
|
||||
guard let value = try? JSONEncoder().encode(newValue) else {
|
||||
return
|
||||
}
|
||||
location.set(value, for: key)
|
||||
}
|
||||
}
|
||||
|
||||
var projectedValue: Publisher {
|
||||
publisher
|
||||
}
|
||||
private var publisher: Publisher
|
||||
struct Publisher: Combine.Publisher {
|
||||
typealias Output = Value
|
||||
typealias Failure = Never
|
||||
var subject: CurrentValueSubject<Value, Never> // PassthroughSubject will lack the call of initial assignment
|
||||
func receive<S>(subscriber: S) where S: Subscriber, Self.Failure == S.Failure, Self.Output == S.Input {
|
||||
subject.subscribe(subscriber)
|
||||
}
|
||||
init(_ output: Output) {
|
||||
subject = .init(output)
|
||||
}
|
||||
}
|
||||
init(wrappedValue: Value, key: String, in location: StoredLocation = .standard) {
|
||||
self.location = location
|
||||
self.key = key
|
||||
var value = wrappedValue
|
||||
if let data = location.data(for: key) {
|
||||
do {
|
||||
value = try JSONDecoder().decode(Value.self, from: data)
|
||||
} catch {}
|
||||
}
|
||||
self.wrappedValue = value
|
||||
publisher = Publisher(value)
|
||||
}
|
||||
static subscript<OuterSelf: ObservableObject>(
|
||||
_enclosingInstance observed: OuterSelf,
|
||||
wrapped wrappedKeyPath: ReferenceWritableKeyPath<OuterSelf, Value>,
|
||||
storage storageKeyPath: ReferenceWritableKeyPath<OuterSelf, Self>
|
||||
) -> Value {
|
||||
get {
|
||||
observed[keyPath: storageKeyPath].wrappedValue
|
||||
}
|
||||
set {
|
||||
if let subject = observed.objectWillChange as? ObservableObjectPublisher {
|
||||
subject.send() // Before modifying wrappedValue
|
||||
observed[keyPath: storageKeyPath].wrappedValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
ios/Runner/VPN/VPNConfig.swift
Normal file
22
ios/Runner/VPN/VPNConfig.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// VPNConfig.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
class VPNConfig: ObservableObject {
|
||||
static let shared = VPNConfig()
|
||||
|
||||
@Stored(key: "VPN.ActiveConfigPath")
|
||||
var activeConfigPath: String = ""
|
||||
|
||||
@Stored(key: "VPN.ConfigOptions")
|
||||
var configOptions: String = ""
|
||||
|
||||
@Stored(key: "VPN.DisableMemoryLimit")
|
||||
var disableMemoryLimit: Bool = false
|
||||
}
|
||||
192
ios/Runner/VPN/VPNManager.swift
Normal file
192
ios/Runner/VPN/VPNManager.swift
Normal file
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// VPNManager.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import NetworkExtension
|
||||
|
||||
enum VPNManagerAlertType: String {
|
||||
case RequestVPNPermission
|
||||
case RequestNotificationPermission
|
||||
case EmptyConfiguration
|
||||
case StartCommandServer
|
||||
case CreateService
|
||||
case StartService
|
||||
}
|
||||
|
||||
struct VPNManagerAlert {
|
||||
let alert: VPNManagerAlertType?
|
||||
let message: String?
|
||||
}
|
||||
|
||||
class VPNManager: ObservableObject {
|
||||
private var cancelBag: Set<AnyCancellable> = []
|
||||
|
||||
private var observer: NSObjectProtocol?
|
||||
private var manager = NEVPNManager.shared()
|
||||
private var loaded: Bool = false
|
||||
private var timer: Timer?
|
||||
|
||||
static let shared: VPNManager = VPNManager()
|
||||
|
||||
@Published private(set) var state: NEVPNStatus = .invalid
|
||||
@Published private(set) var alert: VPNManagerAlert = .init(alert: nil, message: nil)
|
||||
|
||||
@Published private(set) var upload: Int64 = 0
|
||||
@Published private(set) var download: Int64 = 0
|
||||
@Published private(set) var elapsedTime: TimeInterval = 0
|
||||
|
||||
private var _connectTime: Date?
|
||||
private var connectTime: Date? {
|
||||
set {
|
||||
UserDefaults(suiteName: FilePath.groupName)?.set(newValue?.timeIntervalSince1970, forKey: "SingBoxConnectTime")
|
||||
_connectTime = newValue
|
||||
}
|
||||
get {
|
||||
if let _connectTime {
|
||||
return _connectTime
|
||||
}
|
||||
guard let interval = UserDefaults(suiteName: FilePath.groupName)?.value(forKey: "SingBoxConnectTime") as? TimeInterval else {
|
||||
return nil
|
||||
}
|
||||
return Date(timeIntervalSince1970: interval)
|
||||
}
|
||||
}
|
||||
private var readingWS: Bool = false
|
||||
|
||||
@Published var isConnectedToAnyVPN: Bool = false
|
||||
|
||||
init() {
|
||||
observer = NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil) { [weak self] notification in
|
||||
guard let connection = notification.object as? NEVPNConnection else { return }
|
||||
self?.state = connection.status
|
||||
}
|
||||
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
|
||||
guard let self else { return }
|
||||
updateStats()
|
||||
elapsedTime = -1 * (connectTime?.timeIntervalSinceNow ?? 0)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
if let observer {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
timer?.invalidate()
|
||||
}
|
||||
|
||||
func setup() async throws {
|
||||
// guard !loaded else { return }
|
||||
loaded = true
|
||||
try await loadVPNPreference()
|
||||
}
|
||||
|
||||
private func loadVPNPreference() async throws {
|
||||
let managers = try await NETunnelProviderManager.loadAllFromPreferences()
|
||||
if let manager = managers.first {
|
||||
self.manager = manager
|
||||
return
|
||||
}
|
||||
let newManager = NETunnelProviderManager()
|
||||
let `protocol` = NETunnelProviderProtocol()
|
||||
`protocol`.providerBundleIdentifier = "\(FilePath.packageName).SingBoxPacketTunnel"
|
||||
`protocol`.serverAddress = "Hiddify"
|
||||
newManager.protocolConfiguration = `protocol`
|
||||
newManager.localizedDescription = "Hiddify"
|
||||
try await newManager.saveToPreferences()
|
||||
try await newManager.loadFromPreferences()
|
||||
self.manager = newManager
|
||||
}
|
||||
|
||||
private func enableVPNManager() async throws {
|
||||
manager.isEnabled = true
|
||||
try await manager.saveToPreferences()
|
||||
try await manager.loadFromPreferences()
|
||||
}
|
||||
|
||||
@MainActor private func set(upload: Int64, download: Int64) {
|
||||
self.upload = upload
|
||||
self.download = download
|
||||
}
|
||||
|
||||
var isAnyVPNConnected: Bool {
|
||||
let cfDict = CFNetworkCopySystemProxySettings()
|
||||
let nsDict = cfDict!.takeRetainedValue() as NSDictionary
|
||||
guard let keys = nsDict["__SCOPED__"] as? NSDictionary else {
|
||||
return false
|
||||
}
|
||||
for key: String in keys.allKeys as! [String] {
|
||||
if (key == "tap" || key == "tun" || key == "ppp" || key == "ipsec" || key == "ipsec0" || key == "utun1" || key == "utun2") {
|
||||
return true
|
||||
} else if key.starts(with: "utun") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func reset() {
|
||||
loaded = false
|
||||
if state != .disconnected && state != .invalid {
|
||||
disconnect()
|
||||
}
|
||||
$state.filter { $0 == .disconnected || $0 == .invalid }.first().sink { [weak self] _ in
|
||||
Task { [weak self] () in
|
||||
self?.manager = .shared()
|
||||
let managers = try? await NETunnelProviderManager.loadAllFromPreferences()
|
||||
for manager in managers ?? [] {
|
||||
try? await manager.removeFromPreferences()
|
||||
}
|
||||
try? await self?.loadVPNPreference()
|
||||
}
|
||||
}.store(in: &cancelBag)
|
||||
|
||||
}
|
||||
|
||||
private func updateStats() {
|
||||
let isAnyVPNConnected = self.isAnyVPNConnected
|
||||
if isConnectedToAnyVPN != isAnyVPNConnected {
|
||||
isConnectedToAnyVPN = isAnyVPNConnected
|
||||
}
|
||||
guard state == .connected else { return }
|
||||
guard let connection = manager.connection as? NETunnelProviderSession else { return }
|
||||
try? connection.sendProviderMessage("stats".data(using: .utf8)!) { [weak self] response in
|
||||
guard
|
||||
let response,
|
||||
let response = String(data: response, encoding: .utf8)
|
||||
else { return }
|
||||
let responseComponents = response.components(separatedBy: ",")
|
||||
guard
|
||||
responseComponents.count == 2,
|
||||
let upload = Int64(responseComponents[0]),
|
||||
let download = Int64(responseComponents[1])
|
||||
else { return }
|
||||
Task { [upload, download, weak self] () in
|
||||
await self?.set(upload: upload, download: download)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func connect(with config: String, disableMemoryLimit: Bool = false) async throws {
|
||||
await set(upload: 0, download: 0)
|
||||
guard state == .disconnected else { return }
|
||||
try await enableVPNManager()
|
||||
try manager.connection.startVPNTunnel(options: [
|
||||
"Config": config as NSString,
|
||||
"DisableMemoryLimit": (disableMemoryLimit ? "YES" : "NO") as NSString,
|
||||
])
|
||||
connectTime = .now
|
||||
}
|
||||
|
||||
func disconnect() {
|
||||
guard state == .connected else { return }
|
||||
manager.connection.stopVPNTunnel()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
38
ios/Shared/FilePath.swift
Normal file
38
ios/Shared/FilePath.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// FilePath.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum FilePath {
|
||||
public static let packageName = {
|
||||
Bundle.main.infoDictionary?["BASE_BUNDLE_IDENTIFIER"] as? String ?? "unknown"
|
||||
}()
|
||||
}
|
||||
|
||||
public extension FilePath {
|
||||
static let groupName = "group.\(packageName)"
|
||||
|
||||
private static let defaultSharedDirectory: URL! = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: FilePath.groupName)
|
||||
|
||||
static let sharedDirectory = defaultSharedDirectory!
|
||||
|
||||
static let cacheDirectory = sharedDirectory
|
||||
.appendingPathComponent("Library", isDirectory: true)
|
||||
.appendingPathComponent("Caches", isDirectory: true)
|
||||
|
||||
static let workingDirectory = cacheDirectory.appendingPathComponent("Working", isDirectory: true)
|
||||
}
|
||||
|
||||
public extension URL {
|
||||
var fileName: String {
|
||||
var path = relativePath
|
||||
if let index = path.lastIndex(of: "/") {
|
||||
path = String(path[path.index(index, offsetBy: 1)...])
|
||||
}
|
||||
return path
|
||||
}
|
||||
}
|
||||
15
ios/SingBoxPacketTunnel/Info.plist
Normal file
15
ios/SingBoxPacketTunnel/Info.plist
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BASE_BUNDLE_IDENTIFIER</key>
|
||||
<string>$(BASE_BUNDLE_IDENTIFIER)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.networkextension.packet-tunnel</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
52
ios/SingBoxPacketTunnel/Logger.swift
Normal file
52
ios/SingBoxPacketTunnel/Logger.swift
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Logger.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 10/24/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Logger {
|
||||
private static let queue = DispatchQueue.init(label: "\(FilePath.packageName).PacketTunnelLog", qos: .utility)
|
||||
|
||||
private let fileManager = FileManager.default
|
||||
private let url: URL
|
||||
|
||||
private var _fileHandle: FileHandle?
|
||||
private var fileHandle: FileHandle? {
|
||||
get {
|
||||
if let _fileHandle { return _fileHandle }
|
||||
let handle = try? FileHandle(forWritingTo: url)
|
||||
_fileHandle = handle
|
||||
return handle
|
||||
}
|
||||
}
|
||||
|
||||
private var lock = NSLock()
|
||||
|
||||
init(path: URL) {
|
||||
url = path
|
||||
}
|
||||
|
||||
func write(_ message: String) {
|
||||
Logger.queue.async { [message, unowned self] () in
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
let output = message + "\n"
|
||||
do {
|
||||
if !self.fileManager.fileExists(atPath: url.path) {
|
||||
try output.write(to: url, atomically: true, encoding: .utf8)
|
||||
} else {
|
||||
guard let fileHandle else {
|
||||
return
|
||||
}
|
||||
fileHandle.seekToEndOfFile()
|
||||
if let data = output.data(using: .utf8) {
|
||||
fileHandle.write(data)
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
ios/SingBoxPacketTunnel/PacketTunnelProvider.swift
Normal file
37
ios/SingBoxPacketTunnel/PacketTunnelProvider.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// PacketTunnelProvider.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/24/1402 AP.
|
||||
//
|
||||
|
||||
import NetworkExtension
|
||||
|
||||
class PacketTunnelProvider: ExtensionProvider {
|
||||
|
||||
private var upload: Int64 = 0
|
||||
private var download: Int64 = 0
|
||||
// private var trafficLock: NSLock = NSLock()
|
||||
|
||||
// var trafficReader: TrafficReader!
|
||||
|
||||
override func startTunnel(options: [String : NSObject]?) async throws {
|
||||
try await super.startTunnel(options: options)
|
||||
/*trafficReader = TrafficReader { [unowned self] traffic in
|
||||
trafficLock.lock()
|
||||
upload += traffic.up
|
||||
download += traffic.down
|
||||
trafficLock.unlock()
|
||||
}*/
|
||||
}
|
||||
|
||||
override func handleAppMessage(_ messageData: Data) async -> Data? {
|
||||
let message = String(data: messageData, encoding: .utf8)
|
||||
switch message {
|
||||
case "stats":
|
||||
return "\(upload),\(download)".data(using: .utf8)!
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
43
ios/SingBoxPacketTunnel/SingBox/Extension+RunBlocking.swift
Normal file
43
ios/SingBoxPacketTunnel/SingBox/Extension+RunBlocking.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Extension+RunBlocking.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
import NetworkExtension
|
||||
|
||||
func runBlocking<T>(_ block: @escaping () async -> T) -> T {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let box = resultBox<T>()
|
||||
Task.detached {
|
||||
let value = await block()
|
||||
box.result0 = value
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
return box.result0
|
||||
}
|
||||
|
||||
func runBlocking<T>(_ tBlock: @escaping () async throws -> T) throws -> T {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let box = resultBox<T>()
|
||||
Task.detached {
|
||||
do {
|
||||
let value = try await tBlock()
|
||||
box.result = .success(value)
|
||||
} catch {
|
||||
box.result = .failure(error)
|
||||
}
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
return try box.result.get()
|
||||
}
|
||||
|
||||
private class resultBox<T> {
|
||||
var result: Result<T, Error>!
|
||||
var result0: T!
|
||||
}
|
||||
224
ios/SingBoxPacketTunnel/SingBox/ExtensionPlatformInterface.swift
Normal file
224
ios/SingBoxPacketTunnel/SingBox/ExtensionPlatformInterface.swift
Normal file
@@ -0,0 +1,224 @@
|
||||
//
|
||||
// ExtensionPlatformInterface.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
import NetworkExtension
|
||||
|
||||
public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtocol, LibboxCommandServerHandlerProtocol {
|
||||
private let tunnel: ExtensionProvider
|
||||
private var networkSettings: NEPacketTunnelNetworkSettings?
|
||||
|
||||
init(_ tunnel: ExtensionProvider) {
|
||||
self.tunnel = tunnel
|
||||
}
|
||||
|
||||
public func openTun(_ options: LibboxTunOptionsProtocol?, ret0_: UnsafeMutablePointer<Int32>?) throws {
|
||||
try runBlocking { [self] in
|
||||
try await openTun0(options, ret0_)
|
||||
}
|
||||
}
|
||||
|
||||
private func openTun0(_ options: LibboxTunOptionsProtocol?, _ ret0_: UnsafeMutablePointer<Int32>?) async throws {
|
||||
guard let options else {
|
||||
throw NSError(domain: "nil options", code: 0)
|
||||
}
|
||||
guard let ret0_ else {
|
||||
throw NSError(domain: "nil return pointer", code: 0)
|
||||
}
|
||||
|
||||
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1")
|
||||
if options.getAutoRoute() {
|
||||
settings.mtu = NSNumber(value: options.getMTU())
|
||||
|
||||
var error: NSError?
|
||||
let dnsServer = options.getDNSServerAddress(&error)
|
||||
if let error {
|
||||
throw error
|
||||
}
|
||||
settings.dnsSettings = NEDNSSettings(servers: [dnsServer])
|
||||
|
||||
var ipv4Address: [String] = []
|
||||
var ipv4Mask: [String] = []
|
||||
let ipv4AddressIterator = options.getInet4Address()!
|
||||
while ipv4AddressIterator.hasNext() {
|
||||
let ipv4Prefix = ipv4AddressIterator.next()!
|
||||
ipv4Address.append(ipv4Prefix.address)
|
||||
ipv4Mask.append(ipv4Prefix.mask())
|
||||
}
|
||||
let ipv4Settings = NEIPv4Settings(addresses: ipv4Address, subnetMasks: ipv4Mask)
|
||||
var ipv4Routes: [NEIPv4Route] = []
|
||||
let inet4RouteAddressIterator = options.getInet4RouteAddress()!
|
||||
if inet4RouteAddressIterator.hasNext() {
|
||||
while inet4RouteAddressIterator.hasNext() {
|
||||
let ipv4RoutePrefix = inet4RouteAddressIterator.next()!
|
||||
ipv4Routes.append(NEIPv4Route(destinationAddress: ipv4RoutePrefix.address, subnetMask: ipv4RoutePrefix.mask()))
|
||||
}
|
||||
} else {
|
||||
ipv4Routes.append(NEIPv4Route.default())
|
||||
}
|
||||
for (index, address) in ipv4Address.enumerated() {
|
||||
ipv4Routes.append(NEIPv4Route(destinationAddress: address, subnetMask: ipv4Mask[index]))
|
||||
}
|
||||
ipv4Settings.includedRoutes = ipv4Routes
|
||||
settings.ipv4Settings = ipv4Settings
|
||||
|
||||
var ipv6Address: [String] = []
|
||||
var ipv6Prefixes: [NSNumber] = []
|
||||
let ipv6AddressIterator = options.getInet6Address()!
|
||||
while ipv6AddressIterator.hasNext() {
|
||||
let ipv6Prefix = ipv6AddressIterator.next()!
|
||||
ipv6Address.append(ipv6Prefix.address)
|
||||
ipv6Prefixes.append(NSNumber(value: ipv6Prefix.prefix))
|
||||
}
|
||||
let ipv6Settings = NEIPv6Settings(addresses: ipv6Address, networkPrefixLengths: ipv6Prefixes)
|
||||
var ipv6Routes: [NEIPv6Route] = []
|
||||
let inet6RouteAddressIterator = options.getInet6RouteAddress()!
|
||||
if inet6RouteAddressIterator.hasNext() {
|
||||
while inet6RouteAddressIterator.hasNext() {
|
||||
let ipv6RoutePrefix = inet4RouteAddressIterator.next()!
|
||||
ipv6Routes.append(NEIPv6Route(destinationAddress: ipv6RoutePrefix.description, networkPrefixLength: NSNumber(value: ipv6RoutePrefix.prefix)))
|
||||
}
|
||||
} else {
|
||||
ipv6Routes.append(NEIPv6Route.default())
|
||||
}
|
||||
ipv6Settings.includedRoutes = ipv6Routes
|
||||
settings.ipv6Settings = ipv6Settings
|
||||
}
|
||||
|
||||
if options.isHTTPProxyEnabled() {
|
||||
let proxySettings = NEProxySettings()
|
||||
let proxyServer = NEProxyServer(address: options.getHTTPProxyServer(), port: Int(options.getHTTPProxyServerPort()))
|
||||
proxySettings.httpServer = proxyServer
|
||||
proxySettings.httpsServer = proxyServer
|
||||
settings.proxySettings = proxySettings
|
||||
}
|
||||
|
||||
networkSettings = settings
|
||||
try await tunnel.setTunnelNetworkSettings(settings)
|
||||
|
||||
if let tunFd = tunnel.packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32 {
|
||||
ret0_.pointee = tunFd
|
||||
return
|
||||
}
|
||||
|
||||
let tunFdFromLoop = LibboxGetTunnelFileDescriptor()
|
||||
if tunFdFromLoop != -1 {
|
||||
ret0_.pointee = tunFdFromLoop
|
||||
} else {
|
||||
throw NSError(domain: "missing file descriptor", code: 0)
|
||||
}
|
||||
}
|
||||
|
||||
public func usePlatformAutoDetectControl() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
public func autoDetectControl(_: Int32) throws {}
|
||||
|
||||
public func findConnectionOwner(_: Int32, sourceAddress _: String?, sourcePort _: Int32, destinationAddress _: String?, destinationPort _: Int32, ret0_ _: UnsafeMutablePointer<Int32>?) throws {
|
||||
throw NSError(domain: "not implemented", code: 0)
|
||||
}
|
||||
|
||||
public func packageName(byUid _: Int32, error _: NSErrorPointer) -> String {
|
||||
""
|
||||
}
|
||||
|
||||
public func uid(byPackageName _: String?, ret0_ _: UnsafeMutablePointer<Int32>?) throws {
|
||||
throw NSError(domain: "not implemented", code: 0)
|
||||
}
|
||||
|
||||
public func useProcFS() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
public func writeLog(_ message: String?) {
|
||||
guard let message else {
|
||||
return
|
||||
}
|
||||
tunnel.writeMessage(message)
|
||||
}
|
||||
|
||||
public func usePlatformDefaultInterfaceMonitor() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
public func startDefaultInterfaceMonitor(_: LibboxInterfaceUpdateListenerProtocol?) throws {}
|
||||
|
||||
public func closeDefaultInterfaceMonitor(_: LibboxInterfaceUpdateListenerProtocol?) throws {}
|
||||
|
||||
public func useGetter() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
public func getInterfaces() throws -> LibboxNetworkInterfaceIteratorProtocol {
|
||||
throw NSError(domain: "not implemented", code: 0)
|
||||
}
|
||||
|
||||
public func underNetworkExtension() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
public func clearDNSCache() {
|
||||
guard let networkSettings else {
|
||||
return
|
||||
}
|
||||
tunnel.reasserting = true
|
||||
tunnel.setTunnelNetworkSettings(nil) { _ in
|
||||
}
|
||||
tunnel.setTunnelNetworkSettings(networkSettings) { _ in
|
||||
}
|
||||
tunnel.reasserting = false
|
||||
}
|
||||
|
||||
public func serviceReload() throws {
|
||||
runBlocking { [self] in
|
||||
await tunnel.reloadService()
|
||||
}
|
||||
}
|
||||
|
||||
public func getSystemProxyStatus() -> LibboxSystemProxyStatus? {
|
||||
let status = LibboxSystemProxyStatus()
|
||||
guard let networkSettings else {
|
||||
return status
|
||||
}
|
||||
guard let proxySettings = networkSettings.proxySettings else {
|
||||
return status
|
||||
}
|
||||
if proxySettings.httpServer == nil {
|
||||
return status
|
||||
}
|
||||
status.available = true
|
||||
status.enabled = proxySettings.httpEnabled
|
||||
return status
|
||||
}
|
||||
|
||||
public func setSystemProxyEnabled(_ isEnabled: Bool) throws {
|
||||
guard let networkSettings else {
|
||||
return
|
||||
}
|
||||
guard let proxySettings = networkSettings.proxySettings else {
|
||||
return
|
||||
}
|
||||
if proxySettings.httpServer == nil {
|
||||
return
|
||||
}
|
||||
if proxySettings.httpEnabled == isEnabled {
|
||||
return
|
||||
}
|
||||
proxySettings.httpEnabled = isEnabled
|
||||
proxySettings.httpsEnabled = isEnabled
|
||||
networkSettings.proxySettings = proxySettings
|
||||
try runBlocking {
|
||||
try await self.tunnel.setTunnelNetworkSettings(networkSettings)
|
||||
}
|
||||
}
|
||||
|
||||
func reset() {
|
||||
networkSettings = nil
|
||||
}
|
||||
}
|
||||
166
ios/SingBoxPacketTunnel/SingBox/ExtensionProvider.swift
Normal file
166
ios/SingBoxPacketTunnel/SingBox/ExtensionProvider.swift
Normal file
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// ExtensionProvider.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Libcore
|
||||
import NetworkExtension
|
||||
|
||||
open class ExtensionProvider: NEPacketTunnelProvider {
|
||||
public static let errorFile = FilePath.workingDirectory.appendingPathComponent("network_extension_error")
|
||||
|
||||
private var commandServer: LibboxCommandServer!
|
||||
private var boxService: LibboxBoxService!
|
||||
private var systemProxyAvailable = false
|
||||
private var systemProxyEnabled = false
|
||||
private var platformInterface: ExtensionPlatformInterface!
|
||||
private var config: String!
|
||||
|
||||
override open func startTunnel(options: [String: NSObject]?) async throws {
|
||||
try? FileManager.default.removeItem(at: ExtensionProvider.errorFile)
|
||||
try? FileManager.default.removeItem(at: FilePath.workingDirectory.appendingPathComponent("TestLog"))
|
||||
|
||||
let disableMemoryLimit = (options?["DisableMemoryLimit"] as? NSString as? String ?? "NO") == "YES"
|
||||
|
||||
guard let config = options?["Config"] as? NSString as? String else {
|
||||
writeFatalError("(packet-tunnel) error: config not provided")
|
||||
return
|
||||
}
|
||||
guard let config = SingBox.setupConfig(config: config) else {
|
||||
writeFatalError("(packet-tunnel) error: config is invalid")
|
||||
return
|
||||
}
|
||||
self.config = config
|
||||
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: FilePath.workingDirectory, withIntermediateDirectories: true)
|
||||
} catch {
|
||||
writeFatalError("(packet-tunnel) error: create working directory: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
|
||||
LibboxSetup(
|
||||
FilePath.sharedDirectory.relativePath,
|
||||
FilePath.workingDirectory.relativePath,
|
||||
FilePath.cacheDirectory.relativePath,
|
||||
false
|
||||
)
|
||||
|
||||
var error: NSError?
|
||||
LibboxRedirectStderr(FilePath.cacheDirectory.appendingPathComponent("stderr.log").relativePath, &error)
|
||||
if let error {
|
||||
writeError("(packet-tunnel) redirect stderr error: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
LibboxSetMemoryLimit(!disableMemoryLimit)
|
||||
|
||||
if platformInterface == nil {
|
||||
platformInterface = ExtensionPlatformInterface(self)
|
||||
}
|
||||
commandServer = LibboxNewCommandServer(platformInterface, Int32(30))
|
||||
do {
|
||||
try commandServer.start()
|
||||
} catch {
|
||||
writeFatalError("(packet-tunnel): log server start error: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
writeMessage("(packet-tunnel) log server started")
|
||||
await startService()
|
||||
}
|
||||
|
||||
func writeMessage(_ message: String) {
|
||||
if let commandServer {
|
||||
commandServer.writeMessage(message)
|
||||
} else {
|
||||
NSLog(message)
|
||||
}
|
||||
}
|
||||
|
||||
func writeError(_ message: String) {
|
||||
writeMessage(message)
|
||||
try? message.write(to: ExtensionProvider.errorFile, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
public func writeFatalError(_ message: String) {
|
||||
#if DEBUG
|
||||
NSLog(message)
|
||||
#endif
|
||||
writeError(message)
|
||||
cancelTunnelWithError(NSError(domain: message, code: 0))
|
||||
}
|
||||
|
||||
private func startService() async {
|
||||
let configContent = config
|
||||
var error: NSError?
|
||||
let service = LibboxNewService(configContent, platformInterface, &error)
|
||||
if let error {
|
||||
writeError("(packet-tunnel) error: create service: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
guard let service else {
|
||||
return
|
||||
}
|
||||
do {
|
||||
try service.start()
|
||||
} catch {
|
||||
writeError("(packet-tunnel) error: start service: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
boxService = service
|
||||
commandServer.setService(service)
|
||||
}
|
||||
|
||||
private func stopService() {
|
||||
if let service = boxService {
|
||||
do {
|
||||
try service.close()
|
||||
} catch {
|
||||
writeError("(packet-tunnel) error: stop service: \(error.localizedDescription)")
|
||||
}
|
||||
boxService = nil
|
||||
commandServer.setService(nil)
|
||||
}
|
||||
if let platformInterface {
|
||||
platformInterface.reset()
|
||||
}
|
||||
}
|
||||
|
||||
func reloadService() async {
|
||||
writeMessage("(packet-tunnel) reloading service")
|
||||
reasserting = true
|
||||
defer {
|
||||
reasserting = false
|
||||
}
|
||||
stopService()
|
||||
await startService()
|
||||
}
|
||||
|
||||
override open func stopTunnel(with reason: NEProviderStopReason) async {
|
||||
writeMessage("(packet-tunnel) stopping, reason: \(reason)")
|
||||
stopService()
|
||||
if let server = commandServer {
|
||||
try? await Task.sleep(nanoseconds: 100 * NSEC_PER_MSEC)
|
||||
try? server.close()
|
||||
commandServer = nil
|
||||
}
|
||||
}
|
||||
|
||||
override open func handleAppMessage(_ messageData: Data) async -> Data? {
|
||||
messageData
|
||||
}
|
||||
|
||||
override open func sleep() async {
|
||||
if let boxService {
|
||||
boxService.sleep()
|
||||
}
|
||||
}
|
||||
|
||||
override open func wake() {
|
||||
if let boxService {
|
||||
boxService.wake()
|
||||
}
|
||||
}
|
||||
}
|
||||
59
ios/SingBoxPacketTunnel/SingBox/SingBox.swift
Normal file
59
ios/SingBoxPacketTunnel/SingBox/SingBox.swift
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// SingBox.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class SingBox {
|
||||
static func setupConfig(config: String, mtu: Int = 9000) -> String? {
|
||||
guard
|
||||
let config = config.data(using: .utf8),
|
||||
var json = try? JSONSerialization
|
||||
.jsonObject(
|
||||
with: config,
|
||||
options: [.mutableLeaves, .mutableContainers]
|
||||
) as? [String:Any]
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
/*json["log"] = [
|
||||
"disabled": false,
|
||||
"level": "info",
|
||||
"output": "log",
|
||||
"timestamp": true
|
||||
] as [String:Any]
|
||||
json["experimental"] = [
|
||||
"clash_api": [
|
||||
"external_controller": "127.0.0.1:10864"
|
||||
]
|
||||
]
|
||||
json["inbounds"] = [
|
||||
[
|
||||
"type": "tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"auto_route": true,
|
||||
"mtu": mtu,
|
||||
"sniff": true
|
||||
] as [String:Any]
|
||||
]
|
||||
var routing = (json["route"] as? [String:Any]) ?? [
|
||||
"rules": [Any](),
|
||||
"auto_detect_interface": true,
|
||||
"final": (json["inbounds"] as? [[String:Any]])?.first?["tag"] ?? "proxy"
|
||||
]
|
||||
routing["geoip"] = [
|
||||
"path": FilePath.assetsDirectory.appendingPathComponent("geoip.db"),
|
||||
]
|
||||
routing["geosite"] = [
|
||||
"path": FilePath.assetsDirectory.appendingPathComponent("geosite.db"),
|
||||
]
|
||||
json["route"] = routing*/
|
||||
guard let data = try? JSONSerialization.data(withJSONObject: json) else {
|
||||
return nil
|
||||
}
|
||||
return String(data: data, encoding: .utf8)
|
||||
}
|
||||
}
|
||||
14
ios/SingBoxPacketTunnel/SingBoxPacketTunnel.entitlements
Normal file
14
ios/SingBoxPacketTunnel/SingBoxPacketTunnel.entitlements
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.$(BASE_BUNDLE_IDENTIFIER)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
70
ios/SingBoxPacketTunnel/TrafficReader.swift
Normal file
70
ios/SingBoxPacketTunnel/TrafficReader.swift
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// TrafficReader.swift
|
||||
// SingBoxPacketTunnel
|
||||
//
|
||||
// Created by GFWFighter on 7/25/1402 AP.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TrafficReaderUpdate: Codable {
|
||||
let up: Int64
|
||||
let down: Int64
|
||||
}
|
||||
|
||||
|
||||
class TrafficReader {
|
||||
private var task: URLSessionWebSocketTask!
|
||||
private let callback: (TrafficReaderUpdate) -> ()
|
||||
|
||||
init(onUpdate: @escaping (TrafficReaderUpdate) -> ()) {
|
||||
self.callback = onUpdate
|
||||
Task(priority: .background) { [weak self] () in
|
||||
await self?.setup()
|
||||
}
|
||||
}
|
||||
|
||||
private func setup() async {
|
||||
try? await Task.sleep(nanoseconds: 5_000_000_000)
|
||||
//return
|
||||
while true {
|
||||
do {
|
||||
let (_, response) = try await URLSession.shared.data(from: URL(string: "http://127.0.0.1:10864")!)
|
||||
let code = (response as? HTTPURLResponse)?.statusCode ?? -1
|
||||
if code >= 200 && code < 300 {
|
||||
break
|
||||
}
|
||||
} catch {
|
||||
// pass
|
||||
}
|
||||
try? await Task.sleep(nanoseconds: 5_000_000)
|
||||
}
|
||||
let task = URLSession.shared.webSocketTask(with: URL(string: "ws://127.0.0.1:10864/traffic")!)
|
||||
self.task = task
|
||||
read()
|
||||
task.resume()
|
||||
}
|
||||
|
||||
private func read() {
|
||||
task.receive { [weak self] result in
|
||||
switch result {
|
||||
case .failure(_):
|
||||
break
|
||||
case .success(let message):
|
||||
switch message {
|
||||
case .string(let message):
|
||||
guard let data = message.data(using: .utf8) else {
|
||||
break
|
||||
}
|
||||
guard let response = try? JSONDecoder().decode(TrafficReaderUpdate.self, from: data) else {
|
||||
break
|
||||
}
|
||||
self?.callback(response)
|
||||
default:
|
||||
break
|
||||
}
|
||||
self?.read()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,43 @@ import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class FilesEditorService with InfraLogger {
|
||||
|
||||
late final _methodChannel = const MethodChannel("com.hiddify.app/files.method");
|
||||
|
||||
late final Directory baseDir;
|
||||
late final Directory workingDir;
|
||||
late final Directory tempDir;
|
||||
late final Directory logsDir;
|
||||
late final Directory _configsDir;
|
||||
|
||||
Future<void> init() async {
|
||||
baseDir = await getApplicationSupportDirectory();
|
||||
if (Platform.isAndroid) {
|
||||
final externalDir = await getExternalStorageDirectory();
|
||||
workingDir = externalDir!;
|
||||
} else if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||
workingDir = baseDir;
|
||||
} else {
|
||||
workingDir = await getApplicationDocumentsDirectory();
|
||||
Future<Map<String, String>?> getPaths() async {
|
||||
try {
|
||||
final Map<dynamic, dynamic>? directoryMap = await _methodChannel.invokeMethod('get_paths');
|
||||
return directoryMap?.cast<String, String>();
|
||||
} on PlatformException catch (e) {
|
||||
// print("Failed to get shared directory: '${e.message}'.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
if (Platform.isIOS) {
|
||||
final paths = await getPaths();
|
||||
baseDir = Directory(paths!["base"]!);
|
||||
workingDir = Directory(paths["working"]!);
|
||||
tempDir = Directory(paths["temp"]!);
|
||||
} else {
|
||||
baseDir = await getApplicationSupportDirectory();
|
||||
if (Platform.isAndroid) {
|
||||
final externalDir = await getExternalStorageDirectory();
|
||||
workingDir = externalDir!;
|
||||
} else if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||
workingDir = baseDir;
|
||||
} else {
|
||||
workingDir = await getApplicationDocumentsDirectory();
|
||||
}
|
||||
tempDir = await getTemporaryDirectory();
|
||||
}
|
||||
tempDir = await getTemporaryDirectory();
|
||||
logsDir = workingDir;
|
||||
|
||||
loggy.debug("base dir: ${baseDir.path}");
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'package:hiddify/services/singbox/mobile_singbox_service.dart';
|
||||
|
||||
abstract interface class SingboxService {
|
||||
factory SingboxService() {
|
||||
if (Platform.isAndroid) {
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
return MobileSingboxService();
|
||||
} else if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
|
||||
return FFISingboxService();
|
||||
|
||||
@@ -118,6 +118,6 @@ SPEC CHECKSUMS:
|
||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
||||
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
||||
|
||||
PODFILE CHECKSUM: 15674062c2e6d8f1f7ead4db6e1a7e96c717a635
|
||||
PODFILE CHECKSUM: 0b402b362e66492ff5597cf44bda1a7f782269c6
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 1300;
|
||||
LastUpgradeCheck = 1430;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C80D4294CF70F00263BE5 = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
Reference in New Issue
Block a user