|
|
|
@ -827,7 +827,7 @@ class AgentController extends GetxController with WidgetsBindingObserver { |
|
|
|
// Logger.i(TAG, 'liwei-------- 打开导航页面: $start $end '); |
|
|
|
// 2秒后执行的代码 |
|
|
|
|
|
|
|
openNavigation(start, destination, end_latitude, |
|
|
|
openNavigation(false, start, destination, end_latitude, |
|
|
|
end_longitude, ""); |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -1865,18 +1865,234 @@ class AgentController extends GetxController with WidgetsBindingObserver { |
|
|
|
} |
|
|
|
|
|
|
|
//去导航 |
|
|
|
void openNavigation(String start, String destination, String endlatitude, |
|
|
|
String endlongitude, String mode) { |
|
|
|
void openNavigation(bool isshow, String start, String destination, |
|
|
|
String endlatitude, String endlongitude, String mode) { |
|
|
|
print('liwei 导航:$destination $endlatitude $endlongitude $mode'); |
|
|
|
if (isshow) { |
|
|
|
// 弹出导航选择面板 |
|
|
|
_showNavigationSelectionDialog( |
|
|
|
start, destination, endlatitude, endlongitude, mode); |
|
|
|
} else { |
|
|
|
// 使用默认配置直接导航 |
|
|
|
_navigateWithDefaultMode( |
|
|
|
start, destination, endlatitude, endlongitude, mode); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 显示导航选择底部面板 |
|
|
|
void _showNavigationSelectionDialog(String start, String destination, |
|
|
|
String endlatitude, String endlongitude, String mode) { |
|
|
|
Get.bottomSheet( |
|
|
|
Container( |
|
|
|
decoration: const BoxDecoration( |
|
|
|
color: Colors.white, |
|
|
|
borderRadius: BorderRadius.only( |
|
|
|
topLeft: Radius.circular(20), |
|
|
|
topRight: Radius.circular(20), |
|
|
|
), |
|
|
|
), |
|
|
|
child: Column( |
|
|
|
mainAxisSize: MainAxisSize.min, |
|
|
|
children: [ |
|
|
|
// 顶部指示条 |
|
|
|
Container( |
|
|
|
margin: const EdgeInsets.only(top: 12), |
|
|
|
width: 40, |
|
|
|
height: 4, |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.grey[300], |
|
|
|
borderRadius: BorderRadius.circular(2), |
|
|
|
), |
|
|
|
), |
|
|
|
// 标题 |
|
|
|
const Padding( |
|
|
|
padding: EdgeInsets.all(20), |
|
|
|
child: Text( |
|
|
|
'选择导航软件', |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 18, |
|
|
|
fontWeight: FontWeight.bold, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
// 导航选项列表 |
|
|
|
ListTile( |
|
|
|
leading: Container( |
|
|
|
padding: const EdgeInsets.all(8), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.blue.withOpacity(0.1), |
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
), |
|
|
|
child: const Icon(Icons.map, color: Colors.blue), |
|
|
|
), |
|
|
|
title: const Text('高德地图'), |
|
|
|
subtitle: const Text('使用高德地图导航'), |
|
|
|
onTap: () { |
|
|
|
Get.back(); |
|
|
|
openGaodeMap(destination, endlatitude, endlongitude, mode); |
|
|
|
}, |
|
|
|
), |
|
|
|
ListTile( |
|
|
|
leading: Container( |
|
|
|
padding: const EdgeInsets.all(8), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.green.withOpacity(0.1), |
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
), |
|
|
|
child: const Icon(Icons.map, color: Colors.green), |
|
|
|
), |
|
|
|
title: const Text('百度地图'), |
|
|
|
subtitle: const Text('使用百度地图导航'), |
|
|
|
onTap: () { |
|
|
|
Get.back(); |
|
|
|
openBaiduMap(destination, endlatitude, endlongitude, mode); |
|
|
|
}, |
|
|
|
), |
|
|
|
ListTile( |
|
|
|
leading: Container( |
|
|
|
padding: const EdgeInsets.all(8), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.red.withOpacity(0.1), |
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
), |
|
|
|
child: const Icon(Icons.map, color: Colors.red), |
|
|
|
), |
|
|
|
title: const Text('谷歌地图'), |
|
|
|
subtitle: const Text('使用谷歌地图导航'), |
|
|
|
onTap: () { |
|
|
|
Get.back(); |
|
|
|
openGoogleMap(destination, mode); |
|
|
|
}, |
|
|
|
), |
|
|
|
// 苹果导航 - 仅在 iOS 平台显示 |
|
|
|
if (Platform.isIOS) |
|
|
|
ListTile( |
|
|
|
leading: Container( |
|
|
|
padding: const EdgeInsets.all(8), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.grey.withOpacity(0.1), |
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
), |
|
|
|
child: const Icon(Icons.navigation, color: Colors.grey), |
|
|
|
), |
|
|
|
title: const Text('苹果地图'), |
|
|
|
subtitle: const Text('使用苹果地图导航'), |
|
|
|
onTap: () { |
|
|
|
Get.back(); |
|
|
|
openAppleMap(destination, mode); |
|
|
|
}, |
|
|
|
), |
|
|
|
// 底部安全区域 |
|
|
|
SizedBox(height: MediaQuery.of(Get.context!).padding.bottom + 20), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
isScrollControlled: true, |
|
|
|
isDismissible: true, // 点击外部区域可关闭 |
|
|
|
enableDrag: true, // 支持拖拽关闭 |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// 使用默认配置导航 |
|
|
|
void _navigateWithDefaultMode(String start, String destination, |
|
|
|
String endlatitude, String endlongitude, String mode) { |
|
|
|
final navigationMode = |
|
|
|
AppConfig.env('APP_NAVIGATION_MODE') ?? 'external_auto'; |
|
|
|
if (navigationMode == 'internal_gaode') { |
|
|
|
_navigationManager.open(start, "$endlongitude,$endlatitude", mode); |
|
|
|
} else if (navigationMode == 'external_baidu') { |
|
|
|
openBaiduMap(destination, mode); |
|
|
|
openBaiduMap(destination, endlatitude, endlongitude, mode); |
|
|
|
} else if (navigationMode == 'external_gaode') { |
|
|
|
openGaodeMap(destination, endlatitude, destination, mode); |
|
|
|
openGaodeMap(destination, endlatitude, endlongitude, mode); |
|
|
|
} else if (navigationMode == 'external_google') { |
|
|
|
openGoogleMap(destination, mode); |
|
|
|
} else { |
|
|
|
// 自动选择导航应用,优先级:百度 > 高德 > 谷歌 |
|
|
|
_autoSelectNavigation( |
|
|
|
start, destination, endlatitude, endlongitude, mode); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 自动选择导航应用 |
|
|
|
Future<void> _autoSelectNavigation(String start, String destination, |
|
|
|
String endlatitude, String endlongitude, String mode) async { |
|
|
|
try { |
|
|
|
// 1. 优先尝试百度地图 |
|
|
|
final baiduUri = Uri( |
|
|
|
scheme: 'baidumap', |
|
|
|
host: 'map', |
|
|
|
path: 'direction', |
|
|
|
queryParameters: { |
|
|
|
'destination': destination, |
|
|
|
'coord_type': 'gcj02', |
|
|
|
'mode': mode == 'driving' ? 'driving' : 'transit', |
|
|
|
'src': 'deepvoice', |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
if (await canLaunchUrl(baiduUri)) { |
|
|
|
print('自动选择:使用百度地图'); |
|
|
|
openBaiduMap(destination, endlatitude, endlongitude, mode); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 2. 其次尝试高德地图 |
|
|
|
final gaodeUri = Uri( |
|
|
|
scheme: 'amapuri', |
|
|
|
host: 'navi', |
|
|
|
queryParameters: { |
|
|
|
'to': destination, |
|
|
|
'mode': mode.isNotEmpty ? mode : 'driving', |
|
|
|
'callnative': '1', |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
if (await canLaunchUrl(gaodeUri)) { |
|
|
|
print('自动选择:使用高德地图'); |
|
|
|
openGaodeMap(destination, endlatitude, endlongitude, mode); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 3. 然后尝试谷歌地图 |
|
|
|
final googleUri = Uri( |
|
|
|
scheme: 'comgooglemaps', |
|
|
|
queryParameters: { |
|
|
|
'daddr': destination, |
|
|
|
'directionsmode': mode == 'driving' ? 'driving' : 'transit', |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
if (await canLaunchUrl(googleUri)) { |
|
|
|
print('自动选择:使用谷歌地图'); |
|
|
|
openGoogleMap(destination, mode); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 4. 在 iOS 平台尝试苹果地图 |
|
|
|
if (Platform.isIOS) { |
|
|
|
final appleUri = Uri( |
|
|
|
scheme: 'maps', |
|
|
|
queryParameters: { |
|
|
|
'daddr': destination, |
|
|
|
'dirflg': mode == 'driving' ? 'd' : 'r', |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
if (await canLaunchUrl(appleUri)) { |
|
|
|
print('自动选择:使用苹果地图'); |
|
|
|
openAppleMap(destination, mode); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 5. 如果都没有安装,提示用户 |
|
|
|
print('未找到可用的导航应用'); |
|
|
|
final availableApps = |
|
|
|
Platform.isIOS ? '百度地图、高德地图、谷歌地图或苹果地图' : '百度地图、高德地图或谷歌地图'; |
|
|
|
Get.snackbar('提示', '未找到可用的导航应用,请安装$availableApps'); |
|
|
|
} catch (e) { |
|
|
|
print('自动选择导航失败: $e'); |
|
|
|
Get.snackbar('错误', '启动导航失败'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -2187,7 +2403,7 @@ class AgentController extends GetxController with WidgetsBindingObserver { |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开Google地图进行导航 |
|
|
|
Future<void> openGoogleMap(String daddr, String mode) async { |
|
|
|
Future<bool> openGoogleMap(String daddr, String mode) async { |
|
|
|
try { |
|
|
|
// 方案1: 尝试使用Google Maps应用的URL scheme |
|
|
|
// final Uri googleMapsUri = Uri.parse(url); |
|
|
|
@ -2197,26 +2413,28 @@ class AgentController extends GetxController with WidgetsBindingObserver { |
|
|
|
'comgooglemaps://?saddr=CurrentLocation&daddr=$daddr&directionsmode=$mode'); |
|
|
|
if (await canLaunchUrl(appUri)) { |
|
|
|
await launchUrl(appUri, mode: LaunchMode.externalApplication); |
|
|
|
return; |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
final Uri webUrl = Uri.parse( |
|
|
|
"https://www.google.com/maps/dir/?api=1&origin=Current+Location&destination=$daddr&travelmode=$mode"); |
|
|
|
if (await canLaunchUrl(webUrl)) { |
|
|
|
await launchUrl(webUrl); |
|
|
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
print('打开地图失败: $e'); |
|
|
|
Get.snackbar('错误', '打开地图时发生错误'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开高德地图进行导航 |
|
|
|
Future<void> openGaodeMap( |
|
|
|
Future<bool> openGaodeMap( |
|
|
|
String destination, |
|
|
|
String lat, |
|
|
|
String lon, |
|
|
|
String mode, |
|
|
|
String mode, // 'driving', 'transit', 'walking', 'cycling' |
|
|
|
) async { |
|
|
|
try { |
|
|
|
// 获取应用包名 |
|
|
|
@ -2224,92 +2442,174 @@ class AgentController extends GetxController with WidgetsBindingObserver { |
|
|
|
|
|
|
|
// 构建src参数(带平台前缀) |
|
|
|
final String src = Platform.isAndroid |
|
|
|
? "android.${packageInfo.packageName}" |
|
|
|
? packageInfo.packageName |
|
|
|
: "ios.${packageInfo.packageName}"; |
|
|
|
|
|
|
|
// 构建高德地图导航链接 |
|
|
|
final Uri uri = Uri( |
|
|
|
scheme: 'androidamap', |
|
|
|
host: 'navi', |
|
|
|
queryParameters: { |
|
|
|
'poiname': destination, // 目的地地址 |
|
|
|
'lat': lat, |
|
|
|
'lon': lon, |
|
|
|
'mode': mode.isNotEmpty ? mode : 'driving', // 导航模式,默认驾车 |
|
|
|
'sourceApplication': src, // 来源标识 |
|
|
|
'callnative': '1', // 优先调用原生应用 |
|
|
|
}, |
|
|
|
); |
|
|
|
// 导航模式映射 |
|
|
|
String gaodeMode; |
|
|
|
switch (mode) { |
|
|
|
case 'transit': |
|
|
|
gaodeMode = '1'; // 公交 |
|
|
|
break; |
|
|
|
case 'walking': |
|
|
|
gaodeMode = '2'; // 步行 |
|
|
|
break; |
|
|
|
case 'cycling': |
|
|
|
gaodeMode = '3'; // 骑行 |
|
|
|
break; |
|
|
|
case 'driving': |
|
|
|
default: |
|
|
|
gaodeMode = '0'; // 驾车 |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// 根据平台选择不同的 scheme 和参数 |
|
|
|
final Uri uri; |
|
|
|
if (Platform.isAndroid) { |
|
|
|
uri = Uri( |
|
|
|
scheme: 'androidamap', |
|
|
|
host: 'route', |
|
|
|
path: 'plan', |
|
|
|
queryParameters: { |
|
|
|
'dlat': lat, |
|
|
|
'dlon': lon, |
|
|
|
'dname': destination, |
|
|
|
'dev': '0', // 0: gcj02 |
|
|
|
't': gaodeMode, |
|
|
|
'sourceApplication': src, |
|
|
|
}, |
|
|
|
); |
|
|
|
} else { |
|
|
|
// iOS |
|
|
|
uri = Uri( |
|
|
|
scheme: 'amapuri', |
|
|
|
host: 'route', |
|
|
|
path: 'plan', |
|
|
|
queryParameters: { |
|
|
|
'dlat': lat, |
|
|
|
'dlon': lon, |
|
|
|
'dname': destination, |
|
|
|
'dev': '0', // 0: gcj02 |
|
|
|
't': gaodeMode, |
|
|
|
'sourceApplication': src, |
|
|
|
}, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
print('高德导航链接: ${uri.toString()}'); |
|
|
|
// final Uri testMapsUri = Uri.parse( |
|
|
|
// 'androidamap://navi?sourceApplication=android.com.saitong.voitrans&lat=22.615274&lon=114.035576&poiname=深圳北站&dev=0&mode=driving'); |
|
|
|
// // 尝试打开高德地图应用 |
|
|
|
|
|
|
|
if (await canLaunchUrl(uri)) { |
|
|
|
final bool launched = await launchUrl( |
|
|
|
uri, |
|
|
|
mode: LaunchMode.externalApplication, |
|
|
|
); |
|
|
|
if (!launched) { |
|
|
|
print('高德地图已安装,但启动失败'); |
|
|
|
Get.snackbar('提示', '高德地图启动失败'); |
|
|
|
} |
|
|
|
return launched; |
|
|
|
} else { |
|
|
|
print('高德地图未安装'); |
|
|
|
Get.snackbar('提示', '请先安装高德地图应用'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
print('打开地图失败: $e'); |
|
|
|
print('打开高德地图失败: $e'); |
|
|
|
Get.snackbar('错误', '打开地图时发生错误'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开Baidu地图进行导航 |
|
|
|
Future<void> openBaiduMap( |
|
|
|
Future<bool> openBaiduMap( |
|
|
|
String destination, |
|
|
|
String mode, |
|
|
|
String lat, |
|
|
|
String lon, |
|
|
|
String mode, // 'driving', 'transit', 'walking', 'riding' |
|
|
|
) async { |
|
|
|
try { |
|
|
|
// 地址和城市(已编码的字符串也可以直接使用) |
|
|
|
// String destination = "深圳北站"; |
|
|
|
// String city = "深圳"; |
|
|
|
// 获取应用包名 |
|
|
|
final packageInfo = await PackageInfo.fromPlatform(); |
|
|
|
final String src = |
|
|
|
'${Platform.isAndroid ? '' : 'ios.'}${packageInfo.packageName}'; |
|
|
|
|
|
|
|
// 百度地图导航模式映射 |
|
|
|
String baiduMode; |
|
|
|
switch (mode) { |
|
|
|
case 'transit': |
|
|
|
baiduMode = 'transit'; // 公交 |
|
|
|
break; |
|
|
|
case 'walking': |
|
|
|
baiduMode = 'walking'; // 步行 |
|
|
|
break; |
|
|
|
case 'cycling': |
|
|
|
baiduMode = 'riding'; // 骑行 |
|
|
|
break; |
|
|
|
case 'driving': |
|
|
|
default: |
|
|
|
baiduMode = 'driving'; // 驾车 |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// 构建正确的导航链接 |
|
|
|
final Uri appUri = Uri( |
|
|
|
final Uri uri = Uri( |
|
|
|
scheme: 'baidumap', |
|
|
|
host: 'map', |
|
|
|
path: 'direction', // 使用direction端点而非navi |
|
|
|
path: 'direction', |
|
|
|
queryParameters: { |
|
|
|
'destination': destination, |
|
|
|
// 'city': '深圳', |
|
|
|
'mode': mode, // 明确导航模式 |
|
|
|
'src': 'com.saitong.voitrans', // 带平台前缀的src参数 |
|
|
|
'destination': 'name:$destination|latlng:$lat,$lon', |
|
|
|
'coord_type': 'gcj02', |
|
|
|
'mode': baiduMode, |
|
|
|
'src': src, |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
print('生成的链接: ${appUri.toString()}'); |
|
|
|
print('百度导航链接: ${uri.toString()}'); |
|
|
|
|
|
|
|
if (await canLaunchUrl(appUri)) { |
|
|
|
await launchUrl(appUri, mode: LaunchMode.externalApplication); |
|
|
|
if (await canLaunchUrl(uri)) { |
|
|
|
final bool launched = await launchUrl( |
|
|
|
uri, |
|
|
|
mode: LaunchMode.externalApplication, |
|
|
|
); |
|
|
|
return launched; |
|
|
|
} else { |
|
|
|
print('无法打开百度地图,请检查是否已安装'); |
|
|
|
print('百度地图未安装'); |
|
|
|
Get.snackbar('提示', '请先安装百度地图应用'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// final packageInfo = await PackageInfo.fromPlatform(); |
|
|
|
// String packageName = packageInfo.packageName; |
|
|
|
// // 方案1: 尝试使用Google Maps应用的URL scheme |
|
|
|
// // final Uri googleMapsUri = Uri.parse(url); |
|
|
|
// // 简化版链接(仅包含必要参数) |
|
|
|
// final Uri testUri = Uri.parse( |
|
|
|
// 'baidumap://map/navi?location=$end_latitude,$end_longitude&coord_type=bd09ll&src$packageName'); |
|
|
|
// if (await canLaunchUrl(testUri)) { |
|
|
|
// await launchUrl(testUri, mode: LaunchMode.externalApplication); |
|
|
|
// } else { |
|
|
|
// print('打开地图失败'); |
|
|
|
// } |
|
|
|
} catch (e) { |
|
|
|
print('打开地图失败: $e'); |
|
|
|
print('打开百度地图失败: $e'); |
|
|
|
Get.snackbar('错误', '打开地图时发生错误'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开苹果地图进行导航 |
|
|
|
Future<void> openAppleMap(String destination, String mode) async { |
|
|
|
try { |
|
|
|
// 构建苹果地图导航链接 |
|
|
|
final Uri uri = Uri( |
|
|
|
scheme: 'maps', |
|
|
|
queryParameters: { |
|
|
|
'daddr': destination, // 目的地地址 |
|
|
|
'dirflg': mode == 'driving' ? 'd' : 'r', // d=驾车, r=公交 |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
print('苹果地图导航链接: ${uri.toString()}'); |
|
|
|
|
|
|
|
// 尝试打开苹果地图应用 |
|
|
|
if (await canLaunchUrl(uri)) { |
|
|
|
final bool launched = await launchUrl( |
|
|
|
uri, |
|
|
|
mode: LaunchMode.externalApplication, |
|
|
|
); |
|
|
|
if (!launched) { |
|
|
|
print('苹果地图启动失败'); |
|
|
|
Get.snackbar('提示', '苹果地图启动失败'); |
|
|
|
} |
|
|
|
} else { |
|
|
|
print('苹果地图不可用'); |
|
|
|
Get.snackbar('提示', '苹果地图不可用'); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
print('打开苹果地图失败: $e'); |
|
|
|
Get.snackbar('错误', '打开苹果地图时发生错误'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|