import 'package:flutter/material.dart'; import 'package:go_router/go_router.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 WebViewPage extends StatefulWidget { const WebViewPage({super.key}); @override State createState() => _WebViewPageState(); } class _WebViewPageState extends State { late final WebViewController _controller; @override void initState() { super.initState(); late final PlatformWebViewControllerCreationParams params; if (WebViewPlatform.instance is WebKitWebViewPlatform) { params = WebKitWebViewControllerCreationParams( allowsInlineMediaPlayback: true, mediaTypesRequiringUserAction: const {}, ); } else { params = const PlatformWebViewControllerCreationParams(); } final WebViewController controller = WebViewController.fromPlatformCreationParams(params); controller ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(const Color(0x00000000)) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { debugPrint('WebView is loading (progress : $progress%)'); }, onPageStarted: (String url) { debugPrint('Page started loading: $url'); }, onPageFinished: (String url) { debugPrint('Page finished loading: $url'); }, onWebResourceError: (WebResourceError error) { debugPrint(''' Page resource error: code: ${error.errorCode} description: ${error.description} errorType: ${error.errorType} isForMainFrame: ${error.isForMainFrame} '''); }, onNavigationRequest: (NavigationRequest request) { if (request.url.contains('bluetooth.html')) { // Intercept bluetooth.html and navigate to native BluetoothPage debugPrint( 'Intercepting navigation to bluetooth.html -> Native Route', ); // We need context to navigate, but initState doesn't have it easily available // inside this callback unless we store a reference or use a GlobalKey. // However, since we are in a State object, we can use 'context' if mounted? // Actually, NavigationDelegate callbacks are not bound to context directly. // We should probably move the controller creation or use a helper. // BUT, since this is a callback, 'context' of the State is available in the closure! // Warning: don't use 'context' across async gaps without checking mounted. // Since this is synchronous, it should be fine to schedule a navigation. // We must return NavigationDecision.prevent to stop WebView. // And execute navigation asynchronously to avoid blocking. Future.microtask(() { if (mounted) { context.go('/bluetooth'); } }); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ) ..loadFlutterAsset( 'assets/www/index.html', ); // CHANGED: Load Home directly if (controller.platform is AndroidWebViewController) { AndroidWebViewController.enableDebugging(true); (controller.platform as AndroidWebViewController) .setMediaPlaybackRequiresUserGesture(false); } _controller = controller; } @override Widget build(BuildContext context) { // We want the WebView to control the full screen, including status bar usually, // but SafeArea might be needed if the Web content doesn't handle padding. // Our CSS handles env(safe-area-inset-top), so we can disable SafeArea here // or keep top:false. return Scaffold( backgroundColor: Colors.white, body: WebViewWidget(controller: _controller), ); } }