Flutter 混合开发 - 02 百度地图定位功能 android 篇_第1张图片

本节目标

  • 百度地图业务
  • 百度组件初始
  • 编写定位代码 android 篇

Flutter 混合开发 - 02 百度地图定位功能 android 篇_第2张图片

环境

$ flutter doctorDoctor summary (to see all details, run flutter doctor -v):[✓] Flutter (Channel stable, 1.20.1, on Mac OS X 10.15.6 19G73, locale zh-Hans-CN)[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)[✓] Xcode - develop for iOS and macOS (Xcode 11.6)[✓] Android Studio (version 4.0)[✓] VS Code (version 1.47.3)

视频

https://www.bilibili.com/vide...

代码

https://github.com/ducafecat/...

可以直接用 v1.0.3

https://github.com/ducafecat/...

正文

创建组件的几种方式

现成轮子直接用

  • 官方仓库搜索

    https://pub.dev/flutter/packages

    https://pub.flutter-io.cn/flu...

可参考的组件代码

  • 通过仓库,查找 github 代码仓
  • 网站、客服索取代码

参考官方集成文档编写组件

  • 官网文档

http://lbsyun.baidu.com/index...

组件代码

百度应用管理,创建 AK

  • 应用管理

https://lbsyun.baidu.com/apic...

Flutter 混合开发 - 02 百度地图定位功能 android 篇_第3张图片

  • 查询 SHA1

http://lbsyun.baidu.com/index...

Flutter 混合开发 - 02 百度地图定位功能 android 篇_第4张图片

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey
  • 设置 AK

example/android/app/src/main/AndroidManifest.xml

...                    

设置 Android 权限

  • 文档

http://lbsyun.baidu.com/index...

  • android/src/main/AndroidManifest.xml
                                                                                                                

添加 android libs 库文件

  • 目录 android/libs

Flutter 混合开发 - 02 百度地图定位功能 android 篇_第5张图片

  • android/build.gradle
...android {    compileSdkVersion 28    sourceSets {        main {            jniLibs.srcDir 'libs'        }    }    defaultConfig {        minSdkVersion 16    }    lintOptions {        disable 'InvalidPackage'    }}dependencies {    implementation files('libs/BaiduLBS_Android.jar')}

编写 Flutter 组件代码

  • 目录 lib

Flutter 混合开发 - 02 百度地图定位功能 android 篇_第6张图片

  • 地理信息 lib/entity/flutter_baidu_location.dart
/// 百度定位结果类,用于存储各类定位结果信息class BaiduLocation {  /// 定位成功时间  final String locTime;  /// 定位结果类型  final int locType;  /// 半径  final double radius;  /// 纬度  final double latitude;  /// 经度  final double longitude;  /// 海拔  final double altitude;  /// 国家  final String country;  /// 省份  final String province;  /// 城市  final String city;  /// 区县  final String district;  /// 街道  final String street;  /// 地址  final String address;  /// 位置语义化描述,例如"在百度大厦附近"  final String locationDetail;  /// 周边poi信息,每个poi之间用"|"隔开  final String poiList;  /// 定位结果回调时间  final String callbackTime;  /// 错误码  final int errorCode;  /// 定位失败描述信息  final String errorInfo;  BaiduLocation(      {this.locTime,      this.locType,      this.radius,      this.latitude,      this.longitude,      this.altitude,      this.country,      this.province,      this.city,      this.district,      this.street,      this.address,      this.locationDetail,      this.poiList,      this.callbackTime,      this.errorCode,      this.errorInfo});  /// 根据传入的map生成BaiduLocation对象  factory BaiduLocation.fromMap(dynamic value) {    return new BaiduLocation(      locTime: value['locTime'],      locType: value['locType'],      radius: value['radius'],      latitude: value['latitude'],      longitude: value['longitude'],      altitude: value['altitude'],      country: value['country'],      province: value['province'],      city: value['city'],      district: value['district'],      street: value['street'],      address: value['address'],      locationDetail: value['locationDetail'],      poiList: value['poiList'],      callbackTime: value['callbackTime'],      errorCode: value['errorCode'],      errorInfo: value['errorInfo'],    );  }  /// 获取对本类所有变量赋值后的map键值对  Map getMap() {    return {      "locTime": locTime,      "locType": locType,      "radius": radius,      "latitude": latitude,      "longitude": longitude,      "altitude": altitude,      "country": country,      "province": province,      "city": city,      "district": district,      "street": street,      "address": address,      "locationDescribe": locationDetail,      "poiList": poiList,      "callbackTime": callbackTime,      "errorCode": errorCode,      "errorInfo": errorInfo,    };  }}
  • android 配置项 lib/entity/flutter_baidu_location_android_option.dart
