Flutter嵌入式浏览器插件webview_cef的使用
Flutter嵌入式浏览器插件webview_cef的使用
简介
webview_cef
是一个基于Chromium Embedded Framework (CEF) 的Flutter桌面WebView插件。它支持Windows、macOS和Linux平台,适用于需要在Flutter应用中嵌入Web内容的场景。
支持的操作系统
- ✅ Windows 7+
- ✅ macOS 10.12+
- ✅ Linux (x64 和 arm64)
设置步骤
Windows
在您的应用程序文件夹中,需要在 windows\runner\main.cpp
中添加一些代码:
// Introduce the source code of this plugin into your own project
#include "webview_cef/webview_cef_plugin_c_api.h"
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
// Start cef deamon processes. MUST CALL FIRST
initCEFProcesses();
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
// Add this line to enable cef keybord input, and enable to post messages to flutter engine thread from cef message loop thread.
handleWndProcForCEF(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
}
首次构建项目时,会自动下载预构建的cef bin包(200MB),因此第一次构建可能需要较长时间。
macOS
将仓库克隆到您的项目位置,并更新 pubspec.yaml
文件:
dependencies:
# Webview
webview_cef:
path: ./packages/webview_cef # Or wherever you cloned the repo
然后按照以下步骤操作:
- 下载预构建的cef捆绑包(根据您的目标机器架构选择arm64或intel版本)。
- 解压缩并将所有文件放入
macos/third/cef
目录(在克隆的仓库中,而不是您的项目中)。 - 运行示例应用程序。
Linux
只需在 pubspec.yaml
中添加 webview_cef
即可:
dependencies:
webview_cef: ^latest_version
示例代码
以下是完整的示例代码,展示如何使用 webview_cef
插件:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_cef/webview_cef.dart';
import 'package:webview_cef/src/webview_inject_user_script.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late WebViewController _controller;
final _textController = TextEditingController();
String title = "";
Map allCookies = {};
@override
void initState() {
var injectUserScripts = InjectUserScripts();
injectUserScripts.add(UserScript("console.log('injectScript_in_LoadStart')", ScriptInjectTime.LOAD_START));
injectUserScripts.add(UserScript("console.log('injectScript_in_LoadEnd')", ScriptInjectTime.LOAD_END));
_controller = WebviewManager().createWebView(
loading: const Text("not initialized"),
injectUserScripts: injectUserScripts);
super.initState();
initPlatformState();
}
@override
void dispose() {
_controller.dispose();
WebviewManager().quit();
super.dispose();
}
Future<void> initPlatformState() async {
await WebviewManager().initialize(userAgent: "test/userAgent");
String url = "www.baidu.com";
_textController.text = url;
_controller.setWebviewListener(WebviewEventsListener(
onTitleChanged: (t) {
setState(() {
title = t;
});
},
onUrlChanged: (url) {
_textController.text = url;
final Set<JavascriptChannel> jsChannels = {
JavascriptChannel(
name: 'Print',
onMessageReceived: (JavascriptMessage message) {
print(message.message);
_controller.sendJavaScriptChannelCallBack(false, "{'code':'200','message':'print succeed!'}", message.callbackId, message.frameId);
}),
};
_controller.setJavaScriptChannels(jsChannels);
_controller.executeJavaScript("function abc(e){return 'abc:'+ e}");
_controller.evaluateJavascript("abc('test')").then((value) => print(value));
},
onLoadStart: (controller, url) {
print("onLoadStart => $url");
},
onLoadEnd: (controller, url) {
print("onLoadEnd => $url");
},
));
await _controller.initialize(_textController.text);
if (!mounted) return;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true),
home: Scaffold(
body: Column(
children: [
SizedBox(height: 20, child: Text(title)),
Row(
children: [
SizedBox(height: 48, child: MaterialButton(onPressed: () { _controller.reload(); }, child: const Icon(Icons.refresh))),
SizedBox(height: 48, child: MaterialButton(onPressed: () { _controller.goBack(); }, child: const Icon(Icons.arrow_left))),
SizedBox(height: 48, child: MaterialButton(onPressed: () { _controller.goForward(); }, child: const Icon(Icons.arrow_right))),
SizedBox(height: 48, child: MaterialButton(onPressed: () { _controller.openDevTools(); }, child: const Icon(Icons.developer_mode))),
Expanded(child: TextField(controller: _textController, onSubmitted: (url) {
_controller.loadUrl(url);
WebviewManager().visitAllCookies().then((value) {
allCookies = Map.of(value);
if (url == "baidu.com") {
if (!allCookies.containsKey('.$url') || !Map.of(allCookies['.$url']).containsKey('test')) {
WebviewManager().setCookie(url, 'test', 'test123');
} else {
WebviewManager().deleteCookie(url, 'test');
}
}
});
})),
],
),
Expanded(
child: Row(
children: [
ValueListenableBuilder(
valueListenable: _controller,
builder: (context, value, child) {
return _controller.value ? Expanded(child: _controller.webviewWidget) : _controller.loadingWidget;
},
),
],
))
],
)),
);
}
}
截图
您可以参考以下截图来了解 webview_cef
在不同平台上的运行效果:
- Windows:
- macOS:
- Linux:
通过以上步骤和示例代码,您可以在Flutter应用中集成并使用 webview_cef
插件。希望这些信息对您有所帮助!
更多关于Flutter嵌入式浏览器插件webview_cef的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter嵌入式浏览器插件webview_cef的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,使用webview_cef
插件可以嵌入一个基于Chromium Embedded Framework (CEF) 的WebView组件。这对于需要在Flutter应用中展示网页内容或者嵌入网页应用的情况非常有用。以下是一个简单的代码示例,展示了如何在Flutter应用中使用webview_cef
插件。
首先,确保你已经在pubspec.yaml
文件中添加了webview_cef
依赖:
dependencies:
flutter:
sdk: flutter
webview_cef: ^x.y.z # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,在你的Flutter应用中配置和使用webview_cef
。以下是一个完整的示例,展示了如何嵌入WebView并加载一个URL。
主文件 main.dart
import 'package:flutter/material.dart';
import 'package:webview_cef/webview_cef.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter WebView CEF Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: WebViewPage(),
);
}
}
class WebViewPage extends StatefulWidget {
@override
_WebViewPageState createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
WebViewController? _controller;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView CEF Demo'),
),
body: WebView(
initialUrl: 'https://www.example.com',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
onPageFinished: (String url) {
print('Page finished loading: $url');
},
geolocationEnabled: true,
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
if (_controller != null) {
_controller!.evaluateJavascript('alert("Hello from Flutter!");');
}
},
tooltip: 'Execute JS',
child: Icon(Icons.code),
),
);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
}
平台配置
由于webview_cef
是一个平台相关的插件,你可能需要在iOS和Android平台上进行一些额外的配置。以下是一些基本的配置步骤:
iOS
- 在
ios/Runner/Info.plist
中添加必要的权限配置,例如访问网络的权限。 - 确保在
ios/Podfile
中启用了CEF相关的配置(这通常由插件自动处理,但你可能需要检查)。
Android
- 在
android/app/src/main/AndroidManifest.xml
中添加必要的权限配置,例如访问网络的权限。 - 确保
android/build.gradle
和android/app/build.gradle
文件中的配置支持CEF的编译。
注意事项
- 由于CEF是一个重量级的组件,它可能会增加应用的体积和启动时间。
- 确保你遵循了CEF的许可协议。
- 在实际项目中,你可能需要处理更多的WebView事件和配置,例如错误处理、导航控制等。
以上示例提供了一个基本的起点,你可以根据具体需求进行扩展和定制。