第一次写这个东西!!有点激动和小紧张……
废话不多说了,开始进入正题,这篇文章的正题是实现Flutter百度地图的定位功能,因为目前(2019.7.16)还没有一篇文章可以很详细的说明白这个功能到底是怎么实现的,所以希望这篇文章可以帮到大家!
前提:
1、已经有Flutter开发环境
2、有想学习的心思~
开始操作:
一、百度地图官网下载定位功能API (⁎⁍̴̛ᴗ⁍̴̛⁎)传送门
小伙伴们可以自行选择下载示例代码学习!不过我在教程里就会跟大家分享有关知识的(◐‿◑)
二、创建一个FlutterPlugin文件
进行Flutter插件制作推荐使用AndroidStudio,VSCode做这个还是差点事~
三、将第一步下载得到的API解压后文件夹中的libs文件放到新建的插件文件夹根目录下android文件夹下
1、移动libs文件到新建的插件文件夹根目录下android文件夹下
2、将libs文件夹下jar包添加到库,具体操作如下:
在AndroidStudio中android/libs文件目录下BaiduLBS_Android.jar文件右键单击,点击弹出菜单中的Add As Library,在新弹出窗口直接点OK就OK🥳具体操作截图如下⬇️
四、将AndroidStudio从FLutter项目切换到专业Android模式
1、在插件项目名右键点击,按照下图依次点击进入专业Android模式
2、进入专业模式后,点击左上角将Android模式转换为Project模式
3、转换后文件结构如下:
五、整个项目的文件结构如下
六、文件代码及详解
1、FlutterPlugin
**package com.qwk.flutter_plugin;**
import android.app.Activity;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/** FlutterBaiduMapPlugin */
public class FlutterPluginimplements MethodCallHandler {
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel =new MethodChannel(registrar.messenger(), "baidumap");
channel.setMethodCallHandler(new FlutterPlugin(registrar.activity(),channel));
}
private Activityactivity;
private MethodChannelchannel;
private LocationClientmLocationClient =null;
private BDAbstractLocationListenermListener;
public LocationServicelocationService ;
public LocationActivitylocationActivity ;
public FlutterPlugin(Activity activity, MethodChannel channel) {
this.activity = activity;
this.channel = channel;
}
@Override
public void onMethodCall(MethodCall call, Result result) {
locationService =new LocationService(activity.getApplicationContext());
locationActivity=new LocationActivity(locationService,new CurrentLocationListener(result));
if (call.method.equals("getLocal")){
locationActivity.onStart();
}else {
result.notImplemented();
}
}
Maplocation2map(BDLocation location){
Map json =new HashMap<>();
json.put("latitude",location.getLatitude()); //获取纬度信息
json.put("longitude",location.getLongitude()); //获取经度信息
json.put("country",location.getCountry()); //获取国家
json.put("countryCode", location.getCountryCode());
json.put("province",location.getProvince()); //获取省份
json.put("city",location.getCity()); //获取城市
json.put("cityCode", location.getCityCode());
json.put("district",location.getDistrict()); //获取区县
json.put("street",location.getStreet()); //获取街道信息
json.put("locationDescribe",location.getLocationDescribe()); //获取位置描述信息
json.put("adCode",location.getAdCode()); //获取城市adcode
json.put("isInChina",location.getLocationWhere() == BDLocation.LOCATION_WHERE_IN_CN);
json.put("errorCode",location.getLocType());
//获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
return json;
}
/**
* 实现定位回调
*/
class CurrentLocationListenerextends BDAbstractLocationListener {
Resultresult;
CurrentLocationListener(Result result) {
this.result = result;
}
@Override
public synchronized void onReceiveLocation(BDLocation location) {
if (location ==null) {
return;
}
try {
if(result!=null){
result.success((location2map(location)));
}
}finally {
locationActivity.onStop();
result =null;
}
}
}
}
2、LocationActivity
package com.qwk.flutter_plugin;
import com.baidu.location.BDAbstractLocationListener;
/***
* 单点定位示例,用来展示基本的定位结果,配置在LocationService.java中
* 默认配置也可以在LocationService中修改
* 默认配置的内容自于开发者论坛中对开发者长期提出的疑问内容
*
* @author baidu
*
*/
public class LocationActivity {
private LocationService locationService;
private BDAbstractLocationListener mListener;
public LocationActivity(LocationService locationService, FlutterPlugin.CurrentLocationListener mListener) {
this.locationService = locationService;
this.mListener = mListener;
}
/***
* Stop location service
*/
public void onStop() {
locationService.unregisterListener(mListener); //注销掉监听
locationService.stop(); //停止定位服务
}
public void onStart() {
// -----------location config ------------
//获取locationservice实例,建议应用中只初始化1个location实例,然后使用,可以参考其他示例的activity,都是通过此种方式获取locationservice实例的
locationService.registerListener(mListener);
//注册监听
locationService.setLocationOption(locationService.getDefaultLocationClientOption());
locationService.start();
}
}
3、LocationService
package com.qwk.flutter_plugin;
import android.content.Context;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
/**
*
* @author baidu
*
*/
public class LocationService {
private LocationClient client = null;
private LocationClientOption mOption,DIYoption;
private Object objLock = new Object();
/***
*
* @param locationContext
*/
public LocationService(Context locationContext){
synchronized (objLock) {
if(client == null){
client = new LocationClient(locationContext);
client.setLocOption(getDefaultLocationClientOption());
}
}
}
/***
*
* @param listener
* @return
*/
public boolean registerListener(BDAbstractLocationListener listener){
boolean isSuccess = false;
if(listener != null){
client.registerLocationListener(listener);
isSuccess = true;
}
return isSuccess;
}
public void unregisterListener(BDAbstractLocationListener listener){
if(listener != null){
client.unRegisterLocationListener(listener);
}
}
/***
*
* @param option
* @return isSuccessSetOption
*/
public boolean setLocationOption(LocationClientOption option){
boolean isSuccess = false;
if(option != null){
if(client.isStarted())
client.stop();
DIYoption = option;
client.setLocOption(option);
}
return isSuccess;
}
/***
*
* @return DefaultLocationClientOption 默认O设置
*/
public LocationClientOption getDefaultLocationClientOption(){
if(mOption == null){
mOption = new LocationClientOption();
mOption.setLocationMode(LocationMode.Hight_Accuracy);//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
mOption.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll;
mOption.setScanSpan(3000);//可选,默认0,即仅定位一次,设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
mOption.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
mOption.setIsNeedLocationDescribe(true);//可选,设置是否需要地址描述
mOption.setNeedDeviceDirect(false);//可选,设置是否需要设备方向结果
mOption.setLocationNotify(false);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
mOption.setIgnoreKillProcess(true);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
mOption.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
mOption.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
mOption.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集
mOption.setOpenGps(true);//可选,默认false,设置是否开启Gps定位
mOption.setIsNeedAltitude(false);//可选,默认false,设置定位时是否需要海拔信息,默认不需要,除基础定位版本都可用
}
return mOption;
}
/**
*
* @return DIYOption 自定义Option设置
*/
public LocationClientOption getOption(){
if(DIYoption == null) {
DIYoption = new LocationClientOption();
}
return DIYoption;
}
public void start(){
synchronized (objLock) {
if(client != null && !client.isStarted()){
client.start();
}
}
}
public void stop(){
synchronized (objLock) {
if(client != null && client.isStarted()){
client.stop();
}
}
}
public boolean isStart() {
return client.isStarted();
}
public boolean requestHotSpotState(){
return client.requestHotSpotState();
}
}
七、插件根目录下lib文件夹下文件结构
八、插件根目录下lib文件夹下文件代码示例
1、BaiduLocation.dart
class BaiduLocation{
final double latitude;
final double longitude;
final String country;
final String countryCode;
final String province;
final String cityCode;
final String city;
final String district;
final String street;
final String locationDescribe;
final String adCode;
final int errorCode;
final bool isInChina;
BaiduLocation({this.latitude, this.longitude,
this.country, this.countryCode, this.province,
this.cityCode, this.city, this.district, this.street,
this.locationDescribe,this.adCode,this.errorCode,this.isInChina});
factory BaiduLocation.fromMap(dynamic value){
return new BaiduLocation(
latitude: value['latitude'],
longitude:value['longitude'],
country:value['country'],
countryCode:value['countryCode'],
province: value['province'],
cityCode: value['cityCode'],
city: value['city'],
district : value['district'],
street:value['street'],
locationDescribe:value['locationDescribe'],
adCode:value['adCode'],
errorCode:value['errorCode'],
isInChina:value['isInChina']
);
}
bool isSuccess() {
return errorCode == 161;
}
Map getMap() {
return {
"latitude": latitude,
"longitude":longitude,
"country":country,
"countryCode":countryCode,
"province": province,
"cityCode": cityCode,
"city": city,
"district" : district,
"street":street,
"locationDescribe":locationDescribe,
"adCode":adCode,
"errorCode":errorCode,
"isInChina":isInChina
};
}
}
2 、flutter_plugin.dart
我的插件名为flutter_plugin,如果你建立的插件名不一样的话那就用你自己的名字就可以。
import 'dart:async';
import 'package:flutter/services.dart';
import 'baiduLocation.dart';
class QwkBaidumap {
static const MethodChannel _channel = const MethodChannel('baidumap');
static Future<BaiduLocation> get local async {
final BaiduLocation version =
BaiduLocation.fromMap(await _channel.invokeMethod('getLocal'));
// return "X:${version.latitude.toString()} , Y:${version.longitude.toString()}";
return version;
}
}
九、在根目录下example文件夹下lib目录下main.dart中修改示例代码
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_plugin/flutter_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
@override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterPlugin.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
),
);
}
}
十、修改AndroidManifest.xml
修改根目录flutter_plugin/android/src/main/AndroidManifest.xml文件,修改后代码如下,需要注意的是将代码倒数第三行中间内容修改为你自己的百度AK。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qwk.flutter_plugin">
<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 读取系统信息,包含系统版本等信息,用作统计-->
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<!-- 程序在手机屏幕关闭后后台进程仍然运行-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application>
<!-- 声明service组件 -->
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
<!-- AK鉴权 -->
<!-- meta-data需要写在application中 -->
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="修改为你的百度AK" />
</application>
</manifest>
十一、总结
整体的代码就是以上这些,希望能够帮助到大家,有不足的地方请大神即使指正,请大家随意喷我哈,🤒第一次写经验不是很丰富,如果大家有什么不懂的地方大家可以➕我扣扣(1608066610)私聊我就行,希望能够多多交流哦~
两句废话👇
在Flutter学习过程中我们会遇到各种各样的问题👅
多个朋友多条路,让我们愉快的一起玩耍吧!👀
有什么问题欢迎跟我讨论哦~
喜欢交朋友的我的二维码奉上🙆♂️