美文网首页《人生感悟ABC》Flutter圈子Flutter中文社区
Flutter百度地图插件开源实现(一)定位功能

Flutter百度地图插件开源实现(一)定位功能

作者: 乔悟空 | 来源:发表于2019-07-17 10:04 被阅读172次
        第一次写这个东西!!有点激动和小紧张……
    
        废话不多说了,开始进入正题,这篇文章的正题是实现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<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百度地图插件开源实现(一)定位功能

        本文链接:https://www.haomeiwen.com/subject/eywflctx.html