/// 设置android端定位参数类class BaiduLocationAndroidOption {  /// 坐标系类型  String coorType;  /// 是否需要返回地址信息  bool isNeedAddres;  /// 是否需要返回海拔高度信息  bool isNeedAltitude;  /// 是否需要返回周边poi信息  bool isNeedLocationPoiList;  /// 是否需要返回新版本rgc信息  bool isNeedNewVersionRgc;  /// 是否需要返回位置描述信息  bool isNeedLocationDescribe;  /// 是否使用gps  bool openGps;  /// 可选,设置发起定位请求的间隔,int类型,单位ms  /// 如果设置为0,则代表单次定位,即仅定位一次,默认为0  /// 如果设置非0,需设置1000ms以上才有效  int scanspan;  /// 设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式  int locationMode;  /// 可选,设置场景定位参数,包括签到场景、运动场景、出行场景  int locationPurpose;  /// 可选,设置返回经纬度坐标类型,默认GCJ02  /// GCJ02:国测局坐标;  /// BD09ll:百度经纬度坐标;  /// BD09:百度墨卡托坐标;  /// 海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标  void setCoorType(String coorType) {    this.coorType = coorType;  }  /// 是否需要返回地址信息  void setIsNeedAddres(bool isNeedAddres) {    this.isNeedAddres = isNeedAddres;  }  /// 是否需要返回海拔高度信息  void setIsNeedAltitude(bool isNeedAltitude) {    this.isNeedAltitude = isNeedAltitude;  }  /// 是否需要返回周边poi信息  void setIsNeedLocationPoiList(bool isNeedLocationPoiList) {    this.isNeedLocationPoiList = isNeedLocationPoiList;  }  /// 是否需要返回位置描述信息  void setIsNeedLocationDescribe(bool isNeedLocationDescribe) {    this.isNeedLocationDescribe = isNeedLocationDescribe;  }  /// 是否需要返回新版本rgc信息  void setIsNeedNewVersionRgc(bool isNeedNewVersionRgc) {    this.isNeedNewVersionRgc = isNeedNewVersionRgc;  }  /// 是否使用gps  void setOpenGps(bool openGps) {    this.openGps = openGps;  }  /// 可选,设置发起定位请求的间隔,int类型,单位ms  /// 如果设置为0,则代表单次定位,即仅定位一次,默认为0  /// 如果设置非0,需设置1000ms以上才有效  void setScanspan(int scanspan) {    this.scanspan = scanspan;  }  /// 设置定位模式,可选的模式有高精度、仅设备、仅网络,默认为高精度模式  void setLocationMode(LocationMode locationMode) {    if (locationMode == LocationMode.Hight_Accuracy) {      this.locationMode = 1;    } else if (locationMode == LocationMode.Device_Sensors) {      this.locationMode = 2;    } else if (locationMode == LocationMode.Battery_Saving) {      this.locationMode = 3;    }  }  /// 可选,设置场景定位参数,包括签到场景、运动场景、出行场景  void setLocationPurpose(BDLocationPurpose locationPurpose) {    if (locationPurpose == BDLocationPurpose.SignIn) {      this.locationPurpose = 1;    } else if (locationPurpose == BDLocationPurpose.Transport) {      this.locationPurpose = 2;    } else if (locationPurpose == BDLocationPurpose.Sport) {      this.locationPurpose = 3;    }  }  BaiduLocationAndroidOption(      {this.coorType,      this.isNeedAddres,      this.isNeedAltitude,      this.isNeedLocationPoiList,      this.isNeedNewVersionRgc,      this.openGps,      this.isNeedLocationDescribe,      this.scanspan,      this.locationMode,      this.locationPurpose});  /// 根据传入的map生成BaiduLocationAndroidOption对象  factory BaiduLocationAndroidOption.fromMap(dynamic value) {    return new BaiduLocationAndroidOption(      coorType: value['coorType'],      isNeedAddres: value['isNeedAddres'],      isNeedAltitude: value['isNeedAltitude'],      isNeedLocationPoiList: value['isNeedLocationPoiList'],      isNeedNewVersionRgc: value['isNeedNewVersionRgc'],      openGps: value['openGps'],      isNeedLocationDescribe: value[''],      scanspan: value['scanspan'],      locationMode: value['locationMode'],      locationPurpose: value['LocationPurpose'],    );  }  /// 获取对本类所有变量赋值后的map键值对  Map getMap() {    return {      "coorType": coorType,      "isNeedAddres": isNeedAddres,      "isNeedAltitude": isNeedAltitude,      "isNeedLocationPoiList": isNeedLocationPoiList,      "isNeedNewVersionRgc": isNeedNewVersionRgc,      "openGps": openGps,      "isNeedLocationDescribe": isNeedLocationDescribe,      "scanspan": scanspan,      "locationMode": locationMode,    };  }}/// 定位模式枚举类enum LocationMode {  /// 高精度模式  Hight_Accuracy,  /// 低功耗模式  Battery_Saving,  /// 仅设备(Gps)模式  Device_Sensors}/// 场景定位枚举类enum BDLocationPurpose {  ///  签到场景  /// 只进行一次定位返回最接近真实位置的定位结果(定位速度可能会延迟1-3s)  SignIn,  /// 出行场景  /// 高精度连续定位,适用于有户内外切换的场景,卫星定位和网络定位相互切换,卫星定位成功之后网络定位不再返回,卫星信号断开之后一段时间才会返回网络结果  Sport,  /// 运动场景  /// 高精度连续定位,适用于有户内外切换的场景,卫星定位和网络定位相互切换,卫星定位成功之后网络定位不再返回,卫星信号断开之后一段时间才会返回网络结果  Transport}
  • ios 配置项 lib/entity/flutter_baidu_location_ios_option.dart
