From bd5937f910457c20f70ee80fae9187993334db01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9E=97=E9=94=8B?= <2535831261@qq.com>
Date: Wed, 8 Jul 2026 12:03:25 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20HTML=20=E8=B5=84=E6=BA=90?=
=?UTF-8?q?=E8=B7=AF=E5=BE=84=E5=88=B0=20pubspec.yaml=EF=BC=9B=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=20Auth=20=E9=A1=B5=E9=9D=A2=E4=BB=A5=E4=BD=BF?=
=?UTF-8?q?=E7=94=A8=E6=96=B0=E7=9A=84=20Webview=20=E7=BB=84=E4=BB=B6?=
=?UTF-8?q?=E5=8A=A0=E8=BD=BD=E6=9C=AC=E5=9C=B0=20HTML=20=E6=96=87?=
=?UTF-8?q?=E4=BB=B6=EF=BC=9B=E9=87=8D=E6=9E=84=20WebviewPage=20=E4=BB=A5?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=A0=E8=BD=BD=E6=9C=AC=E5=9C=B0=E8=B5=84?=
=?UTF-8?q?=E4=BA=A7=E5=92=8C=E6=B3=A8=E5=85=A5=20JavaScript=20=E9=80=9A?=
=?UTF-8?q?=E4=BF=A1=E6=A1=A5=E6=8E=A5=EF=BC=9B=E6=B8=85=E7=90=86=E4=B8=8D?=
=?UTF-8?q?=E5=BF=85=E8=A6=81=E7=9A=84=E5=AF=BC=E5=85=A5=E5=92=8C=E6=B3=A8?=
=?UTF-8?q?=E9=87=8A=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
assets/html/index.html | 48 +++++++
lib/features/auth/pages/page_auth.dart | 7 +-
.../scan_qrcode/pages/page_push_test.dart | 3 +-
lib/gen/assets.gen.dart | 16 +++
lib/shared/widgets/app_webview.dart | 128 ++++++++++++++----
pubspec.yaml | 2 +
6 files changed, 172 insertions(+), 32 deletions(-)
create mode 100644 assets/html/index.html
diff --git a/assets/html/index.html b/assets/html/index.html
new file mode 100644
index 0000000..76a8495
--- /dev/null
+++ b/assets/html/index.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/features/auth/pages/page_auth.dart b/lib/features/auth/pages/page_auth.dart
index c135f88..c126b69 100644
--- a/lib/features/auth/pages/page_auth.dart
+++ b/lib/features/auth/pages/page_auth.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
-import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart';
+import 'package:recording_tool/shared/widgets/app_webview.dart';
import 'package:recording_tool/shared/widgets/widgets.dart';
class AuthPageWidget extends StatefulWidget {
@@ -35,7 +35,10 @@ class _AuthPageWidgetState extends State {
child: AppButton(
label: '确定',
onPressed: () {
- AppNavigator.push(const ScanQrCodePage());
+ // AppNavigator.push(const ScanQrCodePage());
+ AppNavigator.push(
+ const WebviewPage(assetPath: 'assets/html/index.html'),
+ );
},
variant: AppButtonVariant.secondary,
),
diff --git a/lib/features/scan_qrcode/pages/page_push_test.dart b/lib/features/scan_qrcode/pages/page_push_test.dart
index 317fbaf..5cc30aa 100644
--- a/lib/features/scan_qrcode/pages/page_push_test.dart
+++ b/lib/features/scan_qrcode/pages/page_push_test.dart
@@ -1,6 +1,5 @@
-import 'package:flutter/material.dart';
-import 'package:flutter/material.dart';
import 'package:apivideo_live_stream/apivideo_live_stream.dart';
+import 'package:flutter/material.dart';
import 'package:recording_tool/shared/widgets/app_bar.dart';
class PushSteamTestWidget extends StatefulWidget {
diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart
index d2870ba..80a04cf 100644
--- a/lib/gen/assets.gen.dart
+++ b/lib/gen/assets.gen.dart
@@ -11,6 +11,16 @@
import 'package:flutter/widgets.dart';
+class $AssetsHtmlGen {
+ const $AssetsHtmlGen();
+
+ /// File path: assets/html/index.html
+ String get index => 'assets/html/index.html';
+
+ /// List of all assets
+ List get values => [index];
+}
+
class $AssetsImagesGen {
const $AssetsImagesGen();
@@ -30,18 +40,24 @@ class $AssetsImagesGen {
AssetGenImage get imageLogo =>
const AssetGenImage('assets/images/image_logo.png');
+ /// File path: assets/images/image_vs.png
+ AssetGenImage get imageVs =>
+ const AssetGenImage('assets/images/image_vs.png');
+
/// List of all assets
List get values => [
imageCopy,
imageDelete,
imageDialogBg,
imageLogo,
+ imageVs,
];
}
class Assets {
const Assets._();
+ static const $AssetsHtmlGen html = $AssetsHtmlGen();
static const $AssetsImagesGen images = $AssetsImagesGen();
}
diff --git a/lib/shared/widgets/app_webview.dart b/lib/shared/widgets/app_webview.dart
index 0c724fb..92e2f2a 100644
--- a/lib/shared/widgets/app_webview.dart
+++ b/lib/shared/widgets/app_webview.dart
@@ -5,16 +5,19 @@ import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
class WebviewPage extends StatefulWidget {
- final String url;
+ final String? url;
final String? title;
+ final String? assetPath;
- const WebviewPage({super.key, required this.url, this.title});
+ const WebviewPage({super.key, this.url, this.title, this.assetPath});
@override
State createState() => WebviewPageState();
}
class WebviewPageState extends State {
+ static const String _javaScriptChannelName = 'AppBridge';
+
WebViewController? _controller;
bool _isLoading = true;
String? _errorMessage;
@@ -26,11 +29,12 @@ class WebviewPageState extends State {
}
Future _initController() async {
- if (widget.url?.isEmpty ?? true) {
+ if ((widget.url?.isEmpty ?? true) && widget.assetPath == null) {
return;
}
final params = _createPlatformParams();
- final controller = WebViewController.fromPlatformCreationParams(params)
+ late final WebViewController controller;
+ controller = WebViewController.fromPlatformCreationParams(params)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Colors.transparent)
..setNavigationDelegate(
@@ -46,8 +50,9 @@ class WebviewPageState extends State {
_errorMessage = null;
});
},
- onPageFinished: (String url) {
+ onPageFinished: (String url) async {
debugPrint('webview - page finished: $url');
+ await _injectPostMessageBridge(controller);
if (!mounted) return;
setState(() => _isLoading = false);
},
@@ -72,17 +77,28 @@ class WebviewPageState extends State {
),
);
+ controller.addJavaScriptChannel(
+ _javaScriptChannelName,
+ onMessageReceived: (JavaScriptMessage message) {
+ _onMessageReceived(message);
+ },
+ );
+
if (controller.platform is AndroidWebViewController) {
AndroidWebViewController.enableDebugging(kDebugMode);
await (controller.platform as AndroidWebViewController)
.setMediaPlaybackRequiresUserGesture(false);
}
- final targetUrl = widget.url ?? '';
try {
- await controller.loadRequest(Uri.parse(targetUrl));
+ if (widget.assetPath != null) {
+ await controller.loadFlutterAsset(widget.assetPath!);
+ } else {
+ final targetUrl = widget.url ?? '';
+ await controller.loadRequest(Uri.parse(targetUrl));
+ }
} catch (e) {
- debugPrint('webview - loadRequest failed: $e');
+ debugPrint('webview - load failed: $e');
if (!mounted) return;
setState(() {
_isLoading = false;
@@ -95,6 +111,81 @@ class WebviewPageState extends State {
setState(() => _controller = controller);
}
+ void _onMessageReceived(JavaScriptMessage message) {
+ debugPrint('收到来自 WebView 的消息: ${message.message}');
+ }
+
+ /// 脚本注入传输给h5 数据
+ Future _injectH5NeedData(WebViewController controller) async {
+ try {
+ await controller.runJavaScript('''
+ (function () {
+ if (window.__appBridgePostMessageBridgeInstalled) {
+ return;
+ }
+
+ window.__appBridgePostMessageBridgeInstalled = true;
+ window.addEventListener('message', function (event) {
+ if (!window.AppBridge || !window.AppBridge.postMessage) {
+ return;
+ }
+
+ var payload = event.data;
+ if (typeof payload !== 'string') {
+ try {
+ payload = JSON.stringify(payload);
+ if (typeof payload === 'undefined') {
+ payload = String(event.data);
+ }
+ } catch (error) {
+ payload = String(payload);
+ }
+ }
+
+ window.AppBridge.postMessage(payload);
+ });
+ })();
+ ''');
+ } catch (e) {
+ debugPrint('webview - inject postMessage bridge failed: $e');
+ }
+ }
+
+ Future _injectPostMessageBridge(WebViewController controller) async {
+ // try {
+ // await controller.runJavaScript('''
+ // (function () {
+ // if (window.__appBridgePostMessageBridgeInstalled) {
+ // return;
+ // }
+
+ // window.__appBridgePostMessageBridgeInstalled = true;
+ // window.addEventListener('message', function (event) {
+ // if (!window.AppBridge || !window.AppBridge.postMessage) {
+ // return;
+ // }
+
+ // var payload = event.data;
+ // if (typeof payload !== 'string') {
+ // try {
+ // payload = JSON.stringify(payload);
+ // if (typeof payload === 'undefined') {
+ // payload = String(event.data);
+ // }
+ // } catch (error) {
+ // payload = String(payload);
+ // }
+ // }
+
+ // window.AppBridge.postMessage(payload);
+ // });
+ // })();
+ // ''');
+ // } catch (e) {
+ // debugPrint('webview - inject postMessage bridge failed: $e');
+ // }
+ }
+
PlatformWebViewControllerCreationParams _createPlatformParams() {
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
return WebKitWebViewControllerCreationParams(
@@ -110,27 +201,8 @@ class WebviewPageState extends State {
return Scaffold(
backgroundColor: Colors.transparent,
extendBodyBehindAppBar: true,
- appBar: AppBar(
- backgroundColor: Colors.transparent,
- elevation: 0,
- title: Text(
- widget.title ?? '',
- style: const TextStyle(color: Colors.white),
- ),
- leading: IconButton(
- icon: const Icon(Icons.arrow_back, color: Colors.white),
- onPressed: () async {
- final controller = _controller;
- if (controller != null && await controller.canGoBack()) {
- await controller.goBack();
- } else {
- if (context.mounted) Navigator.of(context).maybePop();
- }
- },
- ),
- iconTheme: const IconThemeData(color: Colors.white),
- ),
+ // appBar: myAppBar(context: context),
body: _buildBody(),
);
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 4669b82..e7d265a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -80,6 +80,8 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/
+ - assets/html/
+
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg