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
使用:
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),);
}
}