【乔悟空】Flutter百度地图插件开源实现(一)定位功能

    第一次写这个东西!!有点激动和小紧张……

    废话不多说了,开始进入正题,这篇文章的正题是实现Flutter百度地图的定位功能,因为目前(2019.7.16)还没有一篇文章可以很详细的说明白这个功能到底是怎么实现的,所以希望这篇文章可以帮到大家!

前提:

1、已经有Flutter开发环境

2、有想学习的心思~

开始操作:

一、百度地图官网下载定位功能API (⁎⁍̴̛ᴗ⁍̴̛⁎)传送门

image

小伙伴们可以自行选择下载示例代码学习!不过我在教程里就会跟大家分享有关知识的(◐‿◑)

二、创建一个FlutterPlugin文件

进行Flutter插件制作推荐使用AndroidStudio,VSCode做这个还是差点事~

三、将第一步下载得到的API解压后文件夹中的libs文件放到新建的插件文件夹根目录下android文件夹下

1、移动libs文件到新建的插件文件夹根目录下android文件夹下

image
image
image

2、将libs文件夹下jar包添加到库,具体操作如下:

在AndroidStudio中android/libs文件目录下BaiduLBS_Android.jar文件右键单击,点击弹出菜单中的Add As Library,在新弹出窗口直接点OK就OK具体操作截图如下⬇️

image

四、将AndroidStudio从FLutter项目切换到专业Android模式

1、在插件项目名右键点击,按照下图依次点击进入专业Android模式

image

2、进入专业模式后,点击左上角将Android模式转换为Project模式

image

3、转换后文件结构如下:

image

五、整个项目的文件结构如下

image

六、文件代码及详解
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文件夹下文件结构

dart端文件结构.png

八、插件根目录下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 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 {
  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future 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。


    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    
    
    
    
    
        
        
        
        
        
        
    


十一、总结
整体的代码就是以上这些,希望能够帮助到大家,有不足的地方请大神即使指正,请大家随意喷我哈,第一次写经验不是很丰富,如果大家有什么不懂的地方大家可以➕我扣扣(1608066610)私聊我就行,希望能够多多交流哦~

两句废话

在Flutter学习过程中我们会遇到各种各样的问题
多个朋友多条路,让我们愉快的一起玩耍吧!
有什么问题欢迎跟我讨论哦~
喜欢交朋友的我的二维码奉上‍♂️


乔悟空

你可能感兴趣的:(【乔悟空】Flutter百度地图插件开源实现(一)定位功能)