From 1d083b4d05d24c9b2f14af76edf9ff72bb2ecd01 Mon Sep 17 00:00:00 2001 From: wanghongenpin Date: Thu, 21 Dec 2023 02:45:37 +0800 Subject: [PATCH] =?UTF-8?q?mac=E7=A8=8B=E5=BA=8F=E5=9D=9E=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=B8=85=E7=90=86=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/network/proxy/ProxyVpnService.kt | 4 ++ .../main/kotlin/com/network/proxy/vpn/Tag.kt | 11 +++++ lib/native/app_lifecycle.dart | 31 +++++++++++++ lib/network/bin/server.dart | 6 ++- lib/ui/desktop/desktop.dart | 5 +- lib/ui/desktop/toolbar/toolbar.dart | 1 - lib/ui/launch/launch.dart | 18 ++++++-- lib/ui/mobile/mobile.dart | 8 ++-- lib/ui/mobile/request/favorite.dart | 5 +- lib/ui/mobile/request/list.dart | 2 +- lib/ui/mobile/request/request.dart | 2 +- lib/ui/mobile/setting/request_rewrite.dart | 2 +- macos/Runner.xcodeproj/project.pbxproj | 4 ++ macos/Runner/AppDelegate.swift | 46 ++++++++++--------- macos/Runner/AppLifecycleChannel.swift | 22 +++++++++ macos/Runner/MainFlutterWindow.swift | 24 +++++----- 16 files changed, 139 insertions(+), 52 deletions(-) create mode 100644 android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt create mode 100644 macos/Runner/AppLifecycleChannel.swift diff --git a/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt b/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt index 79bd2d7..8b5f990 100644 --- a/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt +++ b/android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt @@ -21,6 +21,10 @@ import com.network.proxy.vpn.socket.ProtectSocketHolder class ProxyVpnService : VpnService(), ProtectSocket { private var vpnInterface: ParcelFileDescriptor? = null + private var host: String? = null + private var port: Int = 0 + private var allowApps: List? = null + companion object { const val MAX_PACKET_LEN = 1500 diff --git a/android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt b/android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt new file mode 100644 index 0000000..d7265c5 --- /dev/null +++ b/android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt @@ -0,0 +1,11 @@ +package com.network.proxy.vpn + + +fun formatTag(tag: String): String { + return tag +} + +val Any.TAG: String + get() { + return javaClass.name + } diff --git a/lib/native/app_lifecycle.dart b/lib/native/app_lifecycle.dart index 3da3168..161240a 100644 --- a/lib/native/app_lifecycle.dart +++ b/lib/native/app_lifecycle.dart @@ -1,5 +1,36 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; abstract interface class AppLifecycleListener { void onUserLeaveHint(AppLifecycleState state); + + void onDetached(AppLifecycleState state); +} + +class AppLifecycleBinding { + static const MethodChannel _methodChannel = MethodChannel('com.proxy/appLifecycle'); + static bool _initialized = false; + + static ensureInitialized() { + if (_initialized) { + return; + } + + //注册方法 + _methodChannel.setMethodCallHandler(_methodCallHandler); + _initialized = true; + } + + static Future _methodCallHandler(MethodCall call) async { + switch (call.method) { + case 'appDetached': + await WidgetsBinding.instance.handleRequestAppExit(); + break; + case 'userLeaveHint': + print("userLeaveHint"); + // WidgetsBinding.instance.handleRequestAppExit(); + break; + } + return Future.value(); + } } diff --git a/lib/network/bin/server.dart b/lib/network/bin/server.dart index cbe280d..3836744 100644 --- a/lib/network/bin/server.dart +++ b/lib/network/bin/server.dart @@ -87,10 +87,14 @@ class ProxyServer { /// 停止代理服务 Future stop() async { - logger.i("stop on $port"); + if (!isRunning) { + return server; + } + if (configuration.enableSystemProxy) { await setSystemProxyEnable(false); } + logger.i("stop on $port"); await server?.stop(); return server; } diff --git a/lib/ui/desktop/desktop.dart b/lib/ui/desktop/desktop.dart index e7a183d..3ef2528 100644 --- a/lib/ui/desktop/desktop.dart +++ b/lib/ui/desktop/desktop.dart @@ -147,8 +147,9 @@ class _DesktopHomePagePageState extends State implements EventL '1. 请求重写增加 修改请求,可根据正则替换;\n' '2. 请求重写批量导入、导出;\n' '3. 支持WebSocket抓包;\n' - '4. 优化curl导入;\n' - '5. 支持head请求,修复手机端请求重写切换应用恢复原始的请求问题;\n' + '4. 安卓支持小窗口模式;\n' + '5. 优化curl导入;\n' + '6. 支持head请求,修复手机端请求重写切换应用恢复原始的请求问题;\n' '', style: TextStyle(fontSize: 14))); }); diff --git a/lib/ui/desktop/toolbar/toolbar.dart b/lib/ui/desktop/toolbar/toolbar.dart index b30677b..2f7f374 100644 --- a/lib/ui/desktop/toolbar/toolbar.dart +++ b/lib/ui/desktop/toolbar/toolbar.dart @@ -46,7 +46,6 @@ class _ToolbarState extends State { } if (event.isKeyPressed(LogicalKeyboardKey.metaLeft) && event.isKeyPressed(LogicalKeyboardKey.keyQ)) { - print("windowManager.close()"); windowManager.close(); return; } diff --git a/lib/ui/launch/launch.dart b/lib/ui/launch/launch.dart index efed879..eb1872d 100644 --- a/lib/ui/launch/launch.dart +++ b/lib/ui/launch/launch.dart @@ -1,7 +1,9 @@ import 'dart:io'; +import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_toastr/flutter_toastr.dart'; +import 'package:network_proxy/native/app_lifecycle.dart'; import 'package:network_proxy/network/bin/server.dart'; import 'package:network_proxy/utils/platform.dart'; import 'package:window_manager/window_manager.dart'; @@ -38,8 +40,8 @@ class _SocketLaunchState extends State with WindowListener, Widget super.initState(); windowManager.addListener(this); WidgetsBinding.instance.addObserver(this); + AppLifecycleBinding.ensureInitialized(); //启动代理服务器 - print("SocketLaunch ${widget.startup}"); if (widget.startup) { start(); } @@ -57,13 +59,23 @@ class _SocketLaunchState extends State with WindowListener, Widget @override void onWindowClose() async { - await widget.proxyServer.stop(); print("onWindowClose"); + await appExit(); + } + + Future appExit() async { + await widget.proxyServer.stop(); SocketLaunch.started = false; await windowManager.destroy(); exit(0); } + @override + Future didRequestAppExit() async { + await appExit(); + return super.didRequestAppExit(); + } + @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.detached) { @@ -76,8 +88,6 @@ class _SocketLaunchState extends State with WindowListener, Widget @override Widget build(BuildContext context) { - print("SocketLaunch build ${widget.startup}"); - return IconButton( tooltip: SocketLaunch.started ? "停止" : "启动", icon: Icon(SocketLaunch.started ? Icons.stop : Icons.play_arrow_sharp, diff --git a/lib/ui/mobile/mobile.dart b/lib/ui/mobile/mobile.dart index 76dc50b..1d33dd7 100644 --- a/lib/ui/mobile/mobile.dart +++ b/lib/ui/mobile/mobile.dart @@ -40,8 +40,6 @@ class MobileHomeState extends State with WidgetsBindingObserver @override void didChangeAppLifecycleState(AppLifecycleState state) { - print("didChangeAppLifecycleState $state"); - if (state == AppLifecycleState.inactive && Vpn.isVpnStarted) { if (desktop.value.connect || !Platform.isAndroid || !widget.configuration.smallWindow) { return; @@ -53,7 +51,6 @@ class MobileHomeState extends State with WidgetsBindingObserver if (state == AppLifecycleState.resumed && pictureInPictureNotifier.value) { Vpn.isRunning().then((value) { Vpn.isVpnStarted = value; - print("isRunning $value"); pictureInPictureNotifier.value = false; }); } @@ -165,8 +162,9 @@ class MobileHomeState extends State with WidgetsBindingObserver '1. 请求重写增加 修改请求,可根据增则替换;\n' '2. 请求重写批量导入、导出;\n' '3. 支持WebSocket抓包;\n' - '4. 优化curl导入;\n' - '5. 支持head请求,修复手机端请求重写切换应用恢复原始的请求问题;\n' + '4. 安卓支持小窗口模式;\n' + '5. 优化curl导入;\n' + '6. 支持head请求,修复手机端请求重写切换应用恢复原始的请求问题;\n' ''; showAlertDialog('更新内容V1.0.6', content, () { widget.configuration.upgradeNoticeV6 = false; diff --git a/lib/ui/mobile/request/favorite.dart b/lib/ui/mobile/request/favorite.dart index c340d23..b8a8db3 100644 --- a/lib/ui/mobile/request/favorite.dart +++ b/lib/ui/mobile/request/favorite.dart @@ -69,8 +69,7 @@ class _FavoriteItem extends StatefulWidget { final ProxyServer proxyServer; final Function(Favorite favorite)? onRemove; - const _FavoriteItem(this.favorite, {Key? key, required this.onRemove, required this.proxyServer, required this.index}) - : super(key: key); + const _FavoriteItem(this.favorite, {super.key, required this.onRemove, required this.proxyServer, required this.index}); @override State<_FavoriteItem> createState() => _FavoriteItemState(); @@ -156,7 +155,7 @@ class _FavoriteItemState extends State<_FavoriteItem> { Container(color: Theme.of(context).hoverColor, height: 8), TextButton( child: Container( - height: 40, + height: 55, width: double.infinity, padding: const EdgeInsets.only(top: 10), child: const Text("取消", textAlign: TextAlign.center)), diff --git a/lib/ui/mobile/request/list.dart b/lib/ui/mobile/request/list.dart index 900f823..4559e54 100644 --- a/lib/ui/mobile/request/list.dart +++ b/lib/ui/mobile/request/list.dart @@ -461,7 +461,7 @@ class DomainListState extends State with AutomaticKeepAliveClientMix ), TextButton( child: Container( - height: 60, + height: 55, width: double.infinity, padding: const EdgeInsets.only(top: 10), child: const Text("取消", textAlign: TextAlign.center)), diff --git a/lib/ui/mobile/request/request.dart b/lib/ui/mobile/request/request.dart index 08547d2..403a2e6 100644 --- a/lib/ui/mobile/request/request.dart +++ b/lib/ui/mobile/request/request.dart @@ -145,7 +145,7 @@ class RequestRowState extends State { ), TextButton( child: Container( - height: 40, + height: 55, width: double.infinity, padding: const EdgeInsets.only(top: 10), child: const Text("取消", textAlign: TextAlign.center)), diff --git a/lib/ui/mobile/setting/request_rewrite.dart b/lib/ui/mobile/setting/request_rewrite.dart index 583e76c..7519f54 100644 --- a/lib/ui/mobile/setting/request_rewrite.dart +++ b/lib/ui/mobile/setting/request_rewrite.dart @@ -337,7 +337,7 @@ class _RequestRuleListState extends State { Container(color: Theme.of(context).hoverColor, height: 8), TextButton( child: Container( - height: 48, + height: 55, width: double.infinity, padding: const EdgeInsets.only(top: 10), child: const Text("取消", textAlign: TextAlign.center)), diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index ee43f81..448dcaa 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 59CD0B3B69B2AD63E8F7FD5B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15B6D3EA3FFF7C54E0E30275 /* Pods_Runner.framework */; }; 85F740723892A1960748773D /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C326C0FC3A1C8C78354E1D3 /* Pods_RunnerTests.framework */; }; 9B673CF12A383721009CB5B5 /* T.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B673CF02A383721009CB5B5 /* T.m */; }; + 9B8D91812B335386009B90B1 /* AppLifecycleChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B8D91802B335386009B90B1 /* AppLifecycleChannel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -87,6 +88,7 @@ 8F664CC27DDA6C1AEED215C8 /* 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 9B673CF02A383721009CB5B5 /* T.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = T.m; sourceTree = ""; }; + 9B8D91802B335386009B90B1 /* AppLifecycleChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLifecycleChannel.swift; sourceTree = ""; }; 9BCACE942A3AAED1009FBC53 /* RunnerProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerProfile.entitlements; sourceTree = ""; }; AEE2D821CE41DE974B8482C9 /* 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 = ""; }; C037DD715A776D1345BC6EBC /* 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 = ""; }; @@ -191,6 +193,7 @@ 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( + 9B8D91802B335386009B90B1 /* AppLifecycleChannel.swift */, 9BCACE942A3AAED1009FBC53 /* RunnerProfile.entitlements */, 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, @@ -443,6 +446,7 @@ files = ( 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 9B8D91812B335386009B90B1 /* AppLifecycleChannel.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index 801b2a5..af55012 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -3,26 +3,28 @@ import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { - if !flag { - for window in NSApp.windows { - if !window.isVisible { - window.setIsVisible(true) - } - window.makeKeyAndOrderFront(self) - NSApp.activate(ignoringOtherApps: true) - } - } - return true - } - - override func applicationWillTerminate(_ notification: Notification) { - print("applicationWillTerminate called") - NSLog("applicationWillTerminate") - } - + + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { + if !flag { + for window in NSApp.windows { + if !window.isVisible { + window.setIsVisible(true) + } + window.makeKeyAndOrderFront(self) + NSApp.activate(ignoringOtherApps: true) + } + } + return true + } + + + override func applicationWillTerminate(_ notification: Notification) { + AppLifecycleChannel.appDetached() + NSLog("applicationWillTerminate") + } + } diff --git a/macos/Runner/AppLifecycleChannel.swift b/macos/Runner/AppLifecycleChannel.swift new file mode 100644 index 0000000..f9eb1f9 --- /dev/null +++ b/macos/Runner/AppLifecycleChannel.swift @@ -0,0 +1,22 @@ +// +// AppLifecycleChannel.swift +// +// Created by wanghongen on 2023/12/21. +// + +import Foundation +import FlutterMacOS + +class AppLifecycleChannel { + static private var channel : FlutterMethodChannel? + + //注册 + static func registerChannel(flutterViewController: FlutterViewController) { + channel = FlutterMethodChannel(name: "com.proxy/appLifecycle", binaryMessenger: flutterViewController.engine.binaryMessenger) + } + + static func appDetached() { + channel!.invokeMethod("appDetached", arguments: nil) + Thread.sleep(forTimeInterval: 0.5) + } +} diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift index e10a41a..def8f43 100644 --- a/macos/Runner/MainFlutterWindow.swift +++ b/macos/Runner/MainFlutterWindow.swift @@ -2,15 +2,17 @@ import Cocoa import FlutterMacOS class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } - + + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + AppLifecycleChannel.registerChannel(flutterViewController: flutterViewController) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } }