mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-21 03:32:06 +00:00
199 lines
6.2 KiB
Dart
199 lines
6.2 KiB
Dart
// You have generated a new plugin project without
|
|
// specifying the `--platforms` flag. A plugin project supports no platforms is generated.
|
|
// To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
|
|
// directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
|
|
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'src/create_configuration.dart';
|
|
import 'src/message_channel.dart';
|
|
import 'src/webview.dart';
|
|
import 'src/webview_impl.dart';
|
|
|
|
export 'src/create_configuration.dart';
|
|
export 'src/title_bar.dart';
|
|
export 'src/webview.dart';
|
|
|
|
final List<WebviewImpl> _webviews = [];
|
|
|
|
class WebviewWindow {
|
|
static const MethodChannel _channel = MethodChannel('webview_window');
|
|
|
|
static const _otherIsolateMessageHandler = ClientMessageChannel();
|
|
|
|
static bool _inited = false;
|
|
|
|
static void _init() {
|
|
if (_inited) {
|
|
return;
|
|
}
|
|
_inited = true;
|
|
_channel.setMethodCallHandler((call) async {
|
|
try {
|
|
return await _handleMethodCall(call);
|
|
} catch (e, s) {
|
|
debugPrint("method: ${call.method} args: ${call.arguments}");
|
|
debugPrint('handleMethodCall error: $e $s');
|
|
}
|
|
});
|
|
_otherIsolateMessageHandler.setMessageHandler((call) async {
|
|
try {
|
|
return await _handleOtherIsolateMethodCall(call);
|
|
} catch (e, s) {
|
|
debugPrint('_handleOtherIsolateMethodCall error: $e $s');
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Check if WebView runtime is available on the current devices.
|
|
static Future<bool> isWebviewAvailable() async {
|
|
if (Platform.isWindows) {
|
|
final ret = await _channel.invokeMethod<bool>('isWebviewAvailable');
|
|
return ret == true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static Future<Webview> create({
|
|
CreateConfiguration? configuration,
|
|
}) async {
|
|
configuration ??= CreateConfiguration.platform();
|
|
_init();
|
|
final viewId = await _channel.invokeMethod(
|
|
"create",
|
|
configuration.toMap(),
|
|
) as int;
|
|
final webview = WebviewImpl(viewId, _channel);
|
|
_webviews.add(webview);
|
|
return webview;
|
|
}
|
|
|
|
static Future<dynamic> _handleOtherIsolateMethodCall(MethodCall call) async {
|
|
final webViewId = call.arguments['webViewId'] as int;
|
|
final webView = _webviews
|
|
.cast<WebviewImpl?>()
|
|
.firstWhere((w) => w?.viewId == webViewId, orElse: () => null);
|
|
if (webView == null) {
|
|
return;
|
|
}
|
|
switch (call.method) {
|
|
case 'onBackPressed':
|
|
await webView.back();
|
|
break;
|
|
case 'onForwardPressed':
|
|
await webView.forward();
|
|
break;
|
|
case 'onRefreshPressed':
|
|
await webView.reload();
|
|
break;
|
|
case 'onStopPressed':
|
|
await webView.stop();
|
|
break;
|
|
case 'onClosePressed':
|
|
webView.close();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static Future<dynamic> _handleMethodCall(MethodCall call) async {
|
|
final args = call.arguments as Map;
|
|
final viewId = args['id'] as int;
|
|
final webview = _webviews
|
|
.cast<WebviewImpl?>()
|
|
.firstWhere((e) => e?.viewId == viewId, orElse: () => null);
|
|
assert(webview != null);
|
|
if (webview == null) {
|
|
return;
|
|
}
|
|
switch (call.method) {
|
|
case "onWindowClose":
|
|
_webviews.remove(webview);
|
|
webview.onClosed();
|
|
break;
|
|
case "onJavaScriptMessage":
|
|
webview.onJavaScriptMessage(args['name'], args['body']);
|
|
break;
|
|
case "runJavaScriptTextInputPanelWithPrompt":
|
|
return webview.onRunJavaScriptTextInputPanelWithPrompt(
|
|
args['prompt'],
|
|
args['defaultText'],
|
|
);
|
|
case "onHistoryChanged":
|
|
webview.onHistoryChanged(args['canGoBack'], args['canGoForward']);
|
|
await _otherIsolateMessageHandler.invokeMethod('onHistoryChanged', {
|
|
'webViewId': viewId,
|
|
'canGoBack': args['canGoBack'] as bool,
|
|
'canGoForward': args['canGoForward'] as bool,
|
|
});
|
|
break;
|
|
case "onNavigationStarted":
|
|
webview.onNavigationStarted();
|
|
await _otherIsolateMessageHandler.invokeMethod('onNavigationStarted', {
|
|
'webViewId': viewId,
|
|
});
|
|
break;
|
|
case "onUrlRequested":
|
|
final url = args['url'] as String;
|
|
webview.notifyUrlChanged(url);
|
|
await _otherIsolateMessageHandler.invokeMethod('onUrlRequested', {
|
|
'webViewId': viewId,
|
|
'url': url,
|
|
});
|
|
break;
|
|
case "onWebMessageReceived":
|
|
final message = args['message'] as String;
|
|
webview.notifyWebMessageReceived(message);
|
|
await _otherIsolateMessageHandler.invokeMethod('onWebMessageReceived', {
|
|
'webViewId': viewId,
|
|
'message': message,
|
|
});
|
|
break;
|
|
case "onNavigationCompleted":
|
|
webview.onNavigationCompleted();
|
|
await _otherIsolateMessageHandler
|
|
.invokeMethod('onNavigationCompleted', {
|
|
'webViewId': viewId,
|
|
});
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// Clear all cookies and storage.
|
|
static Future<void> clearAll({
|
|
String userDataFolderWindows = 'webview_window_WebView2',
|
|
}) async {
|
|
await _channel.invokeMethod('clearAll');
|
|
|
|
// FIXME(boyan01) Move the logic to windows platform if WebView2 provider a way to clean caches.
|
|
// https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/user-data-folder#create-user-data-folders
|
|
if (Platform.isWindows) {
|
|
final Directory webview2Dir;
|
|
if (p.isAbsolute(userDataFolderWindows)) {
|
|
webview2Dir = Directory(userDataFolderWindows);
|
|
} else {
|
|
webview2Dir = Directory(p.join(
|
|
p.dirname(Platform.resolvedExecutable), userDataFolderWindows));
|
|
}
|
|
|
|
if (await (webview2Dir.exists())) {
|
|
for (var i = 0; i <= 4; i++) {
|
|
try {
|
|
await webview2Dir.delete(recursive: true);
|
|
break;
|
|
} catch (e) {
|
|
debugPrint("delete cache failed. retring.... $e");
|
|
}
|
|
// wait to ensure all web window has been closed and file handle has been release.
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|