import 'dart:io';
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart';
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
import 'package:flutter_bmflocation/flutter_bmflocation.dart';
import 'package:permission_handler/permission_handler.dart';
typedef LocationResultCallback = void Function(BaiduLocation result);
typedef HeadingResultCallback = void Function(BaiduHeading result);
abstract class LocationService {
LocationFlutterPlugin get locPlugin;
/// 开始定位
Future<bool> startLocation(){
return locPlugin.startLocation();
}
/// 开始获取定位朝向
Future<bool> startUpdatingHeader(){
return locPlugin.startUpdatingHeading();
}
/// 停止定位
Future<bool> stopLocation(){
return locPlugin.stopLocation();
}
/// 设置定位回调
void locationCallback(LocationResultCallback callback){
locPlugin.seriesLocationCallback(callback: callback);
}
/// 设置设备朝向回调
void headerCallback(HeadingResultCallback callback){
locPlugin.updateHeadingCallback(callback: callback);
}
BaiduLocationAndroidOption initAndroidOptions() {
BaiduLocationAndroidOption options = BaiduLocationAndroidOption(
coorType: 'bd09ll',
locationMode: BMFLocationMode.hightAccuracy,
isNeedAddress: true,
isNeedAltitude: true,
isNeedLocationPoiList: true,
isNeedNewVersionRgc: true,
isNeedLocationDescribe: true,
openGps: true,
locationPurpose: BMFLocationPurpose.sport,
coordType: BMFLocationCoordType.bd09ll);
return options;
}
BaiduLocationIOSOption initIOSOptions() {
BaiduLocationIOSOption options = BaiduLocationIOSOption(
coordType: BMFLocationCoordType.bd09ll,
BMKLocationCoordinateType: 'yFDD3IlfSk2xTdQ0G41MjRnzd5gUVG1C',
desiredAccuracy: BMFDesiredAccuracy.best);
return options;
}
/// 初始化定位参数
void initOptions() async {
Map iosMap = initIOSOptions().getMap();
Map androidMap = initAndroidOptions().getMap();
// Waring 如果不setAgreePrivacy(true) 会导致无法定位
locPlugin.setAgreePrivacy(true);
BMFMapSDK.setAgreePrivacy(true);
await locPlugin.prepareLoc(androidMap, iosMap);
}
/// 动态申请定位权限
void requestPermission() async {
// 申请权限
bool hasLocationPermission = await requestLocationPermission();
if (hasLocationPermission) {
// 权限申请通过
} else {}
}
/// 授予定位权限返回true, 否则返回false
Future<bool> requestLocationPermission() async {
//获取当前的权限
var status = await Permission.location.status;
if (status == PermissionStatus.granted) {
//已经授权
return true;
} else {
//未授权则发起一次申请
status = await Permission.location.request();
if (status == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
}
/// 单次定位服务
/// @deprecated: 百度Flutter定位目前不支持多实例(LocationFlutterPlugin)
/// 推荐使用 locationServiceImpl 代替
class SingleLocationService extends LocationService {
final LocationFlutterPlugin _locPlug = LocationFlutterPlugin();
LocationFlutterPlugin get locPlugin => _locPlug;
SingleLocationService(){
requestPermission();
initOptions();
}
locationCallback(LocationResultCallback callback){
var call = (loc){
callback(loc);
// 停止定位
stopLocation();
};
print("except code : ${call.hashCode}");
_locPlug.seriesLocationCallback(callback: call);
}
/// 获取单次定位
void location(LocationResultCallback callback) {
locationCallback(callback);
_locPlug.startLocation();
print("single location instance code ${this.hashCode}, locPlugCode ${_locPlug.hashCode}");
}
BaiduLocationAndroidOption initAndroidOptions(){
var androidOptions = super.initAndroidOptions();
androidOptions.setScanspan(0);
return androidOptions;
}
}
/// 连续定位服务
/// @deprecated: 百度Flutter定位目前不支持多实例(LocationFlutterPlugin)
/// 推荐使用 locationServiceImpl 代替
class SeriesLocationService extends LocationService{
final LocationFlutterPlugin _locPlugin = LocationFlutterPlugin();
bool locationStatus = false;
/// 是否正在连续定位中
bool isStarted() => locationStatus;
/// 连续定位频率
int span;
LocationFlutterPlugin get locPlugin => _locPlugin;
SeriesLocationService({LocationResultCallback? callback, this.span=2000}): super() {
if (callback != null){
locationCallback((result){
callback(result);
});
}
initOptions();
}
Future<bool> stopLocation(){
locationStatus = false;
return locPlugin.stopLocation();
}
void locationCallback(LocationResultCallback callback){
_locPlugin.seriesLocationCallback(callback: (loc){
callback(loc);
});
}
// 参数初始化
BaiduLocationAndroidOption initAndroidOptions() {
var options = super.initAndroidOptions();
options.setScanspan(span);
return options;
}
Future<bool> startLocation(){
if(isStarted()){
return Future(() => false);
}
locationStatus=true;
return locPlugin.startLocation();
}
/// 在地图上绘制定位朝向
void updateUserHeading(BMFMapController mapController, BaiduHeading heading, BMFLocation location, {String title=""}) {
if (Platform.isAndroid) {
//android需要通过course设置方向
location.course = heading.trueHeading;
}
BMFUserLocation userLocation = BMFUserLocation(
//将包含course的BMFLocation对象传值给BMFUserLocation
location: location,
//下面均是iOS的参数,iOS通过heading设置方向
heading: BMFHeading.fromMap(heading.getMap()),
title: title,
);
mapController.updateLocationData(userLocation);
}
}
class LocationCallBack {
final bool isSingleLocation;
final LocationResultCallback locationResultCallback;
LocationCallBack(this.isSingleLocation, this.locationResultCallback);
}
/// 定位服务(单例方式)
class LocationServiceImpl extends LocationService {
final LocationFlutterPlugin _locPlugin = LocationFlutterPlugin();
static LocationServiceImpl? _instance;
static get instance {
_instance ??= LocationServiceImpl._internal();
return _instance;
}
final Set<LocationCallBack> callbackCache = {};
/// 定位服务状态: true 正在定位, false 停止定位
bool locationStatus = false;
LocationServiceImpl._internal() {
super.initOptions();
_locPlugin.seriesLocationCallback(callback: (loc){
List<LocationCallBack> removeItems = [];
for (var item in callbackCache) {
item.locationResultCallback(loc);
if(item.isSingleLocation){
removeItems.add(item);
}
}
// 移除到期的定位回调服务
for (var value in removeItems) {
callbackCache.remove(value);
}
stopLocation();
});
}
/// 停止定位 isEnforce 强制停止定位服务, code 停止(移除)某个定位回调服务
Future<bool> stopLocation({int? code, isEnforce=false}) {
if(isEnforce){
callbackCache.clear();
return _locPlugin.stopLocation();
}
Future<bool> result = Future(() => false);
if(code!=null){
callbackCache.removeWhere((element) => element.hashCode==code);
result = Future(() => true);
}
if (callbackCache.isEmpty) {
_locPlugin.stopLocation();
}else{
print("stop fail there are ${callbackCache.length} callback task");
}
return result;
}
Future<bool> startLocation(){
if(!locationStatus){
return _locPlugin.startLocation();
}
return Future(() => false);
}
LocationFlutterPlugin get locPlugin => _locPlugin;
/// 注册单次定位回调
void singleLocation(LocationResultCallback callback){
callbackCache.add(LocationCallBack(true, (loc){
callback(loc);
stopLocation();
}));
startLocation();
}
/// 注册连续位回调
int seriesLocation(LocationResultCallback callBack){
var item = LocationCallBack(false, callBack);
callbackCache.add(item);
startLocation();
return item.hashCode;
}
}
代码说明:
- SeriesLocationService 与 SingleLocationService 服务不推荐使用; 因为目前的百度的Flutter 定位插件 只能时单实例的也就是只能创建一个LocationFlutterPlugin对象,当你创建多个LocationFlutterPlugin对象时会出现某个LocationFlutterPlugin实例对象的定位回调无法被调用(定位回调调用错乱-我测试了一下,好像是被覆盖了)
- 【推荐】使用LocationServiceImpl ,他支持单次与连续定位,但也有缺点,也就是只能公用一次配置信息(比如:定位回调的周期频率,定位模式等等)。
- 代码比较粗糙,大家可以根据自己实际情况进行二次改造。