import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter/services.dart'; class WebViewPage extends StatefulWidget { final erp_url; const WebViewPage({super.key, this.erp_url}); @override _WebViewPageState createState() => _WebViewPageState(); } class _WebViewPageState extends State { InAppWebViewController? _webViewController; final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); static const platform = MethodChannel('in.webgrid.generp/download'); @override void initState() { super.initState(); _initializeNotifications(); } // Initialize notifications Future _initializeNotifications() async { const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); final InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, ); await _notificationsPlugin.initialize(initializationSettings); // Create a notification channel for Android const AndroidNotificationChannel channel = AndroidNotificationChannel( 'download_channel', 'Downloads', description: 'Notifications for file downloads', importance: Importance.high, ); await _notificationsPlugin .resolvePlatformSpecificImplementation() ?.createNotificationChannel(channel); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("CRM WebView")), body: InAppWebView( initialUrlRequest: URLRequest(url: WebUri(widget.erp_url)), initialSettings: InAppWebViewSettings( javaScriptEnabled: true, domStorageEnabled: true, allowFileAccess: true, allowContentAccess: true, useShouldInterceptAjaxRequest: true, ), onWebViewCreated: (controller) { _webViewController = controller; _webViewController!.addJavaScriptHandler( handlerName: 'MobileAppJavascriptInterface', callback: (args) { print("JavaScript called MobileAppJavascriptInterface with args: $args"); return {'status': 'success'}; }, ); _webViewController!.addJavaScriptHandler( handlerName: 'downloadFile', callback: (args) async { final url = args[0] as String; await _handleDownload(url, '', 'application/octet-stream'); }, ); }, onDownloadStartRequest: (controller, downloadStartRequest) async { await _handleDownload( downloadStartRequest.url.toString(), downloadStartRequest.suggestedFilename!, downloadStartRequest.mimeType ?? 'application/octet-stream', ); }, shouldInterceptAjaxRequest: (controller, ajaxRequest) async { if (ajaxRequest.url.toString().contains('download')) { await _handleDownload(ajaxRequest.url.toString(), '', 'application/octet-stream'); return ajaxRequest; } return ajaxRequest; }, onConsoleMessage: (controller, consoleMessage) { print("JavaScript console message: ${consoleMessage.message}"); }, ), ); } Future _handleDownload(String url, String contentDisposition, String mimeType) async { // Request notification permission for Android 13+ if (await Permission.notification.request().isGranted) { try { // Show custom notification (optional, since DownloadManager shows its own) await _showNotification( id: 1, title: 'Download Started', body: 'Downloading ${url.split('/').last}', ); // Call native Android Download Manager final userAgent = 'Flutter InAppWebView'; await platform.invokeMethod('startDownload', { 'url': url, 'userAgent': userAgent, 'contentDisposition': contentDisposition, 'mimeType': mimeType, }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Download started for ${url.split('/').last}")), ); } catch (e) { await _showNotification( id: 1, title: 'Download Error', body: 'Error: $e', ); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Download error: $e")), ); } } else { await _showNotification( id: 1, title: 'Permission Denied', body: 'Notification permission denied', ); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Notification permission denied")), ); } } Future _showNotification({ required int id, required String title, required String body, }) async { final AndroidNotificationDetails androidPlatformChannelSpecifics = AndroidNotificationDetails( 'download_channel', 'Downloads', channelDescription: 'Notifications for file downloads', importance: Importance.high, priority: Priority.high, onlyAlertOnce: true, ); final NotificationDetails platformChannelSpecifics = NotificationDetails( android: androidPlatformChannelSpecifics, ); await _notificationsPlugin.show( id, title, body, platformChannelSpecifics, ); } }