QinGang_interested/lib/customWidget/BaiDuMap/map_webview_page.dart

488 lines
15 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// lib/pages/map_webview_page.dart
import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:webview_flutter/webview_flutter.dart';
class MapWebViewPage extends StatefulWidget {
const MapWebViewPage({this.canEdit = true,this.oldLongitude = '',this.oldLatitude = '', Key? key}) : super(key: key);
final bool canEdit;
final String oldLongitude;
final String oldLatitude;
@override
State<MapWebViewPage> createState() => _MapWebViewPageState();
}
class _MapWebViewPageState extends State<MapWebViewPage> {
late final WebViewController _controller;
bool _loading = true;
String _mapUrl = '';
double? _selectedLongitude;
double? _selectedLatitude;
bool _locationError = false;
// 默认坐标(北京)
static const double defaultLongitude = 116.397428;
static const double defaultLatitude = 39.90923;
@override
void initState() {
super.initState();
_initializeWebView();
_initializeMap();
}
void _initializeWebView() {
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('FlutterChannel', onMessageReceived: _onMessageReceived)
..setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) {
debugPrint('页面开始加载: $url');
},
onPageFinished: (url) {
debugPrint('页面加载完成: $url');
setState(() {
_loading = false;
});
_injectFlutterBridge();
},
onWebResourceError: (error) {
debugPrint('Web资源错误: ${error.errorCode} - ${error.description}');
setState(() {
_loading = false;
});
},
onNavigationRequest: (request) {
debugPrint('导航请求: ${request.url}');
return NavigationDecision.navigate;
},
));
}
Future<void> _initializeMap() async {
try {
debugPrint('开始获取位置信息...');
// 先设置默认URL避免长时间等待
final defaultCoord = _gcj02ToBd09(defaultLongitude, defaultLatitude);
_setMapUrl(defaultCoord[0], defaultCoord[1]);
var position ;
if(widget.canEdit){
// 异步获取当前位置
position = await _getCurrentLocationWithTimeout();
}else{
try{
double oldLongitude = double.parse(widget.oldLongitude);
double oldLatitude = double.parse(widget.oldLatitude);
position = Position(longitude: oldLongitude, latitude:oldLatitude ,
timestamp: DateTime.now(), accuracy: 0.0, altitude: 0.0, altitudeAccuracy: 0.0, heading: 0.0,
headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0);
}catch (e) {
// 异步获取当前位置
position = await _getCurrentLocationWithTimeout();
}
}
if (position != null) {
debugPrint('成功获取位置: ${position.longitude}, ${position.latitude}');
// GCJ02 -> BD09 坐标转换
final bd09Coord = _gcj02ToBd09(position.longitude, position.latitude);
_setMapUrl(bd09Coord[0], bd09Coord[1]);
} else {
debugPrint('使用默认位置');
_showToast('使用默认位置,您可以手动选择位置');
}
// 加载地图
await _controller.loadRequest(Uri.parse(_mapUrl));
} catch (e) {
debugPrint('地图初始化失败: $e');
// 即使出错也继续加载地图,使用默认位置
_showToast('位置获取失败,使用默认位置');
await _controller.loadRequest(Uri.parse(_mapUrl));
}
}
Future<Position?> _getCurrentLocationWithTimeout() async {
try {
// 首先检查定位服务是否开启
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
debugPrint('定位服务未开启');
_showToast('定位服务未开启,使用默认位置');
return null;
}
// 检查权限
LocationPermission permission = await Geolocator.checkPermission();
debugPrint('当前定位权限: $permission');
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
debugPrint('请求后定位权限: $permission');
}
if (permission == LocationPermission.denied ||
permission == LocationPermission.deniedForever) {
debugPrint('定位权限被拒绝');
_showToast('定位权限被拒绝,使用默认位置');
return null;
}
// 设置超时
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
).timeout(const Duration(seconds: 10));
return position;
} catch (e) {
debugPrint('获取位置异常: $e');
// 尝试获取最后已知位置
try {
final lastPosition = await Geolocator.getLastKnownPosition();
if (lastPosition != null) {
debugPrint('使用最后已知位置: ${lastPosition.longitude}, ${lastPosition.latitude}');
return lastPosition;
}
} catch (e) {
debugPrint('获取最后已知位置失败: $e');
}
return null;
}
}
void _setMapUrl(double longitude, double latitude) {
final timestamp = DateTime.now().millisecondsSinceEpoch;
setState(() {
_mapUrl = 'https://skqhdg.porthebei.com:9004/map/map.html?'
'longitude=$longitude&'
'latitude=$latitude&'
't=$timestamp';
});
debugPrint('地图URL: $_mapUrl');
}
void _injectFlutterBridge() {
const bridgeScript = '''
// 重写uni.postMessage以发送到Flutter
if (typeof uni !== 'undefined') {
const originalPostMessage = uni.postMessage;
uni.postMessage = function(data) {
console.log('uni.postMessage被调用:', data);
// 发送到Flutter
if (window.FlutterChannel) {
try {
window.FlutterChannel.postMessage(JSON.stringify(data));
} catch(e) {
console.log('发送到Flutter失败:', e);
}
}
// 保持原有逻辑
if (typeof originalPostMessage === 'function') {
originalPostMessage(data);
}
};
// 确保plus环境检测返回true
uni.getEnv = function(callback) {
if (typeof callback === 'function') {
callback({ plus: true });
}
};
}
// 添加Flutter专用的消息发送方法
window.sendToFlutter = function(data) {
console.log('sendToFlutter被调用:', data);
if (window.FlutterChannel) {
try {
window.FlutterChannel.postMessage(JSON.stringify(data));
} catch(e) {
console.log('发送到Flutter失败:', e);
}
}
};
console.log('Flutter bridge注入完成');
''';
_controller.runJavaScript(bridgeScript).catchError((error) {
debugPrint('注入Flutter bridge失败: $error');
});
}
void _onMessageReceived(JavaScriptMessage message) {
try {
debugPrint('收到原始消息: ${message.message}');
final data = jsonDecode(message.message);
debugPrint('解析后的消息: $data');
// 解析坐标数据
if (data != null) {
final coords = data['data'];
setState(() {
_selectedLongitude = coords['longitue'];
_selectedLatitude = coords['latitude'];
});
debugPrint('选中坐标: $_selectedLongitude, $_selectedLatitude');
} else {
debugPrint('无法从消息中提取坐标');
}
} catch (e) {
debugPrint('解析地图消息失败: $e');
debugPrint('原始消息内容: ${message.message}');
}
}
Map<String, double>? _extractCoordinates(dynamic data) {
try {
debugPrint('开始提取坐标,数据类型: ${data.runtimeType}');
if (data is Map) {
// 处理不同的数据结构
dynamic coordsData = data;
// 处理嵌套结构
if (data.containsKey('data') && data['data'] is List && data['data'].isNotEmpty) {
coordsData = data['data'][0];
debugPrint('从data数组中提取坐标数据');
}
if (coordsData is Map) {
debugPrint('坐标数据键: ${coordsData.keys}');
// 处理拼写错误 (longitue -> longitude)
final longitude = _toDouble(coordsData['longitude']) ??
_toDouble(coordsData['longitue']);
final latitude = _toDouble(coordsData['latitude']);
debugPrint('解析结果 - 经度: $longitude, 纬度: $latitude');
if (longitude != null && latitude != null) {
return {
'longitude': longitude,
'latitude': latitude,
};
}
}
} else if (data is String) {
// 尝试从字符串中提取坐标
debugPrint('尝试从字符串中提取坐标');
final coordPattern = RegExp(r'[-+]?\d+\.\d+');
final matches = coordPattern.allMatches(data).toList();
if (matches.length >= 2) {
final longitude = double.tryParse(matches[0].group(0)!);
final latitude = double.tryParse(matches[1].group(0)!);
if (longitude != null && latitude != null) {
return {
'longitude': longitude,
'latitude': latitude,
};
}
}
}
} catch (e) {
debugPrint('提取坐标失败: $e');
}
return null;
}
double? _toDouble(dynamic value) {
if (value == null) return null;
if (value is double) return value;
if (value is int) return value.toDouble();
if (value is String) {
// 处理可能的字符串格式
final cleaned = value.replaceAll(RegExp(r'[^\d.-]'), '');
return double.tryParse(cleaned);
}
return null;
}
void _showToast(String message) {
if (!mounted) return;
ToastUtil.showNormal(context, message);
}
Future<void> _confirmSelection() async {
if (_selectedLongitude == null || _selectedLatitude == null) {
// 如果没有选中位置,尝试从页面获取当前位置
await _getCurrentLocationFromPage();
}
if (_selectedLongitude != null && _selectedLatitude != null) {
final result = {
'longitude': _selectedLongitude!,
'latitude': _selectedLatitude!,
};
debugPrint('返回坐标结果: $result');
Navigator.of(context).pop(result);
} else {
_showToast('请先在地图上选择位置');
}
}
Future<void> _getCurrentLocationFromPage() async {
try {
debugPrint('尝试从页面获取选中位置');
const getterScript = '''
(function(){
try {
// 尝试多种方式获取选中位置
if (typeof getSelectedLocation === 'function') {
var result = getSelectedLocation();
if (result) return JSON.stringify(result);
}
if (window.selectedLocation) {
return JSON.stringify(window.selectedLocation);
}
// 如果没有选中位置,返回地图中心
if (map && typeof map.getCenter === 'function') {
var center = map.getCenter();
return JSON.stringify({
longitude: center.getLng(),
latitude: center.getLat()
});
}
return null;
} catch(e) {
console.log('获取位置错误:', e);
return null;
}
})();
''';
final result = await _controller.runJavaScriptReturningResult(getterScript);
debugPrint('页面返回的位置结果: $result');
if (result != null) {
String resultString = result.toString();
// 处理可能的双重编码
if (resultString.startsWith('"') && resultString.endsWith('"')) {
resultString = resultString.substring(1, resultString.length - 1);
}
final coords = _extractCoordinates(jsonDecode(resultString));
if (coords != null) {
setState(() {
_selectedLongitude = coords['longitude'];
_selectedLatitude = coords['latitude'];
});
debugPrint('从页面获取到坐标: $_selectedLongitude, $_selectedLatitude');
}
}
} catch (e) {
debugPrint('从页面获取位置失败: $e');
}
}
void _retryLocation() async {
setState(() {
_loading = true;
_locationError = false;
});
await _initializeMap();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(
title: '地图选点',
actions: [
if (_selectedLongitude != null&&widget.canEdit)
TextButton(
onPressed: _confirmSelection,
child: const Text(
'确定',
style: TextStyle(color: Colors.white, fontSize: 17),
),
),
],
),
body: Column(
children: [
// 状态提示栏
if (_locationError)
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
color: Colors.orange[100],
child: Row(
children: [
Icon(Icons.warning_amber, color: Colors.orange[800], size: 16),
const SizedBox(width: 8),
Expanded(
child: Text(
'定位失败,使用默认位置',
style: TextStyle(color: Colors.orange[800], fontSize: 12),
),
),
TextButton(
onPressed: _retryLocation,
child: Text(
'重试',
style: TextStyle(color: Colors.orange[800], fontSize: 12),
),
),
],
),
),
// 地图区域
Expanded(
child: Stack(
children: [
if (_mapUrl.isNotEmpty)
WebViewWidget(controller: _controller),
if (_loading)
const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('地图加载中...'),
],
),
),
],
),
),
],
),
);
}
// GCJ02 -> BD09 坐标转换
List<double> _gcj02ToBd09(double lng, double lat) {
const double xPi = math.pi * 3000.0 / 180.0;
final double z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * xPi);
final double theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * xPi);
final double bdLng = z * math.cos(theta) + 0.0065;
final double bdLat = z * math.sin(theta) + 0.006;
return [bdLng, bdLat];
}
@override
void dispose() {
super.dispose();
debugPrint('地图页面销毁');
}
}