news 2026/4/23 11:15:55

Flutter混合开发与WebView集成实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter混合开发与WebView集成实战

🔗实战项目:openharmonycrossplatform.csdn.net/content

📖 目录

  • 🌐 WebView集成

  • 🔗 混合通信

  • 📱 原生嵌入

  • 🎯 性能优化

🌐 一、WebView深度集成

1.1 WebView基础封装

dart

// lib/services/webview_service.dart import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; class WebViewService { // 创建WebViewController static Future<WebViewController> createController({ required String initialUrl, bool javascriptEnabled = true, bool autoMediaPlayback = false, }) async { late final PlatformWebViewControllerCreationParams params; if (WebViewPlatform.instance is WebKitWebViewPlatform) { params = WebKitWebViewControllerCreationParams( allowsInlineMediaPlayback: true, mediaTypesRequiringUserAction: autoMediaPlayback ? const <PlaybackMediaTypes>{} : const <PlaybackMediaTypes>{PlaybackMediaTypes.video}, ); } else { params = const PlatformWebViewControllerCreationParams(); } final controller = WebViewController.fromPlatformCreationParams(params); // 通用配置 await controller.setJavaScriptMode(JavascriptMode.unrestricted); await controller.setBackgroundColor(Colors.transparent); await controller.setNavigationDelegate(NavigationDelegate( onProgress: (int progress) { print('加载进度: $progress%'); }, onPageStarted: (String url) { print('开始加载: $url'); }, onPageFinished: (String url) { print('加载完成: $url'); }, onWebResourceError: (WebResourceError error) { print('加载错误: ${error.description}'); }, onNavigationRequest: (NavigationRequest request) { // 允许所有导航 return NavigationDecision.navigate; }, )); // 平台特定配置 if (controller.platform is AndroidWebViewController) { final androidController = controller.platform as AndroidWebViewController; await androidController.setMediaPlaybackRequiresUserGesture(false); } // 加载初始URL await controller.loadRequest(Uri.parse(initialUrl)); return controller; } // 执行JavaScript static Future<String?> evaluateJavascript( WebViewController controller, String script, ) async { try { return await controller.runJavaScriptReturningResult(script) as String?; } catch (e) { print('JS执行失败: $e'); return null; } } // 添加JavaScript通道 static void addJavascriptChannel( WebViewController controller, String channelName, void Function(JavascriptMessage) onMessageReceived, ) { controller.addJavaScriptChannel( channelName, onMessageReceived: onMessageReceived, ); } // 清除缓存 static Future<void> clearCache() async { final WebViewCookieManager cookieManager = WebViewCookieManager(); await cookieManager.clearCookies(); if (WebViewPlatform.instance is WebKitWebViewPlatform) { // iOS缓存清理 } else if (WebViewPlatform.instance is AndroidWebViewPlatform) { // Android缓存清理 } } }

1.2 自定义WebView组件

dart

// lib/ui/components/custom_webview.dart import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class CustomWebView extends StatefulWidget { final String initialUrl; final bool showProgress; final Widget? errorWidget; final Map<String, String>? headers; const CustomWebView({ super.key, required this.initialUrl, this.showProgress = true, this.errorWidget, this.headers, }); @override State<CustomWebView> createState() => _CustomWebViewState(); } class _CustomWebViewState extends State<CustomWebView> { late final WebViewController _controller; bool _isLoading = true; bool _hasError = false; double _progress = 0; @override void initState() { super.initState(); _initWebView(); } Future<void> _initWebView() async { try { _controller = await WebViewService.createController( initialUrl: widget.initialUrl, ); // 监听加载状态 _controller.setNavigationDelegate(NavigationDelegate( onProgress: (progress) { setState(() { _progress = progress / 100; _isLoading = progress < 100; }); }, onPageStarted: (url) { setState(() { _isLoading = true; _hasError = false; }); }, onPageFinished: (url) { setState(() { _isLoading = false; }); }, onWebResourceError: (error) { setState(() { _isLoading = false; _hasError = true; }); }, )); // 添加JS通道 WebViewService.addJavascriptChannel( _controller, 'FlutterChannel', (message) { _handleJsMessage(message.message); }, ); } catch (e) { setState(() { _hasError = true; _isLoading = false; }); } } void _handleJsMessage(String message) { print('收到JS消息: $message'); // 处理JS消息 } void _reload() { _controller.reload(); setState(() { _hasError = false; _isLoading = true; }); } void _goBack() async { if (await _controller.canGoBack()) { await _controller.goBack(); } } void _goForward() async { if (await _controller.canGoForward()) { await _controller.goForward(); } } @override Widget build(BuildContext context) { if (_hasError) { return widget.errorWidget ?? _buildErrorWidget(); } return Column( children: [ // 进度条 if (widget.showProgress && _isLoading) LinearProgressIndicator(value: _progress), // 导航栏 _buildNavigationBar(), // WebView内容 Expanded( child: WebViewWidget( controller: _controller, ), ), ], ); } Widget _buildNavigationBar() { return FutureBuilder<bool>( future: Future.wait([ _controller.canGoBack(), _controller.canGoForward(), ]).then((results) => true), builder: (context, snapshot) { return Container( color: Colors.grey[100], padding: const EdgeInsets.symmetric(horizontal: 8), child: Row( children: [ IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => _goBack(), ), IconButton( icon: const Icon(Icons.arrow_forward), onPressed: () => _goForward(), ), IconButton( icon: const Icon(Icons.refresh), onPressed: _reload, ), Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( widget.initialUrl, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ), ], ), ); }, ); } Widget _buildErrorWidget() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error, size: 64, color: Colors.red), const SizedBox(height: 16), const Text('加载失败'), const SizedBox(height: 16), ElevatedButton( onPressed: _reload, child: const Text('重新加载'), ), ], ), ); } }

