amap_flutter_location.dart
10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'amap_location_option.dart';
/// 高德定位Flutter插件入口类
/// 提供定位功能的主要接口,包括开始定位、停止定位、设置参数等功能
class AMapFlutterLocation {
// 定义与原生平台交互的通道名称
/// 方法通道名称,用于调用原生方法
static const String _CHANNEL_METHOD_LOCATION = "csp_amap_flutter_location";
/// 事件通道名称,用于接收原生端的定位结果
static const String _CHANNEL_STREAM_LOCATION =
"csp_amap_flutter_location_stream";
/// 方法通道,用于调用原生方法
static const MethodChannel _methodChannel =
MethodChannel(_CHANNEL_METHOD_LOCATION);
/// 事件通道,用于接收原生端的定位结果流
static const EventChannel _eventChannel =
EventChannel(_CHANNEL_STREAM_LOCATION);
/// 定位结果的广播流,将原生端的定位结果转换为Map类型
static final Stream<Map<String, Object>> _onLocationChanged = _eventChannel
.receiveBroadcastStream()
.asBroadcastStream()
.map<Map<String, Object>>((element) => element.cast<String, Object>());
/// 逆地理位置编码结果的广播流,将原生端的逆地理位置编码结果转换为Map类型
static final Stream<Map<String, Object>> _onGeocodeSearchChanged =
_eventChannel
.receiveBroadcastStream()
.asBroadcastStream()
.map<Map<String, Object>>(
(element) => element.cast<String, Object>());
/// 定位结果的流控制器
StreamController<Map<String, Object>>? _receiveStream;
/// 逆地理位置编码结果的流控制器
StreamController<Map<String, Object>>? _receiveGeocodeSearchStream;
/// 定位结果的流订阅
StreamSubscription<Map<String, Object>>? _subscription;
/// 逆地理位置编码结果的流订阅
StreamSubscription<Map<String, Object>>? _subscriptionGeocodeSearch;
/// 插件实例的唯一标识符
String? _pluginKey;
/// 适配iOS 14定位新特性,获取系统定位精度授权状态
/// 只在iOS平台有效
/// 返回:定位精度授权状态枚举值
Future<AMapAccuracyAuthorization> getSystemAccuracyAuthorization() async {
int result = -1;
if (Platform.isIOS) {
result = await _methodChannel.invokeMethod(
"getSystemAccuracyAuthorization", {'pluginKey': _pluginKey});
}
if (result == 0) {
return AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy;
} else if (result == 1) {
return AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy;
}
return AMapAccuracyAuthorization.AMapAccuracyAuthorizationInvalid;
}
/// 初始化定位插件
/// 创建唯一的插件标识符
AMapFlutterLocation() {
_pluginKey = DateTime.now().millisecondsSinceEpoch.toString();
}
/// 开始定位
/// 调用原生端开始定位的方法
void startLocation() {
_methodChannel.invokeMethod('startLocation', {'pluginKey': _pluginKey});
return;
}
/// 开始逆地理位置编码
/// 调用原生端开始定位的方法
Future<String> onGeocodeSearch(bool once, List<num> points) async {
String result = await _methodChannel.invokeMethod('onGeocodeSearch',
{'pluginKey': _pluginKey, 'points': points, 'once': once});
return result;
}
/// 圆形搜索
Future<List<dynamic>>poiSearchAround(String keyword,double longitude,double latitude) async {
List<dynamic> result = await _methodChannel.invokeMethod('poiSearchAround',
{'pluginKey': _pluginKey, 'keyword': keyword, 'longitude': longitude,'latitude':latitude});
return result;
}
/// 输入提示
Future<List<dynamic>> doInputtipsRequest(String keyword, {String city=''}) async {
List<dynamic> result = await _methodChannel.invokeMethod('doInputtipsRequest',
{'pluginKey': _pluginKey, 'keyword': keyword, 'city': city});
return result;
}
/// 停止定位
/// 调用原生端停止定位的方法
void stopLocation() {
_methodChannel.invokeMethod('stopLocation', {'pluginKey': _pluginKey});
return;
}
/// 设置Android和iOS的apikey
/// 建议在widget初始化时设置
/// apiKey的申请请参考高德开放平台官网
/// @param androidKey Android平台的key
/// @param iosKey iOS平台的key
/// @param ohosKey 鸿蒙平台的key(可选)
static void setApiKey(String androidKey, String iosKey, {String? ohosKey}) {
_methodChannel.invokeMethod(
'setApiKey', {'android': androidKey, 'ios': iosKey, 'ohos': ohosKey});
}
/// 设置定位参数
/// @param locationOption 定位参数对象
void setLocationOption(AMapLocationOption locationOption) {
Map option = locationOption.getOptionsMap();
option['pluginKey'] = _pluginKey;
_methodChannel.invokeMethod('setLocationOption', option);
}
/// 销毁定位
/// 释放定位资源,取消流订阅
void destroy() {
_methodChannel.invokeListMethod('destroy', {'pluginKey': _pluginKey});
if (_subscription != null) {
_receiveStream?.close();
_subscription?.cancel();
_receiveStream = null;
_subscription = null;
}
if (_subscriptionGeocodeSearch != null) {
_receiveGeocodeSearchStream?.close();
_subscriptionGeocodeSearch?.cancel();
_receiveGeocodeSearchStream = null;
_subscriptionGeocodeSearch = null;
}
}
/// 定位结果回调
///
/// 定位结果以map的形式透出,其中包含的key已经含义如下:
///
/// `callbackTime`:回调时间,格式为"yyyy-MM-dd HH:mm:ss"
///
/// `locationTime`:定位时间, 格式为"yyyy-MM-dd HH:mm:ss"
///
/// `locationType`: 定位类型, 具体类型可以参考https://lbs.amap.com/api/android-location-sdk/guide/utilities/location-type
///
/// `latitude`:纬度
///
/// `longitude`:精度
///
/// `accuracy`:精确度
///
/// `altitude`:海拔, android上只有locationType==1时才会有值
///
/// `bearing`: 角度,android上只有locationType==1时才会有值
///
/// `speed`:速度, android上只有locationType==1时才会有值
///
/// `country`: 国家,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `province`: 省,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `city`: 城市,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `district`: 城镇(区),android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `street`: 街道,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `streetNumber`: 门牌号,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `cityCode`: 城市编码,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `adCode`: 区域编码, android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `address`: 地址信息, android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `description`: 位置语义, android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `errorCode`: 错误码,当定位失败时才会返回对应的错误码, 具体错误请参考:https://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode
///
/// `errorInfo`: 错误信息, 当定位失败时才会返回
Stream<Map<String, Object>> onLocationChanged() {
if (_receiveStream == null) {
_receiveStream = StreamController();
_subscription = _onLocationChanged.listen((Map<String, Object> event) {
if (event['pluginKey'] == _pluginKey) {
try {
Map<String, Object> newEvent = Map<String, Object>.of(event);
newEvent.remove('pluginKey');
_receiveStream?.add(newEvent);
} catch (e) {
print("注册定位结果监听 error : $e");
}
}
// _receiveStream?.add(event);
});
}
return _receiveStream!.stream;
}
///逆地理位置编码结果回调
Stream<Map<String, Object>> onGeocodeSearchChange() {
if (_receiveGeocodeSearchStream == null) {
_receiveGeocodeSearchStream = StreamController();
_subscription =
_onGeocodeSearchChanged.listen((Map<String, Object> event) {
if (event['pluginKey'] == _pluginKey) {
try {
Map<String, Object> newEvent = Map<String, Object>.of(event);
newEvent.remove('pluginKey');
_receiveGeocodeSearchStream?.add(newEvent);
} catch (e) {
print("注册定位结果监听 error : $e");
}
}
// _receiveStream?.add(event);
});
}
return _receiveGeocodeSearchStream!.stream;
}
/// 设置是否已经包含高德隐私政策并弹窗展示显示用户查看
/// 如果未包含或者没有弹窗展示,高德定位SDK将不会工作
/// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
/// 必须保证在调用定位功能之前调用,建议首次启动App时弹出《隐私政策》并取得用户同意
/// @param hasContains 隐私声明中是否包含高德隐私政策说明
/// @param hasShow 隐私权政策是否弹窗展示告知用户
static void updatePrivacyShow(bool hasContains, bool hasShow) {
_methodChannel.invokeMethod('updatePrivacyStatement',
{'hasContains': hasContains, 'hasShow': hasShow});
}
/// 设置是否已经取得用户同意
/// 如果未取得用户同意,高德定位SDK将不会工作
/// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
/// 必须保证在调用定位功能之前调用,建议首次启动App时弹出《隐私政策》并取得用户同意
/// @param hasAgree 隐私权政策是否已经取得用户同意
static void updatePrivacyAgree(bool hasAgree) {
_methodChannel
.invokeMethod('updatePrivacyStatement', {'hasAgree': hasAgree});
}
}