Flutter - APP跳转高德、百度、腾讯、谷歌地图

demo 地址: https://github.com/iotjin/jh_flutter_demo
代码不定时更新,请前往github查看最新代码
这里介绍的是不需要自己开发地图,直接通过给定的经纬度,跳转到三方地图APP调用导航的方式

一种是写的工具类,一种是通过调用三方库map_launcher实现的

官方文档:

参考文章:

Flutter 跳转地图软件调起导航:百度、高德、腾讯、苹果
Flutter 实战调起三方地图导航(高德、百度、腾讯、苹果)

插件:
map_launcher
flutter_map
maps_launcher

实现

在 pubspec.yaml 文件中添加依赖插件:

c 复制代码
  # url打开工具 https://pub.flutter-io.cn/packages/url_launcher
  url_launcher: ^6.1.14
  # 打开地图工具 https://pub.flutter-io.cn/packages/map_launcher
  map_launcher: ^2.5.0+1

示例demo

dart 复制代码
///  map_jump_test_page.dart
///
///  Created by iotjin on 2023/10/16.
///  description: 跳转三方地图APP

import 'package:flutter/material.dart';
import 'package:map_launcher/map_launcher.dart';
import '/jh_common/utils/jh_map_utils.dart';
import '/jh_common/widgets/jh_text_list.dart';

// ignore_for_file: avoid_print

final List titleData = [
  '高德(JhMapUtils)',
  '高德2(JhMapUtils)',
  '百度(JhMapUtils)',
  '腾讯(JhMapUtils)',
  '三方库跳转高德(map_launcher)',
  '三方库弹出地图列表(map_launcher)',
];

class MapJumpTestPage extends StatefulWidget {
  const MapJumpTestPage({Key? key}) : super(key: key);

  @override
  State<MapJumpTestPage> createState() => _MapJumpTestPageState();
}

class _MapJumpTestPageState extends State<MapJumpTestPage> {
  var latitude = 39.922869448132474;
  var longitude = 116.40748500823975;

  @override
  Widget build(BuildContext context) {
    return JhTextList(
      title: '跳转三方地图导航',
      dataArr: titleData,
      callBack: (index, str) {
        if (str == '高德(JhMapUtils)') {
          JhMapUtils.openAMapNavi(dLatitude: latitude, dLongitude: longitude);
        }
        if (str == '高德2(JhMapUtils)') {
          JhMapUtils.openAMapNavi2(latitude: latitude, longitude: longitude);
        }
        if (str == '百度(JhMapUtils)') {
          JhMapUtils.openBaiduMapNavi(dLatitude: latitude, dLongitude: longitude);
        }
        if (str == '腾讯(JhMapUtils)') {
          JhMapUtils.openTencentMapNavi(dLatitude: latitude, dLongitude: longitude);
        }
        if (str == '三方库跳转高德(map_launcher)') {
          _gotoMap();
        }
        if (str == '三方库弹出地图列表(map_launcher)') {
          _openMapsSheet(context);
        }
      },
    );
  }

  _gotoMap() async {
    // Get list of installed maps and launch first
    final availableMaps = await MapLauncher.installedMaps;
    print(availableMaps); // [AvailableMap { mapName: Google Maps, mapType: google }, ...]
    // [
    //   AvailableMap{
    //   mapName: GoogleMaps,
    //   mapType: google
    // },
    //   AvailableMap{
    //   mapName: Amap,
    //   mapType: amap
    // },
    //   AvailableMap{
    //   mapName: BaiduMaps,
    //   mapType: baidu
    // },
    //   AvailableMap{
    //   mapName: Tencent(QQMaps),
    //   mapType: tencent
    // }
    // ]

    // await availableMaps.first.showMarker(
    //   coords: Coords(latitude, longitude),
    //   title: "Ocean Beach",
    // );
    // await availableMaps[1].showMarker(
    //   coords: Coords(latitude, longitude),
    //   title: "Ocean Beach",
    // );

    // Check if map is installed and launch it #
    var canIn = await MapLauncher.isMapAvailable(MapType.amap);
    print('canIn: $canIn');
    if (await MapLauncher.isMapAvailable(MapType.amap) == true) {
      await MapLauncher.showMarker(
        mapType: MapType.amap,
        coords: Coords(latitude, longitude),
        title: 'title',
        description: 'description',
      );
    }
  }