🔗 二、混合通信系统

2.1 Flutter与JavaScript通信

dart

// lib/services/webview_bridge.dart import 'dart:convert'; class WebViewBridge { final WebViewController controller; WebViewBridge(this.controller); // 向JS发送消息 Future<void> sendToJavaScript(String event, dynamic data) async { final message = jsonEncode({'event': event, 'data': data}); final script = ''' if (window.flutterBridge) { window.flutterBridge.receiveFromFlutter($message); } '''; try { await controller.runJavaScript(script); } catch (e) { print('发送到JS失败: $e'); } } // 从JS接收消息 void setupJavaScriptChannels() { controller.addJavaScriptChannel( 'FlutterBridge', onMessageReceived: (message) { _handleJavaScriptMessage(message.message); }, ); } void _handleJavaScriptMessage(String message) { try { final decoded = jsonDecode(message) as Map<String, dynamic>; final event = decoded['event'] as String; final data = decoded['data']; print('收到JS事件: $event'); switch (event) { case 'userLogin': _handleUserLogin(data); break; case 'paymentComplete': _handlePaymentComplete(data); break; case 'navigationRequest': _handleNavigationRequest(data); break; default: print('未知事件: $event'); } } catch (e) { print('解析JS消息失败: $e'); } } void _handleUserLogin(dynamic data) { // 处理用户登录 print('用户登录: $data'); } void _handlePaymentComplete(dynamic data) { // 处理支付完成 print('支付完成: $data'); } void _handleNavigationRequest(dynamic data) { // 处理导航请求 print('导航请求: $data'); } // 注入JS桥接代码 Future<void> injectBridgeScript() async { const bridgeScript = ''' window.flutterBridge = { sendToFlutter: function(event, data) { FlutterBridge.postMessage( JSON.stringify({event: event, data: data}) ); }, receiveFromFlutter: function(message) { // 由具体页面实现 console.log('收到Flutter消息:', message); } }; '''; await controller.runJavaScript(bridgeScript); } }

2.2 HTML模板管理

dart

// lib/services/html_template_service.dart class HtmlTemplateService { // 加载本地HTML模板 Future<String> loadLocalTemplate(String assetPath) async { return await rootBundle.loadString(assetPath); } // 创建HTML页面 String createHtmlPage({ required String title, required String content, String? style, String? script, }) { return ''' <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>$title</title> <style> body { margin: 0; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; } $style </style> </head> <body> $content <script> $script </script> </body> </html> '''; } // 创建数据可视化HTML String createChartHtml(Map<String, dynamic> data) { final chartData = jsonEncode(data); return createHtmlPage( title: '数据图表', content: ''' <div id="chart" style="width: 100%; height: 400px;"></div> ''', script: ''' // 使用Chart.js或其他库渲染图表 const data = $chartData; renderChart(data); ''', ); } // 创建表单HTML String createFormHtml(List<Map<String, dynamic>> fields) { final fieldsHtml = fields.map((field) { return ''' <div class="form-group"> <label>${field['label']}</label> <input type="${field['type']}" name="${field['name']}" placeholder="${field['placeholder']}"> </div> '''; }).join(); return createHtmlPage( title: '表单', content: ''' <form id="myForm"> $fieldsHtml <button type="submit">提交</button> </form> ''', script: ''' document.getElementById('myForm').addEventListener('submit', function(e) { e.preventDefault(); const formData = new FormData(this); const data = Object.fromEntries(formData); window.flutterBridge.sendToFlutter('formSubmit', data); }); ''', ); } }

