web_controller.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import 'dart:io';
  2. import 'package:get/get.dart';
  3. import 'package:device_info_plus/device_info_plus.dart';
  4. import 'package:package_info_plus/package_info_plus.dart';
  5. import 'package:flutter_inappwebview/flutter_inappwebview.dart';
  6. class WebController extends GetxController {
  7. var title = '';
  8. var url = '';
  9. InAppWebViewController? webViewController;
  10. final isLoading = true.obs;
  11. final loadingProgress = 0.0.obs;
  12. final canGoBack = false.obs; // 添加是否可以回退的观察变量
  13. // final _externalSchemes = [
  14. // 'mailto:',
  15. // 'tel:',
  16. // 'sms:',
  17. // 'geo:',
  18. // 'intent:',
  19. // 'market:'
  20. // ];
  21. @override
  22. void onInit() {
  23. if (Get.arguments != null) {
  24. title = Get.arguments['title'] ?? '';
  25. url = Get.arguments['url'] ?? '';
  26. }
  27. loadUserAgent();
  28. super.onInit();
  29. }
  30. Future<void> loadUserAgent() async {
  31. initWebView(await generateUserAgent());
  32. }
  33. Future<String> generateUserAgent() async {
  34. try {
  35. final deviceInfo = DeviceInfoPlugin();
  36. final packageInfo = await PackageInfo.fromPlatform();
  37. if (Platform.isIOS) {
  38. final iosInfo = await deviceInfo.iosInfo;
  39. // 使用类似 Safari 的 UA 格式
  40. return 'Mozilla/5.0 (iPhone; CPU iPhone OS ${iosInfo.systemVersion.replaceAll('.', '_')} like Mac OS X) '
  41. 'AppleWebKit/605.1.15 (KHTML, like Gecko) '
  42. 'Version/${packageInfo.version} Mobile/15E148 Safari/604.1';
  43. } else {
  44. final androidInfo = await deviceInfo.androidInfo;
  45. // 使用简化的 Android UA 格式,避免 WebView 标识
  46. return 'Mozilla/5.0 (Linux; Android ${androidInfo.version.release}; ${androidInfo.model}) '
  47. 'AppleWebKit/537.36 (KHTML, like Gecko) '
  48. 'Version/${packageInfo.version} Mobile Safari/537.36';
  49. }
  50. } catch (e) {
  51. // 如果获取设备信息失败,返回一个通用的安全 UA
  52. return 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) '
  53. 'AppleWebKit/605.1.15 (KHTML, like Gecko) '
  54. 'Version/16.6 Mobile/15E148 Safari/604.1';
  55. }
  56. }
  57. String? userAgent;
  58. void initWebView(String ua) {
  59. userAgent = ua;
  60. // InAppWebView 的初始化在 WebView 组件中完成
  61. // 这里只需要设置 URL
  62. if (url.isNotEmpty) {
  63. // URL 将在 WebView 组件中加载
  64. }
  65. }
  66. // 设置 WebViewController 的引用
  67. void setWebViewController(InAppWebViewController controller) {
  68. webViewController = controller;
  69. // 设置 User Agent
  70. if (userAgent != null) {
  71. webViewController?.setSettings(
  72. settings: InAppWebViewSettings(
  73. userAgent: userAgent!,
  74. javaScriptEnabled: true,
  75. useShouldOverrideUrlLoading: true,
  76. useOnLoadResource: true,
  77. mediaPlaybackRequiresUserGesture: false,
  78. allowsInlineMediaPlayback: true,
  79. iframeAllow: "camera; microphone",
  80. iframeAllowFullscreen: true,
  81. ),
  82. );
  83. }
  84. }
  85. // 检查是否可以回退的方法
  86. Future<bool> checkCanGoBack() async {
  87. try {
  88. if (webViewController != null) {
  89. final canBack = await webViewController!.canGoBack();
  90. canGoBack.value = canBack;
  91. }
  92. } catch (e) {
  93. // 如果检查失败,默认设置为false
  94. canGoBack.value = false;
  95. }
  96. return canGoBack.value;
  97. }
  98. // 回退方法
  99. Future<void> goBack() async {
  100. if (canGoBack.value && webViewController != null) {
  101. await webViewController!.goBack();
  102. // 回退后重新检查状态
  103. checkCanGoBack();
  104. }
  105. }
  106. // 刷新方法
  107. Future<void> reload() async {
  108. if (webViewController != null) {
  109. await webViewController!.reload();
  110. }
  111. }
  112. String? parseIntentUrl(String url) {
  113. if (!url.startsWith("intent://")) return url;
  114. // 提取 scheme
  115. final schemeMatch = RegExp(r"scheme=([a-zA-Z0-9.+-]+);").firstMatch(url);
  116. final scheme = schemeMatch?.group(1) ?? "https";
  117. // 替换 intent:// -> scheme://
  118. var cleanUrl = url
  119. .replaceFirst("intent://", "$scheme://")
  120. .replaceAll(RegExp(r"#Intent;.*;end$"), "");
  121. return cleanUrl;
  122. }
  123. String? parseFallbackUrl(String url) {
  124. final match = RegExp(r"S\.browser_fallback_url=([^;]+);").firstMatch(url);
  125. return match != null ? Uri.decodeComponent(match.group(1)!) : null;
  126. }
  127. }