import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:nomo/config/theme/theme_extensions/theme_extension.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../../utils/log/logger.dart'; import '../../../base/base_view.dart'; import '../../../widgets/ix_app_bar.dart'; import '../controllers/web_controller.dart'; class WebView extends BaseView { const WebView({super.key}); @override PreferredSizeWidget? get appBar => IXAppBar( title: controller.title, // 不需要传递颜色参数,会自动使用响应式主题 onBackPressed: () async { if (await controller.checkCanGoBack()) { controller.goBack(); } else { Get.back(); } }, actions: [ IconButton( onPressed: () { controller.reload(); }, icon: const Icon(Icons.refresh_rounded), ), Obx( () => controller.canGoBack.value ? IconButton( onPressed: () { Get.back(); }, icon: const Icon(Icons.close_rounded), ) : const SizedBox.shrink(), ), ], ); @override Widget buildContent(BuildContext context) { return _buildWebContent(); } Widget _buildWebContent() { return Stack( children: [ InAppWebView( initialUrlRequest: URLRequest(url: WebUri(controller.url)), initialSettings: InAppWebViewSettings( userAgent: controller.userAgent, javaScriptEnabled: true, useShouldOverrideUrlLoading: true, useOnLoadResource: true, mediaPlaybackRequiresUserGesture: false, allowsInlineMediaPlayback: true, iframeAllow: "camera; microphone", iframeAllowFullscreen: true, ), onWebViewCreated: (InAppWebViewController webViewController) { controller.setWebViewController(webViewController); }, onProgressChanged: (InAppWebViewController webViewController, int progress) { controller.loadingProgress.value = progress / 100; controller.isLoading.value = progress < 100; }, onLoadStart: (InAppWebViewController webViewController, Uri? url) { controller.checkCanGoBack(); }, onLoadStop: (InAppWebViewController webViewController, Uri? url) { controller.isLoading.value = false; controller.loadingProgress.value = 0.0; controller.checkCanGoBack(); }, onReceivedError: ( InAppWebViewController webViewController, WebResourceRequest request, WebResourceError error, ) { controller.isLoading.value = false; controller.loadingProgress.value = 0.0; }, shouldOverrideUrlLoading: ( InAppWebViewController webViewController, NavigationAction navigationAction, ) async { final url = navigationAction.request.url?.toString() ?? ''; try { final uri = Uri.parse(url); // 处理 intent:// 链接 if (url.startsWith("intent://")) { final parsedUrl = controller.parseIntentUrl(url); final fallbackUrl = controller.parseFallbackUrl(url); if (parsedUrl != null && await canLaunchUrl(Uri.parse(parsedUrl))) { await launchUrl( Uri.parse(parsedUrl), mode: LaunchMode.externalApplication, ); } else if (fallbackUrl != null && await canLaunchUrl(Uri.parse(fallbackUrl))) { await launchUrl( Uri.parse(fallbackUrl), mode: LaunchMode.externalApplication, ); } return NavigationActionPolicy.CANCEL; } // 处理下载链接 else if (uri.path.endsWith(".apk") || uri.path.endsWith(".pdf") || uri.path.contains("download")) { if (await canLaunchUrl(uri)) { await launchUrl( uri, mode: LaunchMode.externalApplication, ); } return NavigationActionPolicy.CANCEL; } // 处理 http/https 链接 if (uri.scheme == 'http' || uri.scheme == 'https') { return NavigationActionPolicy.ALLOW; } // 处理其他 scheme if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); } } catch (e) { log("Error handling shouldOverrideUrlLoading: $e"); } return NavigationActionPolicy.CANCEL; }, ), Obx( () => controller.isLoading.value ? LinearProgressIndicator( value: controller.loadingProgress.value, backgroundColor: Get.reactiveTheme.scaffoldBackgroundColor, minHeight: 2.w, valueColor: AlwaysStoppedAnimation( Get.reactiveTheme.primaryColor, ), ) : const SizedBox.shrink(), ), ], ); } }