rtc_prd/airhub_app/lib/pages/webview_page.dart
2026-02-06 16:03:32 +08:00

110 lines
4.0 KiB
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 WebViewPage extends StatefulWidget {
const WebViewPage({super.key});
@override
State<WebViewPage> createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
late final WebViewController _controller;
@override
void initState() {
super.initState();
late final PlatformWebViewControllerCreationParams params;
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
} 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) {
Navigator.of(context).pushNamed('/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),
);
}
}