  _openMapsSheet(context) async {
    try {
      const title = "Ocean Beach";
      final availableMaps = await MapLauncher.installedMaps;

      showModalBottomSheet(
        context: context,
        builder: (BuildContext context) {
          return SafeArea(
            child: SingleChildScrollView(
              child: Wrap(
                children: <Widget>[
                  for (var map in availableMaps)
                    ListTile(
                      onTap: () => map.showMarker(coords: Coords(latitude, longitude), title: title),
                      title: Text(map.mapName),
                      leading: const Icon(Icons.map, size: 30),
                    ),
                ],
              ),
            ),
          );
        },
      );
    } catch (e) {
      print(e);
    }
  }
}

jh_map_utils实现代码

dart 复制代码
///  jh_map_utils.dart
///
///  Created by iotjin on 2023/05/06.
///  description:

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'jh_device_utils.dart';

class JhMapUtils {
  /// 跳转其他App
  static Future<void> jumpApp({String? url, String message = '跳转失败!'}) async {
    final Uri uri = Uri.parse(url ?? '');
    if (await canLaunchUrl(uri)) {
      await launchUrl(uri);
    } else {
      debugPrint(message);
      // JhProgressHUD.showText(message);
    }
  }

  /// 判断地图是否有安装
  static Future<bool> isInstallMap(String url) async {
    // var url = Uri.parse(Uri.encodeFull(url));
    final Uri uri = Uri.parse(url);
    bool canLaunch = await canLaunchUrl(uri);
    debugPrint('canLaunch: $canLaunch');
    return canLaunchUrl(uri);
  }

  /// 跳转高德导航 - 路径规划
  /// 高德地图官方文档 - Android: https://lbs.amap.com/api/amap-mobile/guide/android/route
  /// 高德地图官方文档 - iOS: https://lbs.amap.com/api/amap-mobile/guide/ios/route
  static void openAMapNavi({
    double? sLatitude, // 起点纬度
    double? sLongitude, // 起点经度
    String sName = '', // 起点名称
    required double dLatitude, // 终点纬度
    required double dLongitude, // 终点经度
    String dName = '', // 终点名称
    String dev = '0', // 起终点是否偏移。0:lat和lon是已经加密后的,不需要国测加密;1:需要国测加密,可为空,但起点或终点不为空时,不能为空
    String t = '0', // t = 0 驾车;    t = 1 公交;    t = 2 步行;    t = 3 骑行(骑行仅在V788以上版本支持)
    String message = '您没有安装高德地图,请先安装高德地图!',
  }) async {
    if (!JhDeviceUtils.isMobile) {
      return;
    }
    var type = JhDeviceUtils.isIOS ? 'iosamap://path?sourceApplication=applicationName&' : 'amapuri://route/plan/?';
    var url =
        '${type}sid=&slat=${sLatitude ?? ''}&slon=${sLongitude ?? ''}&sname=$sName&dlat=$dLatitude&dlon=$dLongitude&dname=$dName&dev=$dev&t=$t';
    // if (!(await canLaunchUrl(Uri.parse(url)))) {
    //   debugPrint(message);
    //   // JhProgressHUD.showText(message);
    //   return;
    // }
    await launchUrl(Uri.parse(url));
  }

  /// 跳转高德导航
  /// 高德地图官方文档: https://lbs.amap.com/api/amap-mobile/guide/android/navigation
  static void openAMapNavi2({
    required double latitude,
    required double longitude,
    String poiName = '',
    String dev = '0', // 是否偏移(0:lat 和 lon 是已经加密后的,不需要国测加密; 1:需要国测加密)
    String message = '您没有安装高德地图,请先安装高德地图!',
  }) async {
    var device = JhDeviceUtils.isAndroid ? 'android' : 'ios';
    var url = '${device}amap://navi?sourceApplication=amap&poiname=$poiName&lat=$latitude&lon=$longitude&dev=$dev';
    // if (!(await canLaunchUrl(Uri.parse(url)))) {
    //   debugPrint(message);
    //   // JhProgressHUD.showText(message);
    //   return;
    // }
    await launchUrl(Uri.parse(url));
  }

