Add webview for desktop

This commit is contained in:
kodjomoustapha 2023-05-26 08:04:34 +01:00
parent 33eb2458a4
commit 6c67cecf4b
13 changed files with 464 additions and 257 deletions

View file

@ -1,5 +1,6 @@
// ignore_for_file: depend_on_referenced_packages
import 'dart:io';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -22,7 +23,10 @@ import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
late Isar isar;
void main() async {
void main(List<String> args) async {
if (runWebViewTitleBarWidget(args)) {
return;
}
WidgetsFlutterBinding.ensureInitialized();
await _initDB();
runApp(const ProviderScope(child: MyApp()));

View file

@ -152,7 +152,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
),
)
: SizedBox(
width: mediaWidth(context, 0.4),
width: isTablet(context) ? null : mediaWidth(context, 0.4),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:

View file

@ -106,6 +106,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
Map<String, String> data = {
'url': getMangaBaseUrl(widget.mangaType.source!),
'source': widget.mangaType.source!,
'title': ''
};
context.push("/mangawebview", extra: data);
},

View file

@ -1,11 +1,20 @@
// ignore_for_file: depend_on_referenced_packages
import 'dart:convert';
import 'dart:io';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:share_plus/share_plus.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
class MangaWebView extends ConsumerStatefulWidget {
final String url;
@ -26,166 +35,233 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
final GlobalKey webViewKey = GlobalKey();
double progress = 0;
@override
void initState() {
if (Platform.isWindows || Platform.isLinux) {
_runWebViewDesktop();
} else {
setState(() {
isNotDesktop = true;
});
}
super.initState();
}
Webview? webview;
_runWebViewDesktop() async {
webview = await WebviewWindow.create(
configuration: CreateConfiguration(
userDataFolderWindows: await getWebViewPath(),
),
);
webview!
..setBrightness(Brightness.dark)
..setApplicationNameForUserAgent(defaultUserAgent)
..launch(widget.url)
..onClose.whenComplete(() {
Navigator.pop(context);
});
}
bool isNotDesktop = false;
InAppWebViewController? _webViewController;
late String _url = widget.url;
late String _title = widget.title;
bool _canGoback = false;
bool _canGoForward = false;
@override
Widget build(BuildContext context) {
return SafeArea(
child: WillPopScope(
onWillPop: () async {
_webViewController?.goBack();
return false;
},
child: Column(
children: [
SizedBox(
height: AppBar().preferredSize.height,
child: Row(
return !isNotDesktop
? Scaffold(
appBar: AppBar(
title: Text(
_title,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold),
),
leading: IconButton(
onPressed: () {
webview!.close();
Navigator.pop(context);
},
icon: const Icon(Icons.close)),
),
)
: SafeArea(
child: WillPopScope(
onWillPop: () async {
_webViewController?.goBack();
return false;
},
child: Column(
children: [
Expanded(
child: ListTile(
dense: true,
subtitle: Text(
_url,
style: const TextStyle(
fontSize: 10, overflow: TextOverflow.ellipsis),
),
title: Text(
_title,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold),
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.close)),
SizedBox(
height: AppBar().preferredSize.height,
child: Row(
children: [
Expanded(
child: ListTile(
dense: true,
subtitle: Text(
_url,
style: const TextStyle(
fontSize: 10,
overflow: TextOverflow.ellipsis),
),
title: Text(
_title,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold),
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.close)),
),
),
IconButton(
icon: Icon(Icons.arrow_back,
color: _canGoback ? null : Colors.grey),
onPressed: _canGoback
? () {
_webViewController?.goBack();
}
: null,
),
IconButton(
icon: Icon(Icons.arrow_forward,
color: _canGoForward ? null : Colors.grey),
onPressed: _canGoForward
? () {
_webViewController?.goForward();
}
: null,
),
PopupMenuButton(itemBuilder: (context) {
return [
const PopupMenuItem<int>(
value: 0, child: Text("Refresh")),
const PopupMenuItem<int>(
value: 1, child: Text("Share")),
const PopupMenuItem<int>(
value: 2, child: Text("Open in browser")),
const PopupMenuItem<int>(
value: 3, child: Text("Clear cookie")),
];
}, onSelected: (value) async {
if (value == 0) {
_webViewController?.reload();
} else if (value == 1) {
Share.share(_url);
} else if (value == 2) {
await InAppBrowser.openWithSystemBrowser(
url: WebUri.uri(Uri.parse(_url)));
} else if (value == 3) {
CookieManager.instance().getAllCookies();
}
}),
],
),
),
IconButton(
icon: Icon(Icons.arrow_back,
color: _canGoback ? null : Colors.grey),
onPressed: _canGoback
? () {
_webViewController?.goBack();
progress < 1.0
? LinearProgressIndicator(value: progress)
: Container(),
Expanded(
child: InAppWebView(
key: webViewKey,
onWebViewCreated: (controller) async {
_webViewController = controller;
},
onLoadStart: (controller, url) async {
setState(() {
_url = url.toString();
});
},
onPermissionRequest: (controller, request) async {
return PermissionResponse(
resources: request.resources,
action: PermissionResponseAction.GRANT);
},
shouldOverrideUrlLoading:
(controller, navigationAction) async {
var uri = navigationAction.request.url!;
if (![
"http",
"https",
"file",
"chrome",
"data",
"javascript",
"about"
].contains(uri.scheme)) {
if (await canLaunchUrl(uri)) {
// Launch the App
await launchUrl(
uri,
);
// and cancel the request
return NavigationActionPolicy.CANCEL;
}
: null,
}
return NavigationActionPolicy.ALLOW;
},
onLoadStop: (controller, url) async {
setState(() {
_url = url.toString();
});
},
onReceivedError: (controller, request, error) {},
onProgressChanged: (controller, progress) async {
setState(() {
this.progress = progress / 100;
});
},
onUpdateVisitedHistory:
(controller, url, isReload) async {
await ref.watch(
setCookieProvider(widget.source, url.toString())
.future);
final canGoback = await controller.canGoBack();
final canGoForward = await controller.canGoForward();
final title = await controller.getTitle();
setState(() {
_url = url.toString();
_title = title!;
_canGoback = canGoback;
_canGoForward = canGoForward;
});
},
initialSettings: InAppWebViewSettings(
userAgent: isar.settings.getSync(227)!.userAgent!),
initialUrlRequest:
URLRequest(url: WebUri.uri(Uri.parse(widget.url))),
),
),
IconButton(
icon: Icon(Icons.arrow_forward,
color: _canGoForward ? null : Colors.grey),
onPressed: _canGoForward
? () {
_webViewController?.goForward();
}
: null,
),
PopupMenuButton(itemBuilder: (context) {
return [
const PopupMenuItem<int>(
value: 0, child: Text("Refresh")),
const PopupMenuItem<int>(value: 1, child: Text("Share")),
const PopupMenuItem<int>(
value: 2, child: Text("Open in browser")),
const PopupMenuItem<int>(
value: 3, child: Text("Clear cookie")),
];
}, onSelected: (value) async {
if (value == 0) {
_webViewController?.reload();
} else if (value == 1) {
Share.share(_url);
} else if (value == 2) {
await InAppBrowser.openWithSystemBrowser(
url: WebUri.uri(Uri.parse(_url)));
} else if (value == 3) {
CookieManager.instance().getAllCookies();
}
}),
],
),
),
progress < 1.0
? LinearProgressIndicator(value: progress)
: Container(),
Expanded(
child: InAppWebView(
key: webViewKey,
onWebViewCreated: (controller) async {
_webViewController = controller;
},
onLoadStart: (controller, url) async {
setState(() {
_url = url.toString();
});
},
onPermissionRequest: (controller, request) async {
return PermissionResponse(
resources: request.resources,
action: PermissionResponseAction.GRANT);
},
shouldOverrideUrlLoading: (controller, navigationAction) async {
var uri = navigationAction.request.url!;
if (![
"http",
"https",
"file",
"chrome",
"data",
"javascript",
"about"
].contains(uri.scheme)) {
if (await canLaunchUrl(uri)) {
// Launch the App
await launchUrl(
uri,
);
// and cancel the request
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
onLoadStop: (controller, url) async {
setState(() {
_url = url.toString();
});
},
onReceivedError: (controller, request, error) {},
onProgressChanged: (controller, progress) async {
setState(() {
this.progress = progress / 100;
});
},
onUpdateVisitedHistory: (controller, url, isReload) async {
await ref.watch(
setCookieProvider(widget.source, url.toString()).future);
final canGoback = await controller.canGoBack();
final canGoForward = await controller.canGoForward();
final title = await controller.getTitle();
setState(() {
_url = url.toString();
_title = title!;
_canGoback = canGoback;
_canGoForward = canGoForward;
});
},
initialSettings: InAppWebViewSettings(
userAgent: isar.settings.getSync(227)!.userAgent!),
initialUrlRequest:
URLRequest(url: WebUri.uri(Uri.parse(widget.url))),
),
),
],
),
),
);
);
}
}
Future<String> getWebViewPath() async {
final document = await getApplicationDocumentsDirectory();
return p.join(
document.path,
'desktop_webview_window',
);
}
decodeHtml(Webview webview) async {
final html = await webview
.evaluateJavaScript("window.document.documentElement.outerHTML;");
// final cookie = await webview.evaluateJavaScript("window.document.cookie;");
// log(cookie!);
return jsonDecode(html!) as String;
}

View file

@ -1,8 +1,14 @@
import 'dart:developer';
import 'dart:io';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/dom.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/webview/webview.dart';
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'cloudflare_bypass.g.dart';
@ -12,49 +18,88 @@ Future<dom.Document?> cloudflareBypassDom(CloudflareBypassDomRef ref,
{required String url,
required String source,
required bool useUserAgent}) async {
// log(source);
final ua = isar.settings.getSync(227)!.userAgent!;
bool isOk = false;
dom.Document? htmll;
final ua = isar.settings.getSync(227)!.userAgent!;
HeadlessInAppWebView? headlessWebViewJapScan;
headlessWebViewJapScan = HeadlessInAppWebView(
onLoadStop: (controller, u) async {
String? html;
html = await controller.evaluateJavascript(
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
await Future.doWhile(() async {
if (html == null ||
html!.contains("Just a moment") ||
html!.contains("https://challenges.cloudflare.com")) {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
return true;
}
if (Platform.isWindows || Platform.isLinux) {
String? html;
final webview = await WebviewWindow.create(
configuration: CreateConfiguration(
windowHeight: 500,
windowWidth: 500,
userDataFolderWindows: await getWebViewPath(),
),
);
webview
..setBrightness(Brightness.dark)
..setApplicationNameForUserAgent(useUserAgent ? ua : '')
..launch(url);
await Future.delayed(const Duration(seconds: 10));
html = await decodeHtml(webview);
isOk = true;
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
});
html = await controller.evaluateJavascript(
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
htmll = dom.Document.html(html!);
isOk = true;
headlessWebViewJapScan!.dispose();
},
initialSettings: useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
initialUrlRequest: URLRequest(
url: WebUri.uri(Uri.parse(url)),
),
);
}
return true;
});
html = await decodeHtml(webview);
htmll = dom.Document.html(html!);
isOk = true;
webview.close();
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
}
return true;
});
} else {
HeadlessInAppWebView? headlessWebViewJapScan;
headlessWebViewJapScan = HeadlessInAppWebView(
onLoadStop: (controller, u) async {
String? html;
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
await Future.doWhile(() async {
if (html == null ||
html!.contains("Just a moment") ||
html!.contains("https://challenges.cloudflare.com")) {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
return true;
}
return false;
});
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
htmll = dom.Document.html(html!);
isOk = true;
headlessWebViewJapScan!.dispose();
},
initialSettings:
useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
initialUrlRequest: URLRequest(
url: WebUri.uri(Uri.parse(url)),
),
);
headlessWebViewJapScan.run();
headlessWebViewJapScan.run();
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
}
return true;
});
await ref.watch(setCookieProvider(source, url).future);
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
}
return true;
});
await ref.watch(setCookieProvider(source, url).future);
}
return htmll;
}
@ -66,42 +111,71 @@ Future<String> cloudflareBypassHtml(CloudflareBypassHtmlRef ref,
final ua = isar.settings.getSync(227)!.userAgent!;
bool isOk = false;
String? html;
HeadlessInAppWebView? headlessWebViewJapScan;
headlessWebViewJapScan = HeadlessInAppWebView(
onLoadStop: (controller, u) async {
html = await controller.evaluateJavascript(
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
await Future.doWhile(() async {
if (html == null ||
html!.contains("Just a moment") ||
html!.contains("Un instant…")) {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
return true;
}
return false;
});
await Future.delayed(Duration(seconds: 10));
html = await controller.evaluateJavascript(
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
isOk = true;
headlessWebViewJapScan!.dispose();
},
initialSettings: useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
initialUrlRequest: URLRequest(
url: WebUri.uri(Uri.parse(url)),
),
);
if (Platform.isWindows || Platform.isLinux) {
final webview = await WebviewWindow.create(
configuration: CreateConfiguration(
windowHeight: 500,
windowWidth: 500,
userDataFolderWindows: await getWebViewPath(),
),
);
webview
..setBrightness(Brightness.dark)
..setApplicationNameForUserAgent(useUserAgent ? ua : '')
..launch(url);
headlessWebViewJapScan.run();
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 5));
if (html == null) {
html = await decodeHtml(webview);
return true;
}
return false;
}
return true;
});
await ref.watch(setCookieProvider(source, url).future);
});
isOk = true;
webview.close();
} else {
HeadlessInAppWebView? headlessWebViewJapScan;
headlessWebViewJapScan = HeadlessInAppWebView(
onLoadStop: (controller, u) async {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
await Future.doWhile(() async {
if (html == null ||
html!.contains("Just a moment") ||
html!.contains("Un instant…")) {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
return true;
}
return false;
});
await Future.delayed(Duration(seconds: 10));
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
isOk = true;
headlessWebViewJapScan!.dispose();
},
initialSettings:
useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
initialUrlRequest: URLRequest(
url: WebUri.uri(Uri.parse(url)),
),
);
headlessWebViewJapScan.run();
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
}
return true;
});
await ref.watch(setCookieProvider(source, url).future);
}
return html!;
}