/// 设置ios端定位参数类class BaiduLocationIOSOption {  /// 设置位置获取超时时间  int locationTimeout;  /// 设置获取地址信息超时时间  int reGeocodeTimeout;  /// 设置应用位置类型  String activityType;  /// 设置返回位置的坐标系类型  String BMKLocationCoordinateType;  /// 设置预期精度参数  String desiredAccuracy;  /// 是否需要最新版本rgc数据  bool isNeedNewVersionRgc;  /// 指定定位是否会被系统自动暂停  bool pausesLocationUpdatesAutomatically;  /// 指定是否允许后台定位  bool allowsBackgroundLocationUpdates;  /// 设定定位的最小更新距离  double distanceFilter;  /// 指定是否允许后台定位  /// allowsBackgroundLocationUpdates为true则允许后台定位  /// allowsBackgroundLocationUpdates为false则不允许后台定位  void setAllowsBackgroundLocationUpdates(      bool allowsBackgroundLocationUpdates) {    this.allowsBackgroundLocationUpdates = allowsBackgroundLocationUpdates;  }  /// 指定定位是否会被系统自动暂停  /// pausesLocationUpdatesAutomatically为true则定位会被系统自动暂停  /// pausesLocationUpdatesAutomatically为false则定位不会被系统自动暂停  void setPauseLocUpdateAutomatically(bool pausesLocationUpdatesAutomatically) {    this.pausesLocationUpdatesAutomatically =        pausesLocationUpdatesAutomatically;  }  /// 设置位置获取超时时间  void setLocationTimeout(int locationTimeout) {    this.locationTimeout = locationTimeout;  }  /// 设置获取地址信息超时时间  void setReGeocodeTimeout(int reGeocodeTimeout) {    this.reGeocodeTimeout = reGeocodeTimeout;  }  /// 设置应用位置类型  /// activityType可选值包括:  /// "CLActivityTypeOther"  /// "CLActivityTypeAutomotiveNavigation"  /// "CLActivityTypeFitness"  /// "CLActivityTypeOtherNavigation"  void setActivityType(String activityType) {    this.activityType = activityType;  }  /// 设置返回位置的坐标系类型  /// BMKLocationCoordinateType可选值包括:  /// "BMKLocationCoordinateTypeBMK09LL"  /// "BMKLocationCoordinateTypeBMK09MC"  /// "BMKLocationCoordinateTypeWGS84"  /// "BMKLocationCoordinateTypeGCJ02"  void setBMKLocationCoordinateType(String BMKLocationCoordinateType) {    this.BMKLocationCoordinateType = BMKLocationCoordinateType;  }  /// 设置预期精度参数  /// desiredAccuracy可选值包括:  /// "kCLLocationAccuracyBest"  /// "kCLLocationAccuracyNearestTenMeters"  /// "kCLLocationAccuracyHundredMeters"  /// "kCLLocationAccuracyKilometer"  void setDesiredAccuracy(String desiredAccuracy) {    this.desiredAccuracy = desiredAccuracy;  }  /// 设定定位的最小更新距离  void setDistanceFilter(double distanceFilter) {    this.distanceFilter = distanceFilter;  }  /// 是否需要最新版本rgc数据  /// isNeedNewVersionRgc为true则需要返回最新版本rgc数据  /// isNeedNewVersionRgc为false则不需要返回最新版本rgc数据  void setIsNeedNewVersionRgc(bool isNeedNewVersionRgc) {    this.isNeedNewVersionRgc = isNeedNewVersionRgc;  }  BaiduLocationIOSOption(      {this.locationTimeout,      this.reGeocodeTimeout,      this.activityType,      this.BMKLocationCoordinateType,      this.desiredAccuracy,      this.isNeedNewVersionRgc,      this.pausesLocationUpdatesAutomatically,      this.allowsBackgroundLocationUpdates,      this.distanceFilter});  /// 根据传入的map生成BaiduLocationIOSOption对象  factory BaiduLocationIOSOption.fromMap(dynamic value) {    return new BaiduLocationIOSOption(      locationTimeout: value['locationTimeout'],      reGeocodeTimeout: value['reGeocodeTimeout'],      activityType: value['activityType'],      BMKLocationCoordinateType: value['BMKLocationCoordinateType'],      desiredAccuracy: value['desiredAccuracy'],      isNeedNewVersionRgc: value['isNeedNewVersionRgc'],      pausesLocationUpdatesAutomatically:          value['pausesLocationUpdatesAutomatically'],      allowsBackgroundLocationUpdates: value['allowsBackgroundLocationUpdates'],      distanceFilter: value['distanceFilter'],    );  }  /// 获取对本类所有变量赋值后的map键值对  Map getMap() {    return {      "locationTimeout": locationTimeout,      "reGeocodeTimeout": reGeocodeTimeout,      "activityType": activityType,      "BMKLocationCoordinateType": BMKLocationCoordinateType,      "desiredAccuracy": desiredAccuracy,      "isNeedNewVersionRgc": isNeedNewVersionRgc,      "pausesLocationUpdatesAutomatically": pausesLocationUpdatesAutomatically,      "allowsBackgroundLocationUpdates": allowsBackgroundLocationUpdates,      "distanceFilter": distanceFilter,    };  }}
  • 接口 lib/flutter_baidu_plugin_ducafecat.dart
