添加 HTML 资源路径到 pubspec.yaml;更新 Auth 页面以使用新的 Webview 组件加载本地 HTML 文件;重构 WebviewPage 以支持加载本地资产和注入 JavaScript 通信桥接;清理不必要的导入和注释。
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
<style>
|
||||||
|
.aa {
|
||||||
|
|
||||||
|
|
||||||
|
margin: 100px;
|
||||||
|
width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<button class="aa" onclick="postMsgToAPP()">向 APP 发送数据</button>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
if (window.__appInstallData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__appInstallData = true;
|
||||||
|
|
||||||
|
window.AppBridge.token = 'xxx';
|
||||||
|
window.AppBridge.playId = 'xxx';
|
||||||
|
|
||||||
|
///TODO 后续业务
|
||||||
|
|
||||||
|
})();
|
||||||
|
function postMsgToAPP() {
|
||||||
|
window.AppBridge.postMessage(JSON.stringify({ type: 'navigator_pop', value: null }))
|
||||||
|
console.log(window.AppBridge.token)
|
||||||
|
console.log(window.AppBridge.playId)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:recording_tool/app/router/app_navigator.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';
|
import 'package:recording_tool/shared/widgets/widgets.dart';
|
||||||
|
|
||||||
class AuthPageWidget extends StatefulWidget {
|
class AuthPageWidget extends StatefulWidget {
|
||||||
@@ -35,7 +35,10 @@ class _AuthPageWidgetState extends State<AuthPageWidget> {
|
|||||||
child: AppButton(
|
child: AppButton(
|
||||||
label: '确定',
|
label: '确定',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
AppNavigator.push(const ScanQrCodePage());
|
// AppNavigator.push(const ScanQrCodePage());
|
||||||
|
AppNavigator.push(
|
||||||
|
const WebviewPage(assetPath: 'assets/html/index.html'),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
variant: AppButtonVariant.secondary,
|
variant: AppButtonVariant.secondary,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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:apivideo_live_stream/apivideo_live_stream.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_bar.dart';
|
import 'package:recording_tool/shared/widgets/app_bar.dart';
|
||||||
|
|
||||||
class PushSteamTestWidget extends StatefulWidget {
|
class PushSteamTestWidget extends StatefulWidget {
|
||||||
|
|||||||
@@ -11,6 +11,16 @@
|
|||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
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<String> get values => [index];
|
||||||
|
}
|
||||||
|
|
||||||
class $AssetsImagesGen {
|
class $AssetsImagesGen {
|
||||||
const $AssetsImagesGen();
|
const $AssetsImagesGen();
|
||||||
|
|
||||||
@@ -30,18 +40,24 @@ class $AssetsImagesGen {
|
|||||||
AssetGenImage get imageLogo =>
|
AssetGenImage get imageLogo =>
|
||||||
const AssetGenImage('assets/images/image_logo.png');
|
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 of all assets
|
||||||
List<AssetGenImage> get values => [
|
List<AssetGenImage> get values => [
|
||||||
imageCopy,
|
imageCopy,
|
||||||
imageDelete,
|
imageDelete,
|
||||||
imageDialogBg,
|
imageDialogBg,
|
||||||
imageLogo,
|
imageLogo,
|
||||||
|
imageVs,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class Assets {
|
class Assets {
|
||||||
const Assets._();
|
const Assets._();
|
||||||
|
|
||||||
|
static const $AssetsHtmlGen html = $AssetsHtmlGen();
|
||||||
static const $AssetsImagesGen images = $AssetsImagesGen();
|
static const $AssetsImagesGen images = $AssetsImagesGen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,19 @@ import 'package:webview_flutter_android/webview_flutter_android.dart';
|
|||||||
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
|
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
|
||||||
|
|
||||||
class WebviewPage extends StatefulWidget {
|
class WebviewPage extends StatefulWidget {
|
||||||
final String url;
|
final String? url;
|
||||||
final String? title;
|
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
|
@override
|
||||||
State<WebviewPage> createState() => WebviewPageState();
|
State<WebviewPage> createState() => WebviewPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebviewPageState extends State<WebviewPage> {
|
class WebviewPageState extends State<WebviewPage> {
|
||||||
|
static const String _javaScriptChannelName = 'AppBridge';
|
||||||
|
|
||||||
WebViewController? _controller;
|
WebViewController? _controller;
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
String? _errorMessage;
|
String? _errorMessage;
|
||||||
@@ -26,11 +29,12 @@ class WebviewPageState extends State<WebviewPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initController() async {
|
Future<void> _initController() async {
|
||||||
if (widget.url?.isEmpty ?? true) {
|
if ((widget.url?.isEmpty ?? true) && widget.assetPath == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final params = _createPlatformParams();
|
final params = _createPlatformParams();
|
||||||
final controller = WebViewController.fromPlatformCreationParams(params)
|
late final WebViewController controller;
|
||||||
|
controller = WebViewController.fromPlatformCreationParams(params)
|
||||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||||
..setBackgroundColor(Colors.transparent)
|
..setBackgroundColor(Colors.transparent)
|
||||||
..setNavigationDelegate(
|
..setNavigationDelegate(
|
||||||
@@ -46,8 +50,9 @@ class WebviewPageState extends State<WebviewPage> {
|
|||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onPageFinished: (String url) {
|
onPageFinished: (String url) async {
|
||||||
debugPrint('webview - page finished: $url');
|
debugPrint('webview - page finished: $url');
|
||||||
|
await _injectPostMessageBridge(controller);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _isLoading = false);
|
setState(() => _isLoading = false);
|
||||||
},
|
},
|
||||||
@@ -72,17 +77,28 @@ class WebviewPageState extends State<WebviewPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
controller.addJavaScriptChannel(
|
||||||
|
_javaScriptChannelName,
|
||||||
|
onMessageReceived: (JavaScriptMessage message) {
|
||||||
|
_onMessageReceived(message);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (controller.platform is AndroidWebViewController) {
|
if (controller.platform is AndroidWebViewController) {
|
||||||
AndroidWebViewController.enableDebugging(kDebugMode);
|
AndroidWebViewController.enableDebugging(kDebugMode);
|
||||||
await (controller.platform as AndroidWebViewController)
|
await (controller.platform as AndroidWebViewController)
|
||||||
.setMediaPlaybackRequiresUserGesture(false);
|
.setMediaPlaybackRequiresUserGesture(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
final targetUrl = widget.url ?? '';
|
|
||||||
try {
|
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) {
|
} catch (e) {
|
||||||
debugPrint('webview - loadRequest failed: $e');
|
debugPrint('webview - load failed: $e');
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
@@ -95,6 +111,81 @@ class WebviewPageState extends State<WebviewPage> {
|
|||||||
setState(() => _controller = controller);
|
setState(() => _controller = controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onMessageReceived(JavaScriptMessage message) {
|
||||||
|
debugPrint('收到来自 WebView 的消息: ${message.message}');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 脚本注入传输给h5 数据
|
||||||
|
Future<void> _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<void> _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() {
|
PlatformWebViewControllerCreationParams _createPlatformParams() {
|
||||||
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
|
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
|
||||||
return WebKitWebViewControllerCreationParams(
|
return WebKitWebViewControllerCreationParams(
|
||||||
@@ -110,27 +201,8 @@ class WebviewPageState extends State<WebviewPage> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
extendBodyBehindAppBar: true,
|
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(),
|
body: _buildBody(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ flutter:
|
|||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- assets/images/
|
||||||
|
- assets/html/
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
# assets:
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
|
|||||||
Reference in New Issue
Block a user