Flutter--高德地图使用指南

1.在高德官网申请Key

2.导入flutter包

dependencies:
  amap_flutter_map: ^3.0.0

3.初始化

官网的说明很混乱,经过实验。3.0.0版sdk后,初始化apikey这种操作不需要在原生代码中操作了,在你要创建地图时,应当采用如下做法:

iOS和安卓除了添加必要的权限如:定位等,安卓还需添加如下配置:

//安卓所需权限
    
    //获取设备网络状态,禁用后无法获取网络状态
    
    //网络权限,当禁用后,无法进行检索等相关业务
    
    //读取设备硬件信息,统计数据
    
    //读取系统信息,包含系统版本等信息,用作统计
    
    //获取设备的网络状态,鉴权所需网络代理
    
    //允许sd卡写权限,需写入地图数据,禁用后无法显示地图
    
    //获取统计数据
    
    //遇到地图不显示补充以下权限
    
    

android {
    defaultConfig {
        ndk {
            //设置支持的SO库架构(开发者可以根据需要,选择一个或多个平台的so)
            abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86","x86_64"
        }
    }
}

//按照需要添加
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    //3D地图so及jar
    compile 'com.amap.api:3dmap:latest.integration'
    //定位功能
    compile 'com.amap.api:location:latest.integration'
    //搜索功能
    compile 'com.amap.api:search:latest.integration'
}

注意:privacyStatement该参数表示已经给用户看过相关协议,权限要求等,不写拿不到数据,如果要上架必须要在执行该代码前用明显弹窗提示,具体内容可参考重要: SDK合规使用方案 | 高德地图API

///建议在APP首次启动或者进行弹窗进行隐私声明时,根据用户设置
///
/// [hasContains] 隐私权政策是否包含高德开平隐私权政策
///
///[hasShow] 隐私权政策是否弹窗展示告知用户
///
///[hasAgree] 隐私权政策是否已经取得用户同意

    final AMapWidget map = AMapWidget(
      privacyStatement: AMapPrivacyStatement(hasShow: true, hasAgree: true, hasContains: true),
      apiKey: AMapApiKey(
        iosKey: 'You key',
        androidKey: 'You key'
      ),
    );

4.获取审图号

任何使用高德地图API调用地图服务的应用必须在其应用中对外透出审图号,如高德地图在“关于”中的体现。获取审图号应该在地图创建完成后进行,一般在onMapCreated回调里通过AMapController获取即可,如下:

  /// 获取审图号
  void getApprovalNumber(mapController) async {
    //普通地图审图号
    String? mapContentApprovalNumber = await mapController?.getMapContentApprovalNumber();
    //卫星地图审图号
    String? satelliteImageApprovalNumber = await mapController?.getSatelliteImageApprovalNumber();

    print('地图审图号(普通地图): $mapContentApprovalNumber');
    print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
  }


  @override
  Widget build(BuildContext context) {
    final AMapWidget map = AMapWidget(
      initialCameraPosition: _kInitialPosition,
      onMapCreated: onMapCreated,
      privacyStatement: AMapPrivacyStatement(hasShow: true, hasAgree: true, hasContains: true),
      apiKey: AMapApiKey(
        iosKey: '',
        androidKey: ''
      ),
    );

    return map;
  }


  void onMapCreated(AMapController controller) {
    getApprovalNumber(mapController);
  }

5.其他功能实现

这里插一句想要用坐标移动地图视觉等需要用到 AMapController,只能在AMapWidget的onMapCreated回调中获得

参考:创建地图-地图Flutter插件-开发指南-Flutter插件 | 高德地图API

6.Demo

import 'dart:async';
import 'dart:io';

import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:permission_handler/permission_handler.dart';



class AMapPage extends StatelessWidget {

  final String iosKey;
  final String androidKey;

  final LatLng? latLng;
  final void Function(AMapController controller)? onMapCreated;


  const AMapPage(this.iosKey, this.androidKey, {Key? key, this.latLng, this.onMapCreated}) : super(key: key);


