更新 AndroidManifest.xml 以启用明文流量;在 index.html 中替换 token 值
增强 WebviewPage 的清理和导航功能。
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:recording_tool/app/router/app_navigator.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';
|
||||
@@ -8,8 +12,15 @@ class WebviewPage extends StatefulWidget {
|
||||
final String? url;
|
||||
final String? title;
|
||||
final String? assetPath;
|
||||
final bool? canPop;
|
||||
|
||||
const WebviewPage({super.key, this.url, this.title, this.assetPath});
|
||||
const WebviewPage({
|
||||
super.key,
|
||||
this.url,
|
||||
this.title,
|
||||
this.assetPath,
|
||||
this.canPop,
|
||||
});
|
||||
|
||||
@override
|
||||
State<WebviewPage> createState() => WebviewPageState();
|
||||
@@ -28,6 +39,16 @@ class WebviewPageState extends State<WebviewPage> {
|
||||
_initController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
final controller = _controller;
|
||||
_controller = null;
|
||||
if (controller != null) {
|
||||
unawaited(_disposeWebViewController(controller));
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _initController() async {
|
||||
if ((widget.url?.isEmpty ?? true) && widget.assetPath == null) {
|
||||
return;
|
||||
@@ -52,7 +73,8 @@ class WebviewPageState extends State<WebviewPage> {
|
||||
},
|
||||
onPageFinished: (String url) async {
|
||||
debugPrint('webview - page finished: $url');
|
||||
await _injectPostMessageBridge(controller);
|
||||
// await _injectPostMessageBridge(controller);
|
||||
await _injectH5NeedData(controller);
|
||||
if (!mounted) return;
|
||||
setState(() => _isLoading = false);
|
||||
},
|
||||
@@ -107,43 +129,72 @@ class WebviewPageState extends State<WebviewPage> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
if (!mounted) {
|
||||
unawaited(_disposeWebViewController(controller));
|
||||
return;
|
||||
}
|
||||
setState(() => _controller = controller);
|
||||
}
|
||||
|
||||
Future<void> _disposeWebViewController(WebViewController controller) async {
|
||||
await _runWebViewCleanupStep(
|
||||
'reset navigation delegate',
|
||||
() => controller.setNavigationDelegate(NavigationDelegate()),
|
||||
);
|
||||
await _runWebViewCleanupStep(
|
||||
'remove javascript channel',
|
||||
() => controller.removeJavaScriptChannel(_javaScriptChannelName),
|
||||
);
|
||||
await _runWebViewCleanupStep(
|
||||
'load blank page',
|
||||
() => controller.loadRequest(Uri.parse('about:blank')),
|
||||
);
|
||||
await _runWebViewCleanupStep('clear cache', controller.clearCache);
|
||||
await _runWebViewCleanupStep(
|
||||
'clear local storage',
|
||||
controller.clearLocalStorage,
|
||||
);
|
||||
await _runWebViewCleanupStep(
|
||||
'clear cookies',
|
||||
() => WebViewCookieManager().clearCookies(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _runWebViewCleanupStep(
|
||||
String step,
|
||||
Future<void> Function() cleanup,
|
||||
) async {
|
||||
try {
|
||||
debugPrint('webview - dispose cleanup at $step ');
|
||||
|
||||
await cleanup();
|
||||
} catch (e) {
|
||||
debugPrint('webview - dispose cleanup failed at $step: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void _onMessageReceived(JavaScriptMessage message) {
|
||||
debugPrint('收到来自 WebView 的消息: ${message.message}');
|
||||
final jsonMap = json.decode(message.message);
|
||||
if (jsonMap['type'] != null && jsonMap['type'] == 'navigator_pop') {
|
||||
Navigator.of(context).maybePop();
|
||||
}
|
||||
}
|
||||
|
||||
/// 脚本注入传输给h5 数据
|
||||
Future<void> _injectH5NeedData(WebViewController controller) async {
|
||||
final token =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjgxNDI4NTczNTY2NjY4ODAwLCJkYXRhIjp7fSwic3ViIjoiODE0Mjg1NzM1NjY2Njg4MDAiLCJleHAiOjE3ODM5MzM1ODQsIm5iZiI6MTc4MzMyODc4NCwiaWF0IjoxNzgzMzI4Nzg0fQ.r1wYfvpV-5HIgwUuvq1Or3jPgjc3AhfJmoV1PNP23-Y';
|
||||
try {
|
||||
await controller.runJavaScript('''
|
||||
(function () {
|
||||
if (window.__appBridgePostMessageBridgeInstalled) {
|
||||
(function () {
|
||||
if (window.__appInstallData) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.__appInstallData = ${true};
|
||||
|
||||
window.__appBridgePostMessageBridgeInstalled = true;
|
||||
window.addEventListener('message', function (event) {
|
||||
if (!window.AppBridge || !window.AppBridge.postMessage) {
|
||||
return;
|
||||
}
|
||||
window.AppBridge.token = '$token';
|
||||
|
||||
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) {
|
||||
@@ -151,41 +202,6 @@ class WebviewPageState extends State<WebviewPage> {
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
|
||||
return WebKitWebViewControllerCreationParams(
|
||||
@@ -226,11 +242,48 @@ class WebviewPageState extends State<WebviewPage> {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(child: WebViewWidget(controller: controller)),
|
||||
if (_isLoading) const Center(child: CircularProgressIndicator()),
|
||||
],
|
||||
return PopScope(
|
||||
canPop: widget.canPop ?? true,
|
||||
onPopInvokedWithResult: (didPop, result) async {
|
||||
if (didPop) return;
|
||||
|
||||
final ok = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text("提示"),
|
||||
content: const Text("是否返回上一页?"),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: const Text("取消"),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text("确定"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (ok == true) {
|
||||
AppNavigator.pop();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
SizedBox(height: 48),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(child: WebViewWidget(controller: controller)),
|
||||
if (_isLoading)
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user