如何在Flutter WebView中启用网页原生通知功能?
解决Flutter WebView中网页原生通知不显示的问题
要实现类似Chrome的网页原生通知效果,核心思路是通过JavaScript通道拦截网页的Notification API调用,再借助Flutter本地通知插件触发系统通知,完全适配网页原生的通知逻辑,无需依赖Firebase。
具体实现步骤
1. 添加依赖
在pubspec.yaml中引入必要插件:
dependencies: flutter: sdk: flutter webview_flutter: ^4.4.0 flutter_local_notifications: ^16.1.0 permission_handler: ^10.2.0 # 用于Android 13+动态申请通知权限
2. 核心代码实现
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:permission_handler/permission_handler.dart'; class WebViewWithNotifications extends StatefulWidget { final String targetUrl; const WebViewWithNotifications({super.key, required this.targetUrl}); @override State<WebViewWithNotifications> createState() => _WebViewWithNotificationsState(); } class _WebViewWithNotificationsState extends State<WebViewWithNotifications> { late WebViewController _webController; final FlutterLocalNotificationsPlugin _notificationPlugin = FlutterLocalNotificationsPlugin(); @override void initState() { super.initState(); _requestNotificationPermission(); _initNotificationPlugin(); _setupWebViewController(); } // 动态申请Android通知权限 void _requestNotificationPermission() async { if (await Permission.notification.isDenied) { await Permission.notification.request(); } } // 初始化本地通知插件 void _initNotificationPlugin() async { const AndroidInitializationSettings androidInitSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const InitializationSettings initSettings = InitializationSettings(android: androidInitSettings); await _notificationPlugin.initialize( initSettings, onDidReceiveNotificationResponse: (response) { // 可选:处理通知点击事件,比如跳转回WebView对应的页面 _webController.loadRequest(Uri.parse(widget.targetUrl)); }, ); } // 配置WebView并拦截通知请求 void _setupWebViewController() { _webController = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) // 添加JS通道,接收网页传递的通知数据 ..addJavaScriptChannel( 'WebNotificationChannel', onMessageReceived: (JavaScriptMessage message) { final Map<String, dynamic> notificationData = Map.castFrom(message.data); _showSystemNotification(notificationData); }, ) ..loadRequest(Uri.parse(widget.targetUrl)) // 注入JS代码重写Notification构造函数 ..runJavaScript(''' const OriginalNotification = window.Notification; window.Notification = function(title, options) { // 将通知参数发送给Flutter端 WebNotificationChannel.postMessage({ title: title, body: options?.body || '', icon: options?.icon || '' }); // 保留网页内的通知显示(可选,不需要可删除) return new OriginalNotification(title, options); }; // 同步原Notification的静态属性和方法 window.Notification.permission = OriginalNotification.permission; window.Notification.requestPermission = OriginalNotification.requestPermission; '''); } // 触发系统本地通知 void _showSystemNotification(Map<String, dynamic> data) async { const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'web_page_notifications', '网页通知', channelDescription: '接收来自内嵌网页的通知消息', importance: Importance.max, priority: Priority.high, showWhen: true, ); const NotificationDetails notificationDetails = NotificationDetails(android: androidDetails); await _notificationPlugin.show( DateTime.now().millisecondsSinceEpoch ~/ 1000, data['title'], data['body'], notificationDetails, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('内嵌网页')), body: WebViewWidget(controller: _webController), ); } }
3. Android平台额外配置
在android/app/src/main/AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
关键说明
- 完全适配网页原生的通知流程:保留网页的
Notification.requestPermission()授权逻辑,用户授权后网页发起的通知请求会被拦截并转为系统通知。 - 无需依赖第三方推送服务,仅通过WebView的JS桥接实现,和Chrome浏览器的通知体验一致。
- 支持通知点击回调,可自定义点击后的跳转逻辑。
内容的提问来源于stack exchange,提问作者Hassaan
相关产品推荐
相关产品推荐