📱 三、原生嵌入方案

3.1 Flutter与原生视图混合

dart

// lib/ui/hybrid/native_embedding.dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class NativeEmbeddingPage extends StatefulWidget { const NativeEmbeddingPage({super.key}); @override State<NativeEmbeddingPage> createState() => _NativeEmbeddingPageState(); } class _NativeEmbeddingPageState extends State<NativeEmbeddingPage> { static const platform = MethodChannel('com.example/native_view'); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('原生嵌入'), ), body: Column( children: [ // Flutter部分 Expanded( flex: 2, child: ListView( children: [ ListTile( title: const Text('Flutter组件'), subtitle: const Text('标准的Flutter组件'), trailing: IconButton( icon: const Icon(Icons.refresh), onPressed: _callNativeMethod, ), ), ], ), ), // 原生视图容器 Expanded( flex: 3, child: _buildNativeViewContainer(), ), ], ), ); } Widget _buildNativeViewContainer() { if (Platform.isAndroid) { return AndroidView( viewType: 'com.example/native_view', creationParams: {'text': '从Flutter传递的参数'}, creationParamsCodec: const StandardMessageCodec(), onPlatformViewCreated: _onPlatformViewCreated, ); } else if (Platform.isIOS) { return UiKitView( viewType: 'com.example/native_view', creationParams: {'text': '从Flutter传递的参数'}, creationParamsCodec: const StandardMessageCodec(), onPlatformViewCreated: _onPlatformViewCreated, ); } return const Center(child: Text('不支持此平台')); } void _onPlatformViewCreated(int id) { // 原生视图创建完成 print('原生视图ID: $id'); // 设置消息处理器 platform.setMethodCallHandler(_handleMethodCall); } Future<dynamic> _handleMethodCall(MethodCall call) async { switch (call.method) { case 'nativeEvent': print('收到原生事件: ${call.arguments}'); return '收到'; default: throw PlatformException( code: '未实现', message: '方法 ${call.method} 未实现', ); } } Future<void> _callNativeMethod() async { try { final result = await platform.invokeMethod('flutterMethod', { 'param1': 'value1', 'param2': 'value2', }); print('原生方法返回: $result'); } on PlatformException catch (e) { print('调用失败: ${e.message}'); } } }

3.2 Android原生视图实现

kotlin

// android/src/main/kotlin/com/example/NativeView.kt package com.example import android.content.Context import android.view.View import android.widget.TextView import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.platform.PlatformView class NativeView( context: Context, messenger: BinaryMessenger, viewId: Int, creationParams: Map<String, Any>? ) : PlatformView { private val textView: TextView private val methodChannel: MethodChannel init { textView = TextView(context) methodChannel = MethodChannel(messenger, "com.example/native_view_$viewId") // 设置文本 val text = creationParams?.get("text") as? String ?: "默认文本" textView.text = "原生视图: $text" // 设置点击事件 textView.setOnClickListener { methodChannel.invokeMethod("nativeEvent", mapOf( "viewId" to viewId, "event" to "click" )) } // 设置方法处理器 methodChannel.setMethodCallHandler { call, result -> when (call.method) { "updateText" -> { val newText = call.arguments as? String textView.text = newText result.success(true) } else -> result.notImplemented() } } } override fun getView(): View { return textView } override fun dispose() { methodChannel.setMethodCallHandler(null) } }

🎯 四、性能优化策略

4.1 WebView性能优化

dart