  @override
  Widget build(BuildContext context) {

    CameraPosition kInitialPosition = CameraPosition(
      target: latLng ?? const LatLng(39.909187, 116.397451),
      zoom: 10.0,
    );

    return AMapWidget(
      initialCameraPosition: kInitialPosition,
      buildingsEnabled: false,
      onMapCreated: onCreated,
      privacyStatement: const AMapPrivacyStatement(hasShow: true, hasAgree: true, hasContains: true),
      apiKey: AMapApiKey(
        iosKey: iosKey,
        androidKey: androidKey,
      ),
    );
  }


  void onCreated(AMapController controller) {
    AMapApprovalNumber.setApprovalNumber(controller);
    if (onMapCreated != null) onMapCreated!(controller);
  }

}

/// 获取审图号
/// 这里设计的很奇怪,当地图创建后才知道这个号码,但是这个号码不一定要显示在地图之上,却一定要显示在app之内,主要是和上架后的合规有关
class AMapApprovalNumber {
  static String? mapContentApprovalNumber;
  static String? satelliteImageApprovalNumber;

  static Function(String? mapContentApprovalNumber, String? satelliteImageApprovalNumber)? _listener;

  static void addListener(Function(String? mapContentApprovalNumber, String? satelliteImageApprovalNumber) run) {
    _listener = run;
  }

  static void setApprovalNumber(AMapController? mapController) async {
    //普通地图审图号
    mapContentApprovalNumber = await mapController?.getMapContentApprovalNumber();
    //卫星地图审图号
    satelliteImageApprovalNumber = await mapController?.getSatelliteImageApprovalNumber();

    if (kDebugMode) {
      print('地图审图号(普通地图): $mapContentApprovalNumber');
      print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
    }

    if (_listener != null) _listener!(mapContentApprovalNumber, satelliteImageApprovalNumber);
  }
}




