需求:
1.实现设备的定位
2.当前位置和目标位置的1000米范围内才能打卡
该页面就是简单的进去的时候就获取定位,如果定位获取到了就停止定位,并toast是否可以打卡的消息。
采用的定位的插件:
flutter_bmflocation: ^2.0.0-nullsafety.0
##为什么使用百度地图的插件?而不是其他的插件
采用的是百度地图的插件,这个星期尝试了三个插件,第一个最先使用的location插件,不需要申请啥开发者啥的直接可以用的,但是悲哀的是时不时会失灵的,怀疑是网络问题,回调死活进不去。第二个尝试的是高德地图的,为什么呢,搜索的时候大家都用高德的,所以我也去试验了一下,但是高德地图明显很久没有维护了,现在flutter是空安全的,但是它明显是老的,不支持空安全,导致调试的时候非常麻烦,虽然可以用,但是为了以后方便还是被pass。然后选择了百度,明显百度有在维护,有支持空安全和不支持空安全的版本,所以选择了它。
##注意
当然使用百度地图的api,当然要去注册开发者申请一个应用,然后去申请AK这一系列麻烦的东西。
dart插件的例子
https://pub.dev/packages/flutter_bmflocation/example
百度定位的flutter的文档,照着来就行
https://lbsyun.baidu.com/index.php?title=flutter/loc
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:math';
import 'package:app_flutter/common/global.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bmflocation/bdmap_location_flutter_plugin.dart';
import 'package:flutter_bmflocation/flutter_baidu_location.dart';
import 'package:flutter_bmflocation/flutter_baidu_location_android_option.dart';
import 'package:flutter_bmflocation/flutter_baidu_location_ios_option.dart';
class ImageUploadRoute extends StatefulWidget {
ImageUploadRoute({Key? key, this.title}) : super(key: key);
final String? title;
@override
_ImageUploadState createState() => _ImageUploadState();
}
class _ImageUploadState extends State<ImageUploadRoute> {
//编辑文本
late TextEditingController _controller;
//定位相关
double lat1=0.0;//当前的维度
double lng1=0.0;//当前的经度
double lat2=0.0;//目的地的维度
double lng2=0.0;//目的地的经度
int limitMmeters=1000;//限制上传的距离,一公里范围内
late Map<String, Object>? _loationResult=null;
BaiduLocation? _baiduLocation;
late StreamSubscription<Map<String, Object>?> _locationListener;
LocationFlutterPlugin _locationPlugin = new LocationFlutterPlugin();
//初始化的时候打开定位相关
@override
void initState() {
super.initState();
_controller = TextEditingController();
/// 动态申请定位权限
_locationPlugin.requestPermission();
/// 设置ios端ak, android端ak可以直接在清单文件中配置
LocationFlutterPlugin.setApiKey("jInwiO1AhcbkZyz0Z9ZL9fC88pThdGZP");
_locationListener = _locationPlugin.onResultCallback().listen((Map<String, Object>? result) {
setState(() {
_loationResult = result;
print("longitude$result['longitude']");
try {
_baiduLocation = BaiduLocation.fromMap(result);
isInArea();
// print(_baiduLocation);
} catch (e) {
print(e);
}
});
});
_startLocation();//开启位置监听
}
@override
void dispose() {
_controller.dispose();
super.dispose();
if (null != _locationListener) {
_locationListener.cancel();
}
}
/// 设置android端和ios端定位参数
void _setLocOption() {
/// android 端设置定位参数
BaiduLocationAndroidOption androidOption = new BaiduLocationAndroidOption();
androidOption.setCoorType("bd09ll"); // 设置返回的位置坐标系类型
androidOption.setIsNeedAltitude(true); // 设置是否需要返回海拔高度信息
androidOption.setIsNeedAddres(true); // 设置是否需要返回地址信息
androidOption.setIsNeedLocationPoiList(true); // 设置是否需要返回周边poi信息
androidOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
androidOption.setIsNeedLocationDescribe(true); // 设置是否需要返回位置描述
androidOption.setOpenGps(true); // 设置是否需要使用gps
androidOption.setLocationMode(LocationMode.Hight_Accuracy); // 设置定位模式
androidOption.setScanspan(1000); // 设置发起定位请求时间间隔
Map androidMap = androidOption.getMap();
/// ios 端设置定位参数
BaiduLocationIOSOption iosOption = new BaiduLocationIOSOption();
iosOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
iosOption.setBMKLocationCoordinateType(
"BMKLocationCoordinateTypeBMK09LL"); // 设置返回的位置坐标系类型
iosOption.setActivityType("CLActivityTypeAutomotiveNavigation"); // 设置应用位置类型
iosOption.setLocationTimeout(10); // 设置位置获取超时时间
iosOption.setDesiredAccuracy("kCLLocationAccuracyBest"); // 设置预期精度参数
iosOption.setReGeocodeTimeout(10); // 设置获取地址信息超时时间
iosOption.setDistanceFilter(100); // 设置定位最小更新距离
iosOption.setAllowsBackgroundLocationUpdates(true); // 是否允许后台定位
iosOption.setPauseLocUpdateAutomatically(true); // 定位是否会被系统自动暂停
Map iosMap = iosOption.getMap();
_locationPlugin.prepareLoc(androidMap, iosMap);
}
/// 启动定位
void _startLocation() {
if (null != _locationPlugin) {
_setLocOption();
_locationPlugin.startLocation();
}
}
/// 停止定位
void _stopLocation() {
if (null != _locationPlugin) {
_locationPlugin.stopLocation();
}
}
double _rad(double d) {
return d * pi / 180.0;
}
double _getDistance(double lat1, double lng1, double lat2, double lng2) {
/// 单位:米
/// def :地球半径
double def = 6378137.0;
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)));
return (s * def ).roundToDouble();
}
//是否在范围内?
void isInArea(){
lat1=_baiduLocation?.latitude??0;//如果没值 那么0
lng1=_baiduLocation?.longitude??0;//如果没值 那么0
double distance=_getDistance(lat1,lng1,lat2,lng2);
if(lat1!=0&&lng1!=0){//正确的获取到了坐标
if(limitMmeters>=distance){//在范围内允许
Global.showCenterToast("允许打卡");
_stopLocation();
}else{//在范围外
Global.showCenterToast("不在范围内,当前距离目标位置$distance米,打卡范围为$limitMmeters米");
_stopLocation();
}
}else{
Global.showCenterToast("位置获取中!");
}
}
//页面的控件布局
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("定位"),),
body:Stack(
children: [
Positioned(//占满屏幕
top: 0,
bottom: 0,
left: 0,
right: 0,
child: Column(
children: [
TextField(
maxLines: 10,
minLines: 3,
controller:_controller,
decoration:InputDecoration(
border:InputBorder.none ,
fillColor:Colors.white ,
filled: true,
hintText: "签收情况",
),
),
],
)),
],
)
);
}
}