mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-04-21 21:50:21 +08:00
mac程序坞退出清理事件
This commit is contained in:
@@ -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<String>? = null
|
||||
|
||||
companion object {
|
||||
const val MAX_PACKET_LEN = 1500
|
||||
|
||||
|
||||
11
android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt
Normal file
11
android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.network.proxy.vpn
|
||||
|
||||
|
||||
fun formatTag(tag: String): String {
|
||||
return tag
|
||||
}
|
||||
|
||||
val Any.TAG: String
|
||||
get() {
|
||||
return javaClass.name
|
||||
}
|
||||
@@ -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<void> _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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,14 @@ class ProxyServer {
|
||||
|
||||
/// 停止代理服务
|
||||
Future<Server?> 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;
|
||||
}
|
||||
|
||||
@@ -147,8 +147,9 @@ class _DesktopHomePagePageState extends State<DesktopHomePage> 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)));
|
||||
});
|
||||
|
||||
@@ -46,7 +46,6 @@ class _ToolbarState extends State<Toolbar> {
|
||||
}
|
||||
|
||||
if (event.isKeyPressed(LogicalKeyboardKey.metaLeft) && event.isKeyPressed(LogicalKeyboardKey.keyQ)) {
|
||||
print("windowManager.close()");
|
||||
windowManager.close();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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<SocketLaunch> 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<SocketLaunch> with WindowListener, Widget
|
||||
|
||||
@override
|
||||
void onWindowClose() async {
|
||||
await widget.proxyServer.stop();
|
||||
print("onWindowClose");
|
||||
await appExit();
|
||||
}
|
||||
|
||||
Future<void> appExit() async {
|
||||
await widget.proxyServer.stop();
|
||||
SocketLaunch.started = false;
|
||||
await windowManager.destroy();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AppExitResponse> didRequestAppExit() async {
|
||||
await appExit();
|
||||
return super.didRequestAppExit();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.detached) {
|
||||
@@ -76,8 +88,6 @@ class _SocketLaunchState extends State<SocketLaunch> 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,
|
||||
|
||||
@@ -40,8 +40,6 @@ class MobileHomeState extends State<MobileHomePage> 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<MobileHomePage> 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<MobileHomePage> 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;
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -461,7 +461,7 @@ class DomainListState extends State<DomainList> with AutomaticKeepAliveClientMix
|
||||
),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 60,
|
||||
height: 55,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: const Text("取消", textAlign: TextAlign.center)),
|
||||
|
||||
@@ -145,7 +145,7 @@ class RequestRowState extends State<RequestRow> {
|
||||
),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 40,
|
||||
height: 55,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: const Text("取消", textAlign: TextAlign.center)),
|
||||
|
||||
@@ -337,7 +337,7 @@ class _RequestRuleListState extends State<RequestRuleList> {
|
||||
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)),
|
||||
|
||||
@@ -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 = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9B673CF02A383721009CB5B5 /* T.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = T.m; sourceTree = "<group>"; };
|
||||
9B8D91802B335386009B90B1 /* AppLifecycleChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLifecycleChannel.swift; sourceTree = "<group>"; };
|
||||
9BCACE942A3AAED1009FBC53 /* RunnerProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerProfile.entitlements; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
22
macos/Runner/AppLifecycleChannel.swift
Normal file
22
macos/Runner/AppLifecycleChannel.swift
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user