「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
本篇文章主要讲解在 Flutter 中如何集成百度定位 SDK 定位获取当前位置信息。
百度官网提供了定位的 Flutter SDK,但是在集成过程中可能会存在很多坑,本文将详细介绍如何一步一步集成百度定位 SDK 实现定位功能。
添加依赖
在项目的 pubspec.yaml 中添加百度定位 sdk 库 flutter_bmflocation ,最新版本为 2.0.0 且已支持空安全,如下:
dependencies:
flutter_bmflocation: ^2.0.0-nullsafety.1
配置
百度控制台创建应用
要使用百度定位 SDK,需先在百度百度地图开放平台控制台创建对应平台的应用:
Android:
如上图,填写应用名称,应用类型选择 Android SDK,然后选择需要用到的服务,最后填写应用的签名 SHA1 指纹以及包名点击提交即可。
iOS:
如上图,填写应用名称,应用类型选择 iOS SDK,选择需要用到的服务,最后填写应用安全码(Bundle Identifier)点击提交即可。
创建应用后即可在应用列表中获取应用的 AK :
配置 AK
Android
在项目的 android/app/src/main/AndroidManifest.xml 的 application 中添加 meta-data 配置应用的 AK, 如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.loongwind.core.flutter_app_core">
<application
android:label="flutter_app_core"
android:icon="@mipmap/ic_launcher">
<...>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="2o77w1HNochxxxxxxxxxxxxmjNTmFulAYl" />
</application>
</manifest>
iOS
iOS 配置 AK 可直接在 Flutter 中调用 setApiKey 进行设置, 如下:
if(Platform.isIOS){
LocationFlutterPlugin.setApiKey("GfhocIpWb6uxxxxxxxxxxfpVgtgFwIOg2");
}
iOS 配置
iOS 集成百度 SDK 还需进行如下配置:
- 权限配置
在项目的 Info.plist 添加定位权限申请, 如图添加 Privacy - Location When In Use Usage Description 并在 Value 填写使用该定位权限的描述。
在项目的 Info.plist 添加 App Transport Security Settings 字段,并在其下添加 Allow Arbitrary Loads 项并将值设置为 YES , 如图:
- 环境配置
在 TARGETS->Build Settings-> Linking -> Other Linker Flags 中添加 -ObjC
- PodFile 配置
因为百度地图定位 SDK 使用到了 permission_handler 库用于权限获取,所以需要在项目的 ios/Podfile 中添加 permission_handler 的定位权限配置。
在 PodFile 的 post_install 下添加 permission_handler 的权限配置:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.calendar
# 'PERMISSION_EVENTS=1',
## dart: PermissionGroup.reminders
# 'PERMISSION_REMINDERS=1',
## dart: PermissionGroup.contacts
# 'PERMISSION_CONTACTS=1',
## dart: PermissionGroup.camera
# 'PERMISSION_CAMERA=1',
## dart: PermissionGroup.microphone
# 'PERMISSION_MICROPHONE=1',
## dart: PermissionGroup.speech
# 'PERMISSION_SPEECH_RECOGNIZER=1',
## dart: PermissionGroup.photos
# 'PERMISSION_PHOTOS=1',
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=1',
## dart: PermissionGroup.notification
# 'PERMISSION_NOTIFICATIONS=1',
## dart: PermissionGroup.mediaLibrary
# 'PERMISSION_MEDIA_LIBRARY=1',
## dart: PermissionGroup.sensors
# 'PERMISSION_SENSORS=0'
]
end
flutter_additional_ios_build_settings(target)
end
end
因为这里只需要定位的权限,所以将 PERMISSION_LOCATION 的注释放开即可。
关于 permission_handler 的具体使用请查阅官方文档 permission_handler
定位
经过上面的配置,就可以在 Flutter 中使用百度定位 SDK 进行定位了。创建一个 LocationService 类,用于封装定位相关代码。
导入定位相关类文件
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';
初始化
/// 创建插件对象
final LocationFlutterPlugin _locationPlugin = LocationFlutterPlugin();
/// 初始化
void init(){
if(Platform.isIOS){
/// 设置 iOS 应用的 AK
LocationFlutterPlugin.setApiKey("GfhocIpWb6uxxxxxxxxxxfpVgtgFwIOg2");
}
}
设置定位参数
/// 设置android端和ios端定位参数
void _setLocOption() {
/// android 端设置定位参数
BaiduLocationAndroidOption androidOption = BaiduLocationAndroidOption();
/// 可选,设置返回经纬度坐标类型,默认gcj02
/// gcj02:国测局坐标;
/// bd09ll:百度经纬度坐标;
/// bd09:百度墨卡托坐标;
/// 海外地区定位,无需设置坐标类型,统一返回wgs84类型坐标
androidOption.setCoorType("bd09ll");
androidOption.setIsNeedAltitude(true); /// 设置是否需要返回海拔高度信息
androidOption.setIsNeedAddres(true); /// 设置是否需要返回地址信息
androidOption.setIsNeedLocationPoiList(true); /// 设置是否需要返回周边poi信息
androidOption.setIsNeedNewVersionRgc(true); /// 设置是否需要返回最新版本rgc信息
androidOption.setIsNeedLocationDescribe(true); /// 设置是否需要返回位置描述
androidOption.setOpenGps(true); /// 设置是否需要使用gps
/// 可选,设置定位模式,可选的模式有高精度、低功耗、仅设备,默认为高精度模式,可选值如下:
/// 高精度模式: LocationMode.Hight_Accuracy
/// 低功耗模式:LocationMode.Battery_Saving
/// 仅设备(Gps)模式:LocationMode.Device_Sensors
androidOption.setLocationMode(LocationMode.Hight_Accuracy);
/// 可选,设置发起定位请求的间隔,int类型,单位ms
/// 如果设置为0,则代表单次定位,即仅定位一次,默认为0
/// 如果设置非0,需设置1000ms以上才有效
androidOption.setScanspan(1000);
/// 可选,设置场景定位参数,包括签到场景、运动场景、出行场景,可选值如下:
/// 签到场景: BDLocationPurpose.SignIn
/// 运动场景: BDLocationPurpose.Transport
/// 出行场景: BDLocationPurpose.Sport
androidOption.setLocationPurporse(BDLocationPurpose.SignIn);
Map androidMap = androidOption.getMap();
/// ios 端设置定位参数
BaiduLocationIOSOption iosOption = new BaiduLocationIOSOption();
iosOption.setIsNeedNewVersionRgc(true); /// 设置是否需要返回最新版本rgc信息
/// 可选,设置返回位置的坐标系类型 ,参数为String类型,可选值如下:
/// "BMKLocationCoordinateTypeBMK09LL" 百度经纬度坐标
/// "BMKLocationCoordinateTypeBMK09MC" 百度墨卡托坐标
/// "BMKLocationCoordinateTypeWGS84" gps坐标
/// "BMKLocationCoordinateTypeGCJ02" 国测局坐标
iosOption.setBMKLocationCoordinateType("BMKLocationCoordinateTypeBMK09LL");
/// 可选,设置应用位置类型,参数为String类型,可选值如下:
/// "CLActivityTypeOther"
/// "CLActivityTypeAutomotiveNavigation"
/// "CLActivityTypeFitness"
/// "CLActivityTypeOtherNavigation"
iosOption.setActivityType("CLActivityTypeAutomotiveNavigation");
iosOption.setLocationTimeout(10); /// 设置位置获取超时时间
/// 可选,设置期望定位精度,参数为String类型,可选值如下:
/// "kCLLocationAccuracyBest"
/// "kCLLocationAccuracyNearestTenMeters"
/// "kCLLocationAccuracyHundredMeters"
/// "kCLLocationAccuracyKilometer"
iosOption.setDesiredAccuracy("kCLLocationAccuracyBest");
iosOption.setLocationTimeout(10); /// 可选,设置位置获取超时时间,参数为int类型
iosOption.setReGeocodeTimeout(10); /// 设置获取地址信息超时时间
iosOption.setDistanceFilter(100); /// 设置定位最小更新距离
iosOption.setAllowsBackgroundLocationUpdates(true); // 是否允许后台定位
iosOption.setPauseLocUpdateAutomatically(false); /// 定位是否会被系统自动暂停
iosOption.setDistanceFilter(10); /// 设置定位的最小更新距离,参数为double类型
Map iosMap = iosOption.getMap();
_locationPlugin.prepareLoc(androidMap, iosMap);
}
定位
Future<BaiduLocation?> location() async {
/// 动态申请定位权限
_locationPlugin.requestPermission();
Completer<BaiduLocation> completer = Completer();
///定位回调
_locationPlugin.onResultCallback().listen((Map<String, Object>? result) {
try {
/// 获取定位结果
BaiduLocation baiduLocation = BaiduLocation.fromMap(result);
///返回结果
completer.complete(baiduLocation);
} catch (e) {
print(e);
completer.completeError("location fail");
}
_stopLocation();
}).onError((e) {
completer.completeError("location fail");
});
_startLocation();
return completer.future;
}
/// 启动定位
void _startLocation() {
///设置定位参数
_setLocOption();
_locationPlugin.startLocation();
}
/// 停止定位
void _stopLocation() {
_locationPlugin.stopLocation();
}
使用
void location() async{
LocationService locationService = LocationService();
locationService.init();
BaiduLocation? location = await locationService.location();
print(""
"纬度 : ${location?.latitude} \n"
"经度 : ${location?.longitude} \n"
"地址 : ${location?.address}\n"
"位置语义化描述 : ${location?.locationDetail}\n"
"国家 : ${location?.country}\n"
"省份 : ${location?.province}\n"
"城市 : ${location?.city}\n"
"区县 : ${location?.district}\n"
"街道 : ${location?.street}\n"
"周边poi信息 : ${location?.poiList}\n"
);
}
分别在 Android 和 iOS 的设备上测试,输出结果如下:
//----------android-----------
纬度 : 39.91930
经度 : 116.4180582
地址 : addr = 北京市东城区王府井大街168号-6层
位置语义化描述 : 在东安市场附近
国家 : 中国
省份 : 北京市
城市 : 北京市
区县 : 东城区
街道 : 王府井大街
周边poi信息 : 东安市场,购物;购物中心,北京市东城区王府井大街138号|apm,购物;购物中心,北京市东城区王府井大街138号|王府井商业街,购物;其他,北京市东城区东长安街北侧|北京新中国儿童用品商店(王府井大街店),购物;购物中心,北京市东城区王府井大街138号|王府井百货办公大楼,房地产;写字楼,北京市东城区王府井大街255号
//------------iOS-------------
纬度 : 39.919304161081385
经度:116.41805829214785
地址 : addr = 110101 | 0 | 中国 | 北京市 | 131 | 东华门街道 | 王府井大街 | 168号-6层 | 东城区 | 北京市 | 在东安市场附近 |
位置语义化描述 : null
国家 : 中国
省份 : 北京市
城市 : 北京市
区县 : 东城区
街道 : 王府井大街
周边poi信息 : 东安市场,购物;购物中心,北京市东城区王府井大街138号|apm,购物;购物中心,北京市东城区王府井大街138号|王府井商业街,购物;其他,北京市东城区东长安街北侧|北京新中国儿童用品商店(王府井大街店),购物;购物中心,北京市东城区王府井大街138号|王府井百货办公大楼,房地产;写字楼,北京市东城区王府井大街255号
通过输出结果可以看到,在 Android 和 iOS 上都定位成功了,但是返回的数据结构有所区别:
- Android 的 addr 返回的是格式化的地址,iOS 返回的是国家省市区等用 | 分割的数据
- Android 有返回语义化描述字段
locationDetail, 而 iOS 没有该字段值
至此就完成了 Flutter 集成百度定位 SDK 的使用了。