// lib/services/webview_optimizer.dart class WebViewOptimizer { // 预加载WebView static Future<WebViewController> preloadWebView({ required String url, bool enableCache = true, }) async { final controller = await WebViewService.createController( initialUrl: url, ); if (enableCache) { _configureCache(controller); } return controller; } static void _configureCache(WebViewController controller) { // 配置缓存策略 if (controller.platform is AndroidWebViewController) { final androidController = controller.platform as AndroidWebViewController; // Android缓存配置 } } // 内存管理 static void manageMemory(WebViewController controller) { // 定期清理内存 controller.clearCache(); controller.clearLocalStorage(); } // 监控性能 static Stream<WebViewPerformance> monitorPerformance( WebViewController controller, ) async* { // 监控加载时间 final stopwatch = Stopwatch()..start(); // 监听页面加载完成 controller.setNavigationDelegate(NavigationDelegate( onPageFinished: (url) { stopwatch.stop(); print('页面加载时间: ${stopwatch.elapsedMilliseconds}ms'); }, )); // 监控内存使用 // 可以通过MethodChannel获取原生内存信息 } } class WebViewPerformance { final int loadTime; final int memoryUsage; final int networkRequests; const WebViewPerformance({ required this.loadTime, required this.memoryUsage, required this.networkRequests, }); }

4.2 混合应用打包优化

dart

// lib/build/build_optimizer.dart class BuildOptimizer { // 分析包大小 static Future<void> analyzePackageSize() async { // 检查资源文件 final assetFiles = await _getAssetFiles(); final largeFiles = assetFiles.where((file) => file.size > 1024 * 1024); if (largeFiles.isNotEmpty) { print('发现大文件:'); for (final file in largeFiles) { print(' ${file.path}: ${file.size ~/ 1024}KB'); } } } // 资源文件信息 static Future<List<AssetFile>> _getAssetFiles() async { final manifest = await rootBundle.loadString('AssetManifest.json'); final manifestMap = jsonDecode(manifest) as Map<String, dynamic>; final files = <AssetFile>[]; for (final key in manifestMap.keys) { if (key.contains('assets/web/')) { // Web资源文件 final byteData = await rootBundle.load(key); files.add(AssetFile( path: key, size: byteData.lengthInBytes, )); } } return files; } // 优化建议 static List<String> getOptimizationSuggestions() { return [ '1. 压缩图片资源', '2. 移除未使用的Web资源', '3. 使用CDN加载外部资源', '4. 启用GZIP压缩', '5. 实现资源懒加载', ]; } } class AssetFile { final String path; final int size; const AssetFile({ required this.path, required this.size, }); }

📊 总结

混合开发要点:

  1. WebView集成:深度定制、性能优化

  2. 混合通信:双向消息传递、数据同步

  3. 原生嵌入:平台视图、方法通道

  4. 性能优化:缓存策略、包大小控制

依赖配置:

yaml

dependencies: webview_flutter: ^4.4.2 webview_flutter_android: ^2.11.2 webview_flutter_wkwebview: ^2.16.1

欢迎大家加入[开源鸿蒙跨平台开发者社区](https://openharmonycrossplatform.csdn.net),一起共建开源鸿蒙跨平台生态。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 11:34:50

三菱FX5U与三菱E700变频器专用协议通讯实践

三菱FX5U与三菱E700变频器 专用协议方式通讯程序(SL5U-25) 通讯说明&#xff1a;用三菱FX5U的PLC实现与三菱E700变频器的变频器专用协议通讯 器件&#xff1a;三菱FX5U PLC&#xff0c;三菱E700变频器&#xff0c;昆仑通态TPC7022NI触摸屏 功能&#xff1a;触摸屏上设置每台频率…

作者头像 李华
网站建设 2026/4/23 3:07:33

国内纸纱线FSC春夏14至16针,实力公司推荐排行榜揭秘

国内纸纱线FSC春夏14至16针&#xff0c;实力公司推荐排行榜揭秘引言在时尚与环保并行的当下&#xff0c;纸纱线FSC春夏14至16针产品凭借其独特的质感和环保属性&#xff0c;在纺织市场中崭露头角。这种纱线不仅满足了消费者对春夏衣物轻薄透气的需求&#xff0c;还响应了全球可…

作者头像 李华
网站建设 2026/4/20 19:04:08

Linux系统编程——进程进阶:父子关系、终止与资源回收

目录 一、父子进程关系 二、进程终止的 8 种场景 三、退出函数 1.exit() 1&#xff09;基础信息 2&#xff09;核心特点 3&#xff09;参数 status 的作用 4&#xff09;exit 与 return 的区别 2._exit() 1&#xff09;基础信息 2&#xff09;核心特点 四、退出后的…

作者头像 李华