  /// 跳转百度导航 - 路径规划
  /// 百度地图官方文档: https://lbsyun.baidu.com/index.php?title=uri/api/android
  static void openBaiduMapNavi({
    double? sLatitude, // 起点纬度
    double? sLongitude, // 起点经度
    String sName = '', // 起点名称
    required double dLatitude, // 终点纬度
    required double dLongitude, // 终点经度
    String dName = '', // 终点名称
    String mode = 'driving', // 导航模式,可选transit(公交)、driving(驾车)、walking(步行)和riding(骑行)默认:driving
    String coordType =
        'gcj02', // 坐标类型,必选参数。coord_type= bd09ll 允许的值为:bd09ll(百度经纬度坐标) bd09mc(百度墨卡托坐标) gcj02(经国测局加密的坐标) wgs84(gps获取的原始坐标)
    String message = '您没有安装百度地图,请先安装百度地图!',
  }) async {
    var url =
        'baidumap://map/direction?origin=name:$sName|latlng:$sLatitude,$sLongitude&destination=name:$dName|latlng:$dLatitude,$dLongitude&mode=$mode&coord_type=$coordType';
    // if (!(await canLaunchUrl(Uri.parse(url)))) {
    //   debugPrint(message);
    //   // JhProgressHUD.showText(message);
    //   return;
    // }
    await launchUrl(Uri.parse(url));
  }

  /// 跳转腾讯导航
  /// 腾讯地图官方文档: https://lbs.qq.com/webApi/uriV1/uriGuide/uriMobileRoute
  static void openTencentMapNavi({
    double? sLatitude, // 起点纬度
    double? sLongitude, // 起点经度
    String sName = '', // 起点名称
    required double dLatitude, // 终点纬度
    required double dLongitude, // 终点经度
    String dName = '', // 终点名称
    String type = 'drive', // 路线规划方式参数:  公交:bus  驾车:drive  步行:walk  骑行:bike
    String referer = 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77', // 请填写开发者key,
    String message = '您没有安装腾讯地图,请先安装腾讯地图!',
  }) async {
    // 起点坐标,格式:lat,lng (纬度在前,经度在后,逗号分隔)  功能参数值:CurrentLocation :使用定位点作为起点坐标
    var formInfo = (sLatitude == null || sLongitude == null)
        ? 'from=$sName&CurrentLocation'
        : 'from=$sName&fromcoord=$sLatitude,$sLongitude';
    var url = 'qqmap://map/routeplan?type=$type&${formInfo}&to=$dName&tocoord=$dLatitude,$dLongitude&referer=$referer';
    // if (!(await canLaunchUrl(Uri.parse(url)))) {
    //   debugPrint(message);
    //   // JhProgressHUD.showText(message);
    //   return;
    // }
    await launchUrl(Uri.parse(url));
  }

  static const double earthRadius = 6378.137; //地球半径

  //计算两点间距离
  static double distance(double lat1, double lng1, double lat2, double lng2) {
    double radLat1 = _rad(lat1);
    double radLat2 = _rad(lat2);
    double a = radLat1 - radLat2;
    double b = _rad(lng1) - _rad(lng2);
    double s = 2 * asin(sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2)));
    s *= earthRadius;
    s = (s * 10000).round() / 10000;
    return s;
  }

  static double _rad(double d) {
    return d * pi / 180.0; //角度转换成弧度
  }
}
相关推荐
陈思杰系统思考Jason7 小时前
系统思考—全局思维
百度·微信·微信公众平台·新浪微博·微信开放平台
m0_748247801 天前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
迷雾漫步者1 天前
Flutter组件————PageView
flutter·跨平台·dart
QQ同步助手1 天前
如何正确使用人工智能:开启智慧学习与创新之旅
人工智能·学习·百度
迷雾漫步者1 天前
Flutter组件————FloatingActionButton
前端·flutter·dart
coder_pig2 天前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
捡芝麻丢西瓜2 天前
flutter自学笔记5- dart 编码规范
flutter·dart
恋猫de小郭2 天前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
sunly_3 天前
Flutter:导航,tab切换,顶部固定,列表分页滚动
开发语言·javascript·flutter
敲代码的小强3 天前
Flutter项目兼容鸿蒙Next系统
flutter·华为·harmonyos