View file

@ -1,13 +1,16 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:html/dom.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/modules/webview/webview.dart';
import 'package:mangayomi/services/http_service/http_service.dart';
import 'package:mangayomi/sources/service.dart';
import 'package:mangayomi/sources/utils/utils.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/reg_exp_matcher.dart';
import 'package:mangayomi/utils/xpath_selector.dart';
@ -91,47 +94,76 @@ class Madara extends MangaYomiServices {
.toList();
bool isOk = false;
String? html;
HeadlessInAppWebView? headlessWebViewJapScan;
headlessWebViewJapScan = HeadlessInAppWebView(
onLoadStop: (controller, u) async {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
await Future.doWhile(() async {
if (Platform.isWindows || Platform.isLinux) {
final webview = await WebviewWindow.create(
configuration: CreateConfiguration(
windowHeight: 500,
windowWidth: 500,
userDataFolderWindows: await getWebViewPath(),
),
);
webview
..setBrightness(Brightness.dark)
..setApplicationNameForUserAgent(defaultUserAgent)
..launch(manga.url!);
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 10));
html = await decodeHtml(webview);
if (xpathSelector(html!)
.query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
.attrs
.isEmpty) {
html = await decodeHtml(webview);
return true;
}
return false;
});
html = await decodeHtml(webview);
isOk = true;
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
}
return true;
});
html = await decodeHtml(webview);
webview.close();
} else {
HeadlessInAppWebView? headlessWebViewJapScan;
headlessWebViewJapScan = HeadlessInAppWebView(
onLoadStop: (controller, u) async {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
if (xpathSelector(html!)
.query(
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
.attrs
.isEmpty) {
await Future.doWhile(() async {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
return true;
}
return false;
});
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
isOk = true;
headlessWebViewJapScan!.dispose();
},
initialUrlRequest: URLRequest(
url: WebUri.uri(Uri.parse(manga.url!)),
),
);
headlessWebViewJapScan.run();
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (isOk == true) {
return false;
}
return true;
});
if (xpathSelector(html!)
.query(
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
.attrs
.isEmpty) {
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
return true;
}
return false;
});
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
isOk = true;
headlessWebViewJapScan!.dispose();
},
initialUrlRequest: URLRequest(
url: WebUri.uri(Uri.parse(manga.url!)),
),
);
}
final xpath = xpathSelector(html!);
for (var url in xpath
.query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")

View file

@ -6,11 +6,15 @@
#include "generated_plugin_registrant.h"
#include <desktop_webview_window/desktop_webview_window_plugin.h>
#include <flutter_js/flutter_js_plugin.h>
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
g_autoptr(FlPluginRegistrar) flutter_js_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterJsPlugin");
flutter_js_plugin_register_with_registrar(flutter_js_registrar);

View file

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
desktop_webview_window
flutter_js
isar_flutter_libs
url_launcher_linux

View file

@ -5,6 +5,7 @@
import FlutterMacOS
import Foundation
import desktop_webview_window
import flutter_inappwebview
import flutter_js
import isar_flutter_libs
@ -15,6 +16,7 @@ import sqflite
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
FlutterJsPlugin.register(with: registry.registrar(forPlugin: "FlutterJsPlugin"))
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))

View file

@ -282,6 +282,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
desktop_webview_window:
dependency: "direct main"
description:
name: desktop_webview_window
sha256: da2fc164b46257c7a8b88649d3f2b34b4d98e7b7c403fb9e4183ebe8ff008004
url: "https://pub.dev"
source: hosted
version: "0.2.0"
draggable_menu:
dependency: "direct main"
description:

View file

@ -61,6 +61,7 @@ dependencies:
isar_flutter_libs: 3.1.0+1
share_plus: ^7.0.0
xpath_selector_html_parser: ^3.0.1
desktop_webview_window: ^0.2.0
# The following adds the Cupertino Icons font to your application.

View file

@ -6,6 +6,7 @@
#include "generated_plugin_registrant.h"
#include <desktop_webview_window/desktop_webview_window_plugin.h>
#include <flutter_js/flutter_js_plugin.h>
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
@ -13,6 +14,8 @@
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
DesktopWebviewWindowPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
FlutterJsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterJsPlugin"));
IsarFlutterLibsPluginRegisterWithRegistrar(

View file

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
desktop_webview_window
flutter_js
isar_flutter_libs
permission_handler_windows