///需要在程序启动时向用户展示隐私政策等
///高德地图的定位插件,可以进行连续定位,返回当前位置的经纬度以及转译过的位置信息
mixin AMapLocationStateMixin on State {

  String get iosKey;
  String get androidKey;


  /// 是否拥有定位权限
  bool get hasLocationPermission => _hasLocationPermission;

  ///获取到的定位信息
  Map get locationResult => _locationResult ?? {};
  ///整理过的数据
  LocationInfo get locationInfo => LocationInfo(locationResult);

  ///开始定位
  void startLocation() {
    ///开始定位之前设置定位参数
    _setLocationOption();
    _locationPlugin.startLocation();
  }

  ///停止定位
  void stopLocation() {
    _locationPlugin.stopLocation();
  }


  Map? _locationResult;

  StreamSubscription>? _locationListener;

  final AMapFlutterLocation _locationPlugin = AMapFlutterLocation();

  @override
  void initState() {
    super.initState();
    /// 设置是否已经包含高德隐私政策并弹窗展示显示用户查看,如果未包含或者没有弹窗展示,高德定位SDK将不会工作
    ///
    /// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
    /// 必须保证在调用定位功能之前调用, 建议首次启动App时弹出《隐私政策》并取得用户同意
    ///
    /// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
    ///
    /// [hasContains] 隐私声明中是否包含高德隐私政策说明
    ///
    /// [hasShow] 隐私权政策是否弹窗展示告知用户
    AMapFlutterLocation.updatePrivacyShow(true, true);

    /// 设置是否已经取得用户同意,如果未取得用户同意,高德定位SDK将不会工作
    ///
    /// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
    ///
    /// 必须保证在调用定位功能之前调用, 建议首次启动App时弹出《隐私政策》并取得用户同意
    ///
    /// [hasAgree] 隐私权政策是否已经取得用户同意
    AMapFlutterLocation.updatePrivacyAgree(true);

    /// 动态申请定位权限
    _requestLocationPermission();

    ///设置Android和iOS的apiKey
///key的申请请参考高德开放平台官网说明
///Android: https://lbs.amap.com/api/android-location-sdk/guide/create-project/get-key ///iOS: https://lbs.amap.com/api/ios-location-sdk/guide/create-project/get-key AMapFlutterLocation.setApiKey(androidKey, iosKey); ///iOS 获取native精度类型 if (Platform.isIOS) { _requestAccuracyAuthorization(); } ///注册定位结果监听 _locationListener = _locationPlugin.onLocationChanged().listen((Map result) { setState(() { _locationResult = result; }); }); } @override void dispose() { super.dispose(); ///移除定位监听 if (null != _locationListener) { _locationListener?.cancel(); } ///销毁定位 _locationPlugin.destroy(); } ///设置定位参数 void _setLocationOption() { AMapLocationOption locationOption = AMapLocationOption(); ///是否单次定位 locationOption.onceLocation = false; ///是否需要返回逆地理信息 locationOption.needAddress = true; ///逆地理信息的语言类型 locationOption.geoLanguage = GeoLanguage.DEFAULT; locationOption.desiredLocationAccuracyAuthorizationMode = AMapLocationAccuracyAuthorizationMode.ReduceAccuracy; locationOption.fullAccuracyPurposeKey = "AMapLocationScene"; ///设置Android端连续定位的定位间隔 locationOption.locationInterval = 2000; ///设置Android端的定位模式
///可选值:
///
  • [AMapLocationMode.Battery_Saving]
  • ///
  • [AMapLocationMode.Device_Sensors]
  • ///
  • [AMapLocationMode.Hight_Accuracy]
  • locationOption.locationMode = AMapLocationMode.Hight_Accuracy; ///设置iOS端的定位最小更新距离
    locationOption.distanceFilter = -1; ///设置iOS端期望的定位精度 /// 可选值:
    ///
  • [DesiredAccuracy.Best] 最高精度
  • ///
  • [DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度
  • ///
  • [DesiredAccuracy.NearestTenMeters] 10米
  • ///
  • [DesiredAccuracy.Kilometer] 1000米
  • ///
  • [DesiredAccuracy.ThreeKilometers] 3000米
  • locationOption.desiredAccuracy = DesiredAccuracy.Best; ///设置iOS端是否允许系统暂停定位 locationOption.pausesLocationUpdatesAutomatically = false; ///将定位参数设置给定位插件 _locationPlugin.setLocationOption(locationOption); } ///获取iOS native的accuracyAuthorization类型 Future _requestAccuracyAuthorization() async { AMapAccuracyAuthorization currentAccuracyAuthorization = await _locationPlugin.getSystemAccuracyAuthorization(); if (kDebugMode) { if (currentAccuracyAuthorization == AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) { print("精确定位类型"); } else if (currentAccuracyAuthorization == AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) { print("模糊定位类型"); } else { print("未知定位类型"); } } return currentAccuracyAuthorization; } bool _hasLocationPermission = false; /// 申请定位权限 Future _requestLocationPermission() async { //获取当前的权限 var status = await Permission.location.status; if (status == PermissionStatus.granted) { //已经授权 _hasLocationPermission = true; } else { //未授权则发起一次申请 status = await Permission.location.request(); if (status == PermissionStatus.granted) { _hasLocationPermission = true; } else { _hasLocationPermission = false; } } if (kDebugMode) { if (_hasLocationPermission) { print("定位权限申请通过"); } else { print("定位权限申请不通过"); } } } } class LocationInfo { //TODO:应当再此类对信息做转换,明确数据类型 String? locTime; String? province; String? callbackTime; String? district; double? speed; double? latitude; double? longitude; String? country; String? city; String? cityCode; String? street; String? streetNumber; String? address; String? description; double? bearing; double? accuracy; String? adCode; double? altitude; int? locationType; LocationInfo(Map locationResult) { locTime = locationResult["locTime"] as String; province = locationResult["province"] as String; callbackTime = locationResult["callbackTime"] as String; district = locationResult["district"] as String; speed = locationResult["speed"] as double; latitude = double.parse(locationResult["latitude"] as String); longitude = double.parse(locationResult["longitude"] as String); country = locationResult["country"] as String; city = locationResult["city"] as String; cityCode = locationResult["cityCode"] as String; street = locationResult["street"] as String; streetNumber = locationResult["streetNumber"] as String; address = locationResult["address"] as String; description = locationResult["description"] as String; bearing = locationResult["bearing"] as double; accuracy = locationResult["accuracy"] as double; adCode = locationResult["adCode"] as String; altitude = locationResult["altitude"] as double; locationType = locationResult["locationType"] as int; } }

    使用:

    import 'dart:async';
    import 'dart:io';
    
    import 'package:amap_flutter_location/amap_flutter_location.dart';
    import 'package:amap_flutter_location/amap_location_option.dart';
    import 'package:amap_test_app/amap_page.dart';
    import 'package:flutter/material.dart';
    
    import 'package:amap_flutter_map/amap_flutter_map.dart';
    import 'package:amap_flutter_base/amap_flutter_base.dart';
    import 'package:permission_handler/permission_handler.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: _ShowMapPageBody(),
        );
      }
    }
    
    
    
    
    class _ShowMapPageBody extends StatefulWidget {
      @override
      State createState() => _ShowMapPageState();
    }
    
    class _ShowMapPageState extends State<_ShowMapPageBody>  with AMapLocationStateMixin {
    
      @override
      String get iosKey => '42dbeddf9adbc780e7b09da13ddd5755';
    
      @override
      String get androidKey => '1dbf56e2e8a4d0e4cdc2df9efd36bc71';
    
      String? get mapContentApprovalNumber => AMapApprovalNumber.mapContentApprovalNumber;
      String? get satelliteImageApprovalNumber => AMapApprovalNumber.satelliteImageApprovalNumber;
    
      @override
      void initState() {
        super.initState();
    
        startLocation();
      }
    
      AMapController? aMapController;
    
      @override
      Widget build(BuildContext context) {
        final AMapPage map = AMapPage(iosKey, androidKey, onMapCreated: (AMapController controller) {
          aMapController = controller;
        },);
    
        List approvalNumberWidget = [
          if (null != mapContentApprovalNumber) Text(mapContentApprovalNumber!),
          if (null != satelliteImageApprovalNumber) Text(satelliteImageApprovalNumber!),
        ];
    
        return Scaffold(
          appBar: AppBar(
            title: const Text("高德地图"),
            actions: [
              TextButton(onPressed: () {
                LatLng latlng = LatLng(locationInfo.latitude ?? 39.909187, locationInfo.longitude ?? 116.397451);
                CameraUpdate cameraUpdate = CameraUpdate.newLatLng(latlng);
                aMapController?.moveCamera(cameraUpdate);
              }, child: const Icon(Icons.location_on_rounded, color: Colors.red,))
            ],
          ),
          body: map,
          drawer: Container(
            color: Colors.white,
            child: SafeArea(
              child: Column(children: [
                createButtonContainer(),
                Expanded(child: resultList()),
                ...approvalNumberWidget,
              ],),
            ),
            width: MediaQuery.of(context).size.width * 0.8,
          ),
        );
    
      }
    
    
      Widget createButtonContainer() {
        return Row(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: startLocation,
              child: const Text('开始定位'),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.blue),
                foregroundColor: MaterialStateProperty.all(Colors.white),
              ),
            ),
            Container(width: 20.0),
            ElevatedButton(
              onPressed: stopLocation,
              child: const Text('停止定位'),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.blue),
                foregroundColor: MaterialStateProperty.all(Colors.white),
              ),
            )
          ],
        );
      }
    
      Widget resultList() {
        List widgets = [];
    
        locationResult.forEach((key, value) {
          widgets.add(Text('$key: $value', softWrap: true, style: const TextStyle(color: Colors.lightGreenAccent),),);
        });
    
        return ListView(children: widgets, padding: const EdgeInsets.all(8),);
      }
    
    }
    
    
    

    你可能感兴趣的:(flutter开发,flutter)