Files
MWClash/lib/plugins/service.dart
chen08209 ed7868282a Add android separates the core process
Support core status check and force restart

Optimize proxies page and access page

Update flutter and pub dependencies

Update go version

Optimize more details
2025-09-23 15:23:58 +08:00

122 lines
3.1 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'package:fl_clash/common/constant.dart';
import 'package:fl_clash/common/system.dart';
import 'package:fl_clash/models/common.dart';
import 'package:fl_clash/models/core.dart';
import 'package:fl_clash/state.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
abstract mixin class ServiceListener {
void onServiceEvent(CoreEvent event) {}
void onServiceCrash(String message) {}
}
class Service {
static Service? _instance;
late MethodChannel methodChannel;
ReceivePort? receiver;
final ObserverList<ServiceListener> _listeners =
ObserverList<ServiceListener>();
factory Service() {
_instance ??= Service._internal();
return _instance!;
}
Service._internal() {
methodChannel = const MethodChannel('$packageName/service');
methodChannel.setMethodCallHandler((call) async {
switch (call.method) {
case 'getVpnOptions':
return handleGetVpnOptions();
case 'event':
final data = call.arguments as String? ?? '';
final result = ActionResult.fromJson(json.decode(data));
for (final listener in _listeners) {
listener.onServiceEvent(CoreEvent.fromJson(result.data));
}
break;
case 'crash':
final message = call.arguments as String? ?? '';
for (final listener in _listeners) {
listener.onServiceCrash(message);
}
break;
default:
throw MissingPluginException();
}
});
}
Future<ActionResult?> invokeAction(Action action) async {
final data = await methodChannel.invokeMethod<String>(
'invokeAction',
json.encode(action),
);
if (data == null) {
return null;
}
return ActionResult.fromJson(json.decode(data));
}
String handleGetVpnOptions() {
return json.encode(globalState.getVpnOptions());
}
Future<bool> start() async {
return await methodChannel.invokeMethod<bool>('start') ?? false;
}
Future<bool> stop() async {
return await methodChannel.invokeMethod<bool>('stop') ?? false;
}
Future<String> syncAndroidState(AndroidState state) async {
return await methodChannel.invokeMethod<String>(
'syncState',
json.encode(state),
) ??
'';
}
Future<String> init() async {
return await methodChannel.invokeMethod<String>(
'init',
!globalState.isService,
) ??
'';
}
Future<bool> shutdown() async {
return await methodChannel.invokeMethod<bool>('shutdown') ?? true;
}
Future<DateTime?> getRunTime() async {
final ms = await methodChannel.invokeMethod<int>('getRunTime') ?? 0;
if (ms == 0) {
return null;
}
return DateTime.fromMillisecondsSinceEpoch(ms);
}
bool get hasListeners {
return _listeners.isNotEmpty;
}
void addListener(ServiceListener listener) {
_listeners.add(listener);
}
void removeListener(ServiceListener listener) {
_listeners.remove(listener);
}
}
Service? get service => system.isAndroid ? Service() : null;