import 'dart:async';import 'dart:io';import 'package:flutter/services.dart';class FlutterBaiduPluginDucafecat {  /// flutter端主动调用原生端方法  static const MethodChannel _channel =      const MethodChannel('flutter_baidu_plugin_ducafecat');  /// 原生端主动回传结果数据到flutter端  static const EventChannel _stream =      const EventChannel("flutter_baidu_plugin_ducafecat_stream");  /// ios 下设置 key  /// android 在 AndroidManifest.xml 中设置  static Future setApiKey(String key) async {    return await _channel.invokeMethod("setApiKey", key);  }  /// 设置定位参数  void prepareLoc(Map androidMap, Map iosMap) {    Map map;    if (Platform.isAndroid) {      map = androidMap;    } else {      map = iosMap;    }    _channel.invokeMethod("updateOption", map);    return;  }  /// 启动定位  void startLocation() {    _channel.invokeMethod('startLocation');    return;  }  /// 停止定位  void stopLocation() {    _channel.invokeMethod('stopLocation');    return;  }  /// 原生端回传键值对map到flutter端  /// map中key为isInChina对应的value,如果为1则判断是在国内,为0则判断是在国外  /// map中存在key为nearby则判断为已到达设置监听位置附近  Stream> onResultCallback() {    Stream> _resultMap;    if (_resultMap == null) {      _resultMap = _stream.receiveBroadcastStream().map>(          (element) => element.cast());    }    return _resultMap;  }}

触发 registerWith 的方式,老项目

// This static function is optional and equivalent to onAttachedToEngine. It supports the old
// pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
// plugin registration via this function while apps migrate to use the new Android APIs
// post-flutter-1.12 via https://flutter.dev/go/androi...
  • android 组件代码

android/src/main/java/tech/ducafecat/flutter_baidu_plugin_ducafecat/FlutterBaiduPluginDucafecatPlugin.java

  public static void registerWith(Registrar registrar) {    ......  }
  • example android 注册组件

example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java

public final class GeneratedPluginRegistrant {  public static void registerWith(PluginRegistry registry) {    if (alreadyRegisteredWith(registry)) {      return;    }    LocationFlutterPlugin.registerWith(registry.registrarFor("com.baidu.bdmap_location_flutter_plugin.LocationFlutterPlugin"));    PermissionHandlerPlugin.registerWith(registry.registrarFor("com.baseflow.permissionhandler.PermissionHandlerPlugin"));  }  private static boolean alreadyRegisteredWith(PluginRegistry registry) {    final String key = GeneratedPluginRegistrant.class.getCanonicalName();    if (registry.hasPlugin(key)) {      return true;    }    registry.registrarFor(key);    return false;  }}

成员变量、同步、异步处理

MethodChannel 请求方法后,同步返回结果

EventChannel 组件主动推消息到 Flutter

  • android/src/main/java/tech/ducafecat/flutter_baidu_plugin_ducafecat/FlutterBaiduPluginDucafecatPlugin.java

用到的成员变量先定义下

public class FlutterBaiduPluginDucafecatPlugin implements FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler {  // 通道名称  private static final String CHANNEL_METHOD_LOCATION = "flutter_baidu_plugin_ducafecat";  private static final String CHANNEL_STREAM_LOCATION = "flutter_baidu_plugin_ducafecat_stream";  private Context mContext = null; // flutter view context  private LocationClient mLocationClient = null; // 定位对象  private EventChannel.EventSink mEventSink = null; // 事件对象  private BDNotifyListener mNotifyListener; // 位置提醒对象  private boolean isPurporseLoc = false; // 签到场景  private boolean isInChina = false;  // 是否启用国内外位置判断功能  private boolean isNotify = false; // 位置提醒  // 通道对象  private MethodChannel channel = null;  private EventChannel eventChannel = null;

组件生命周期

  • 文件

android/src/main/java/tech/ducafecat/flutter_baidu_plugin_ducafecat/FlutterBaiduPluginDucafecatPlugin.java

  • 组件注册 onAttachedToEngine
  @Override  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {    this.mContext = flutterPluginBinding.getApplicationContext();    /**     * 开始、停止定位     */    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL_METHOD_LOCATION);    channel.setMethodCallHandler(this);    /**     * 监听位置变化     */    eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL_STREAM_LOCATION);    eventChannel.setStreamHandler(this);  }
  • 老项目 组件注册 registerWith
  public static void registerWith(Registrar registrar) {    FlutterBaiduPluginDucafecatPlugin plugin = new FlutterBaiduPluginDucafecatPlugin();    plugin.mContext = registrar.context();    /**     * 开始、停止定位     */    final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_METHOD_LOCATION);    channel.setMethodCallHandler(plugin);    /**     * 监听位置变化     */    final EventChannel eventChannel = new EventChannel(registrar.messenger(), CHANNEL_STREAM_LOCATION);    eventChannel.setStreamHandler(plugin);//    final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_baidu_plugin_ducafecat");//    channel.setMethodCallHandler(new FlutterBaiduPluginDucafecatPlugin());  }
  • 注销组件 onCancel
  @Override  public void onCancel(Object arguments) {    stopLocation();    if (isNotify) {      if (null != mLocationClient) {        mLocationClient.removeNotifyEvent(mNotifyListener);      }      mNotifyListener = null;    }  }
  • 销毁组件 onDetachedFromEngine
  @Override  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {    channel.setMethodCallHandler(null);    eventChannel.setStreamHandler(null);  }
  • 方法调用 onMethodCall
  @Override  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {    if ("startLocation".equals(call.method)) {      startLocation(); // 启动定位    } else if ("stopLocation".equals(call.method)) {      stopLocation(); // 停止定位    } else if("updateOption".equals(call.method)) { // 设置定位参数      try {        updateOption((Map) call.arguments);      } catch (Exception e) {        e.printStackTrace();      }    } else if (("getPlatformVersion").equals(call.method)) {      result.success("Android " + android.os.Build.VERSION.RELEASE);    } else {      result.notImplemented();    }  }
  • flutter onListen 回调对象
  @Override  public void onListen(Object arguments, EventChannel.EventSink events) {    mEventSink = events;  }

地图业务参数

  • 更新参数 updateOption
  /**   * 准备定位   * @param arguments   */  private void updateOption(Map arguments) {    if (null == mLocationClient) {      mLocationClient = new LocationClient(mContext);    }    // 判断是否启用位置提醒功能    if (arguments.containsKey("isNotify")) {      isNotify = true;      if (null == mNotifyListener) {        mNotifyListener = new MyNotifyLister();      }      mLocationClient.registerNotify(mNotifyListener);      double lat = 0;      double lon = 0;      float radius = 0;      if (arguments.containsKey("latitude")) {        lat = (double)arguments.get("latitude");      }      if (arguments.containsKey("longitude")) {        lon = (double)arguments.get("longitude");      }      if (arguments.containsKey("radius")) {        double radius1 = (double)arguments.get("radius");        radius = Float.parseFloat(String.valueOf(radius1));      }      String coorType = mLocationClient.getLocOption().getCoorType();      mNotifyListener.SetNotifyLocation(lat, lon, radius, coorType);      return;    } else {      isNotify = false;    }    mLocationClient.registerLocationListener(new CurrentLocationListener());    // 判断是否启用国内外位置判断功能    if (arguments.containsKey("isInChina")) {      isInChina = true;      return;    } else {      isInChina =false;    }    LocationClientOption option = new LocationClientOption();    parseOptions(option, arguments);    option.setProdName("flutter");    mLocationClient.setLocOption(option);  }
  • 解析定位参数 parseOptions
  /**   * 解析定位参数   * @param option   * @param arguments   */  private void parseOptions(LocationClientOption option,Map arguments) {    if (arguments != null) {      // 可选,设置是否返回逆地理地址信息。默认是true      if (arguments.containsKey("isNeedAddres")) {        if (((boolean)arguments.get("isNeedAddres"))) {          option.setIsNeedAddress(true);        } else {          option.setIsNeedAddress(false);        }      }      // 可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式      if (arguments.containsKey("locationMode")) {        if (((int)arguments.get("locationMode")) == 1) {          option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy); // 高精度模式        } else if (((int)arguments.get("locationMode")) == 2) {          option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors); // 仅设备模式        } else if (((int)arguments.get("locationMode")) == 3) {          option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving); // 仅网络模式        }      }      // 可选,设置场景定位参数,包括签到场景、运动场景、出行场景      if ((arguments.containsKey("LocationPurpose"))) {        isPurporseLoc = true;        if  (((int)arguments.get("LocationPurpose")) == 1) {          option.setLocationPurpose(LocationClientOption.BDLocationPurpose.SignIn); // 签到场景        } else if (((int)arguments.get("LocationPurpose")) == 2) {          option.setLocationPurpose(LocationClientOption.BDLocationPurpose.Transport); // 运动场景        } else if (((int)arguments.get("LocationPurpose")) == 3) {          option.setLocationPurpose(LocationClientOption.BDLocationPurpose.Sport); // 出行场景        }      } else {        isPurporseLoc = false;      }      // 可选,设置需要返回海拔高度信息      if (arguments.containsKey("isNeedAltitude")) {        if (((boolean)arguments.get("isNeedAltitude"))) {          option.setIsNeedAddress(true);        } else {          option.setIsNeedAltitude(false);        }      }      // 可选,设置是否使用gps,默认false      if (arguments.containsKey("openGps")) {        if(((boolean)arguments.get("openGps"))) {          option.setOpenGps(true);        } else {          option.setOpenGps(false);        }      }      // 可选,设置是否允许返回逆地理地址信息,默认是true      if (arguments.containsKey("isNeedLocationDescribe")) {        if(((boolean)arguments.get("isNeedLocationDescribe"))) {          option.setIsNeedLocationDescribe(true);        } else {          option.setIsNeedLocationDescribe(false);        }      }      // 可选,设置发起定位请求的间隔,int类型,单位ms      // 如果设置为0,则代表单次定位,即仅定位一次,默认为0      // 如果设置非0,需设置1000ms以上才有效      if (arguments.containsKey("scanspan")) {        option.setScanSpan((int)arguments.get("scanspan"));      }      // 可选,设置返回经纬度坐标类型,默认GCJ02      // GCJ02:国测局坐标;      // BD09ll:百度经纬度坐标;      // BD09:百度墨卡托坐标;      // 海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标      if (arguments.containsKey("coorType")) {        option.setCoorType((String)arguments.get("coorType"));      }      // 设置是否需要返回附近的poi列表      if (arguments.containsKey("isNeedLocationPoiList")) {        if (((boolean)arguments.get("isNeedLocationPoiList"))) {          option.setIsNeedLocationPoiList(true);        } else {          option.setIsNeedLocationPoiList(false);        }      }      // 设置是否需要最新版本rgc数据      if (arguments.containsKey("isNeedNewVersionRgc")) {        if (((boolean)arguments.get("isNeedNewVersionRgc"))) {          option.setIsNeedLocationPoiList(true);        } else {          option.setIsNeedLocationPoiList(false);        }      }    }  }

编写启动、停止功能

  • 开始定位
  private void startLocation() {    if(null != mLocationClient) {      mLocationClient.start();    }  }
  • 停止定位
  private void stopLocation() {    if (null != mLocationClient) {      mLocationClient.stop();      mLocationClient = null;    }  }

百度定位回调

  • CurrentLocationListener
  /**   * 格式化时间   *   * @param time   * @param strPattern   * @return   */  private String formatUTC(long time, String strPattern) {    if (TextUtils.isEmpty(strPattern)) {      strPattern = "yyyy-MM-dd HH:mm:ss";    }    SimpleDateFormat sdf = null;    try {      sdf = new SimpleDateFormat(strPattern, Locale.CHINA);      sdf.applyPattern(strPattern);    } catch (Throwable e) {      e.printStackTrace();    }    return sdf == null ? "NULL" : sdf.format(time);  }  class CurrentLocationListener extends BDAbstractLocationListener {    @Override    public void onReceiveLocation(BDLocation bdLocation) {      if (null == mEventSink) {        return;      }      Map result = new LinkedHashMap<>();      // 判断国内外获取结果      if (isInChina) {        if (bdLocation.getLocationWhere() == BDLocation.LOCATION_WHERE_IN_CN) {          result.put("isInChina", 1); // 在国内        } else {          result.put("isInChina", 0); // 在国外        }        mEventSink.success(result);        return;      }      // 场景定位获取结果      if (isPurporseLoc) {        result.put("latitude", bdLocation.getLatitude()); // 纬度        result.put("longitude", bdLocation.getLongitude()); // 经度        mEventSink.success(result);        return;      }      result.put("callbackTime", formatUTC(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"));      if (null != bdLocation) {        if (bdLocation.getLocType() == BDLocation.TypeGpsLocation                || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation                || bdLocation.getLocType() == BDLocation.TypeOffLineLocation) {          result.put("locType", bdLocation.getLocType()); // 定位结果类型          result.put("locTime", bdLocation.getTime()); // 定位成功时间          result.put("latitude", bdLocation.getLatitude()); // 纬度          result.put("longitude", bdLocation.getLongitude()); // 经度          if (bdLocation.hasAltitude()) {            result.put("altitude", bdLocation.getAltitude()); // 高度          }          result.put("radius", Double.parseDouble(String.valueOf(bdLocation.getRadius()))); // 定位精度          result.put("country", bdLocation.getCountry()); // 国家          result.put("province", bdLocation.getProvince()); // 省份          result.put("city", bdLocation.getCity()); // 城市          result.put("district", bdLocation.getDistrict()); // 区域          result.put("town", bdLocation.getTown()); // 城镇          result.put("street", bdLocation.getStreet()); // 街道          result.put("address", bdLocation.getAddrStr()); // 地址          result.put("locationDetail", bdLocation.getLocationDescribe()); // 位置语义化描述          if (null != bdLocation.getPoiList() && !bdLocation.getPoiList().isEmpty()) {            List pois = bdLocation.getPoiList();            StringBuilder stringBuilder = new StringBuilder();            if (pois.size() == 1) {              stringBuilder.append(pois.get(0).getName()).append(",").append(pois.get(0).getTags())                      .append(pois.get(0).getAddr());            } else {              for (int i = 0; i < pois.size() - 1; i++) {                stringBuilder.append(pois.get(i).getName()).append(",").append(pois.get(i).getTags())                        .append(pois.get(i).getAddr()).append("|");              }              stringBuilder.append(pois.get(pois.size()-1).getName()).append(",").append(pois.get(pois.size()-1).getTags())                      .append(pois.get(pois.size()-1).getAddr());            }            result.put("poiList",stringBuilder.toString()); // 周边poi信息//          }          if (bdLocation.getFloor() != null) {            // 当前支持高精度室内定位            String buildingID = bdLocation.getBuildingID();// 百度内部建筑物ID            String buildingName = bdLocation.getBuildingName();// 百度内部建筑物缩写            String floor = bdLocation.getFloor();// 室内定位的楼层信息,如 f1,f2,b1,b2            StringBuilder stringBuilder = new StringBuilder();            stringBuilder.append(buildingID).append("-").append(buildingName).append("-").append(floor);            result.put("indoor", stringBuilder.toString()); // 室内定位结果信息            mLocationClient.startIndoorMode();// 开启室内定位模式(重复调用也没问题),开启后,定位SDK会融合各种定位信息(GPS,WI-FI,蓝牙,传感器等)连续平滑的输出定位结果;          } else {            mLocationClient.stopIndoorMode(); // 处于室外则关闭室内定位模式          }        } else {          result.put("errorCode", bdLocation.getLocType()); // 定位结果错误码          result.put("errorInfo", bdLocation.getLocTypeDescription()); // 定位失败描述信息        }      } else {        result.put("errorCode", -1);        result.put("errorInfo", "location is null");      }      mEventSink.success(result); // android端实时检测位置变化,将位置结果发送到flutter端    }  }

位置提醒服务

  public class MyNotifyLister extends BDNotifyListener {    // 已到达设置监听位置附近    public void onNotify(BDLocation mlocation, float distance){      if (null == mEventSink) {        return;      }      Map result = new LinkedHashMap<>();      result.put("nearby", "已到达设置监听位置附近"); // 1为已经到达 0为未到达      mEventSink.success(result);    }  }

Example 代码

动态授权

  • example/pubspec.yaml
dependencies:  flutter:    sdk: flutter  ...  permission_handler: ^5.0.1+1
  • example/lib/main.dart
class _MyAppState extends State {  @override  void initState() {    super.initState();    _requestPermission(); // 执行权限请求  }  // 动态申请定位权限  Future _requestPermission() async {    Map statuses = await [      Permission.location,      Permission.storage,    ].request();    return statuses[Permission.location].isGranted &&        statuses[Permission.storage].isGranted;  }}

主界面代码

  • example/lib/main.dart
import 'dart:io';import 'package:flutter/material.dart';import 'dart:async';import 'package:flutter_baidu_plugin_ducafecat/flutter_baidu_plugin_ducafecat.dart';import 'package:flutter_baidu_plugin_ducafecat_example/views/location-view.dart';import 'package:permission_handler/permission_handler.dart';void main() {  runApp(MyApp());}class MyApp extends StatefulWidget {  @override  _MyAppState createState() => _MyAppState();}class _MyAppState extends State {  @override  void initState() {    super.initState();    _requestPermission(); // 执行权限请求    if (Platform.isIOS == true) {      FlutterBaiduPluginDucafecat.setApiKeyForIOS(          "dkYT07blcAj3drBbcN1eGFYqt16HP1pR");    }  }  @override  void dispose() {    super.dispose();  }  // 动态申请定位权限  Future _requestPermission() async {    Map statuses = await [      Permission.location,      Permission.storage,    ].request();    return statuses[Permission.location].isGranted &&        statuses[Permission.storage].isGranted;  }  @override  Widget build(BuildContext context) {    return MaterialApp(      routes: {        "location_view": (context) => LocationView(),      },      home: MyHome(),    );  }}class MyHome extends StatelessWidget {  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(title: Text('地图插件')),      body: SingleChildScrollView(        child: Column(          children: [            ListTile(              title: Text('定位信息'),              subtitle: Text('点击开始后,百度地图实时推送经纬度信息'),              leading: Icon(Icons.location_searching),              trailing: Icon(Icons.keyboard_arrow_right),              onTap: () {                Navigator.pushNamed(context, "location_view");              },            )          ],        ),      ),    );  }}

定位服务代码

  • example/lib/views/location-view.dart
import 'dart:async';import 'package:flutter/material.dart';import 'package:flutter_baidu_plugin_ducafecat/entity/flutter_baidu_location.dart';import 'package:flutter_baidu_plugin_ducafecat/entity/flutter_baidu_location_android_option.dart';import 'package:flutter_baidu_plugin_ducafecat/entity/flutter_baidu_location_ios_option.dart';import 'package:flutter_baidu_plugin_ducafecat/flutter_baidu_plugin_ducafecat.dart';class LocationView extends StatefulWidget {  LocationView({Key key}) : super(key: key);  @override  _LocationViewState createState() => _LocationViewState();}class _LocationViewState extends State {  FlutterBaiduPluginDucafecat _locationPlugin = FlutterBaiduPluginDucafecat();  StreamSubscription> _locationListener; // 事件监听  BaiduLocation _baiduLocation; // 经纬度信息  // Map _loationResult; // 返回格式数据  @override  void dispose() {    super.dispose();    // 取消监听    if (null != _locationListener) {      _locationListener.cancel();    }  }  // 返回定位信息  void _setupListener() {    if (_locationListener != null) {      return;    }    _locationListener =        _locationPlugin.onResultCallback().listen((Map result) {      setState(() {        // _loationResult = result;        try {          _baiduLocation = BaiduLocation.fromMap(result);          print(_baiduLocation);        } catch (e) {          print(e);        }      });    });  }  // 设置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 _handleStartLocation() {    if (null != _locationPlugin) {      _setupListener();      _setLocOption();      _locationPlugin.startLocation();    }  }  // 停止定位  void _handleStopLocation() {    if (null != _locationPlugin) {      _locationPlugin.stopLocation();      setState(() {        _baiduLocation = null;      });    }  }  ////////////////////////////////////////////////////////////  // 显示地理信息  Widget _buildLocationView() {    return _baiduLocation != null        ? Table(            children: [              TableRow(children: [                TableCell(child: Text('经度')),                TableCell(child: Text(_baiduLocation.longitude.toString())),              ]),              TableRow(children: [                TableCell(child: Text('纬度')),                TableCell(child: Text(_baiduLocation.latitude.toString())),              ]),              TableRow(children: [                TableCell(child: Text('国家')),                TableCell(                    child: Text(_baiduLocation.country != null                        ? _baiduLocation.country                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('省份')),                TableCell(                    child: Text(_baiduLocation.province != null                        ? _baiduLocation.province                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('城市')),                TableCell(                    child: Text(_baiduLocation.city != null                        ? _baiduLocation.city                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('区县')),                TableCell(                    child: Text(_baiduLocation.district != null                        ? _baiduLocation.district                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('街道')),                TableCell(                    child: Text(_baiduLocation.street != null                        ? _baiduLocation.street                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('地址')),                TableCell(                    child: Text(_baiduLocation.address != null                        ? _baiduLocation.address                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('位置语义化描述')),                TableCell(                    child: Text(_baiduLocation.locationDetail != null                        ? _baiduLocation.locationDetail                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('周边poi信息')),                TableCell(                    child: Text(_baiduLocation.poiList != null                        ? _baiduLocation.poiList                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('错误码')),                TableCell(                    child: Text(_baiduLocation.errorCode != null                        ? _baiduLocation.errorCode.toString()                        : "")),              ]),              TableRow(children: [                TableCell(child: Text('定位失败描述信息')),                TableCell(                    child: Text(_baiduLocation.errorInfo != null                        ? _baiduLocation.errorInfo                        : "")),              ]),            ],          )        : Container();  }  // 控制面板  Widget _buildControlPlan() {    return Row(      mainAxisAlignment: MainAxisAlignment.center,      children: [        MaterialButton(          color: Colors.blue,          textColor: Colors.white,          onPressed: _baiduLocation == null ? _handleStartLocation : null,          child: Text('开始定位'),        ),        MaterialButton(          color: Colors.blue,          textColor: Colors.white,          onPressed: _baiduLocation != null ? _handleStopLocation : null,          child: Text('暂停定位'),        )      ],    );  }  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: Text('定位信息'),      ),      body: SingleChildScrollView(        child: Column(          children: [            _buildControlPlan(),            Divider(),            _buildLocationView(),          ],        ),      ),    );  }}

参考


© 猫哥

https://ducafecat.tech
https://ducafecat.gitee.io

更多相关文章

  1. Android设备系统及屏幕分辨率统计信息汇总(截至2018年7月)
  2. android2.1获得联系人信息+Android 获取信息终端
  3. Android Build获得系统信息
  4. Android ProgressBar 自定义样式(六),仿真QQ pad版加载(位置居中)
  5. [置顶] 手机信息备份和恢复系统
  6. Android 获取手机的厂商信息
  7. android 从SIM卡获取联系人信息
  8. Android分享到腾讯微博,信息,新浪微博等等,的实现方式

随机推荐

  1. Android(安卓)4.0 ICS SystemUI浅析——S
  2. android实现短信监听
  3. Android自定义dialog主题样式解析
  4. Android中GridView实现长按多选功能
  5. Android原生音量控制
  6. android 使用InstanceState保存和恢复数
  7. Android(安卓)Studio 使用技巧集锦
  8. Android(安卓)自定义View -- 圆形进度条,
  9. Android(安卓)限制显示小数点位数
  10. Android与H5页面的互调