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; //角度转换成弧度
  }
}
相关推荐
天渺工作室16 分钟前
Flutter 版的 NVM——FVM 使用指南
flutter·dart
Lanren的编程日记11 小时前
Flutter鸿蒙应用开发:生物识别(指纹/面容)功能集成实战
flutter·华为·harmonyos
Lanren的编程日记14 小时前
Flutter鸿蒙应用开发:基础UI组件库设计与实现实战
flutter·ui·harmonyos
西西学代码14 小时前
Flutter---波形动画
flutter
于慨18 小时前
flutter基础组件用法
开发语言·javascript·flutter
恋猫de小郭20 小时前
Android CLI ,谷歌为 Android 开发者专研的 AI Agent,提速三倍
android·前端·flutter
火柴就是我21 小时前
flutter pushAndRemoveUntil 的一次小疑惑
flutter
于慨21 小时前
flutter doctor问题解决
flutter
唔6621 小时前
flutter 图片加载类 图片的安全使用
安全·flutter
Nathan202406161 天前
Flutter - InheritedWidget
flutter·dart