Flutter鸿蒙扩展高德定位插件

本文我们扩展amap_flutter_location,使其支持鸿蒙。目前该插件已经开源。

我们先看下目录结构

第一步,在原有项目的基础上怎么加对ohos平台的支持,命令如下

flutter create --template=plugin --platforms=ohos .

这样会新建一个ohos的文件夹,我们在里面新建鸿蒙的原生工程的文件

然后用DevEco Studio打开ohos文件夹,编写原生代码

首选,在oh-package.json5里面编写添加依赖

perl 复制代码
"@amap/amap_lbs_common": "^1.0.3",
"@amap/amap_lbs_location": "^1.0.2",
"dayjs": "^1.11.7"

新建

AmapFlutterLocationPlugin.ets文件作为插件的入口

kotlin 复制代码
import {
  Any,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult } from '@ohos/flutter_ohos';
import { FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin'
import EventChannel, { EventSink, StreamHandler } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel';
import { common } from '@kit.AbilityKit';
import { AMapLocationClientImpl } from './AMapLocationClientImpl';
import { HashMap } from '@kit.ArkTS';
import {
  AMapLocationManagerImpl
} from '@amap/amap_lbs_location/src/main/ets/com/amap/location/AMapLocationManagerImpl';
import { AMapPrivacyAgreeStatus, AMapPrivacyInfoStatus, AMapPrivacyShowStatus, TextUtils } from '@amap/amap_lbs_common';

const TAG: string = "AMapFlutterLocationPlugin";
const CHANNEL_METHOD_LOCATION: string = "amap_flutter_location";
const CHANNEL_STREAM_LOCATION: string = "amap_flutter_location_stream";
/** AmapFlutterLocationPlugin **/
export default class AmapFlutterLocationPlugin implements FlutterPlugin, MethodCallHandler, StreamHandler {
  private channel: MethodChannel | null = null;
  private eventChannel: EventChannel | null = null;

  private pluginBinding: FlutterPluginBinding | null = null;

  private mContext: common.Context | null  = null;

  private mEventSink: EventSink | null = null;

  private locationClientMap: HashMap = new HashMap();

  constructor() {
  }

  getUniqueClassName(): string {
    return TAG;
  }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(binding.getBinaryMessenger(), CHANNEL_METHOD_LOCATION);
    this.channel.setMethodCallHandler(this)
    this.eventChannel = new EventChannel(binding.getBinaryMessenger(), CHANNEL_STREAM_LOCATION);
    this.eventChannel.setStreamHandler(this)
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    if (this.channel != null) {
      this.channel.setMethodCallHandler(null)
    }
  }

  onListen(args: Object, eventSink: EventSink): void {
    this.mEventSink = eventSink;
  }

  onCancel(args: Object): void {
    this.locationClientMap.forEach((value, key) => {
      value!.stopLocation();
    });
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    switch (call.method) {
      case "updatePrivacyStatement":
        this.updatePrivacyStatement(call.args as Map);
        break;
      case "setApiKey":
        this.setApiKey(call.args as Map);
        break;
      case "setLocationOption":
        this.setLocationOption(call.args as Map);
        break;
      case "startLocation":
        this.startLocation(call.args as Map);
        break;
      case "stopLocation":
        this.stopLocation(call.args as Map);
        break;
      case "destroy":
        this.destroy(call.args as Map);
        break;
      default:
        result.notImplemented();
        break;
    }
  }

  private updatePrivacyStatement(privacyShowMap: Map):void {
    if (null != privacyShowMap) {
      if (privacyShowMap.has("hasContains") && privacyShowMap.has("hasShow")) {

        let hasContains: boolean = privacyShowMap.get("hasContains") as boolean;
        let hasShow: boolean = privacyShowMap.get("hasShow") as boolean;

        
        AMapLocationManagerImpl.updatePrivacyShow(hasShow ? AMapPrivacyShowStatus.DidShow :
        AMapPrivacyShowStatus.NotShow,
          hasContains ? AMapPrivacyInfoStatus.DidContain : AMapPrivacyInfoStatus.NotContain, this.mContext)

      }

      if (privacyShowMap.has("hasAgree")) {
        let hasAgree: boolean = privacyShowMap.get("hasAgree") as boolean;
        AMapLocationManagerImpl.updatePrivacyAgree(hasAgree ? AMapPrivacyAgreeStatus.DidAgree : AMapPrivacyAgreeStatus.NotAgree, this.mContext)
      }
    }
  }

  
  private  setApiKey(apiKeyMap: Map): void {
    if (null != apiKeyMap) {
      if (apiKeyMap.has("ohos") && !TextUtils.isEmpty(apiKeyMap.get("ohos") as string)){
        
        
        AMapLocationManagerImpl.setApiKey(apiKeyMap.get("ohos") as string);
        
      }
    }
  }

  
  private setLocationOption(argsMap: Map): void {
    let locationClientImp = this.getLocationClientImp(argsMap);
    if (null != locationClientImp) {
      locationClientImp.setLocationOption(argsMap);
    }
  }

  private getLocationClientImp(argsMap: Map): AMapLocationClientImpl|null {
    if (null == this.locationClientMap) {
      this.locationClientMap = new HashMap();
    }

    let pluginKey = this.getPluginKeyFromArgs(argsMap);
    if (TextUtils.isEmpty(pluginKey)) {
      return null;
    }

    if (!this.locationClientMap.hasKey(pluginKey)) {
      let locationClientImp = new AMapLocationClientImpl(this.mContext!, pluginKey!, this.mEventSink!);
      this.locationClientMap.set(pluginKey, locationClientImp);
    }
    return this.locationClientMap.get(pluginKey);
  }



  private getPluginKeyFromArgs(argsMap: Map): string|null {
    let pluginKey: string|null = null;
    if (null != argsMap) {
      pluginKey = argsMap.get("pluginKey") as string;
    }
    return pluginKey;
  }

  
  private startLocation(argsMap: Map):void {
    let locationClientImp = this.getLocationClientImp(argsMap);
    if (null != locationClientImp) {
      locationClientImp.startLocation();
    }
  }

  
  private  stopLocation(argsMap: Map): void {
    let locationClientImp = this.getLocationClientImp(argsMap);
    if (null != locationClientImp) {
      locationClientImp.stopLocation();
    }
  }

  
  private destroy(argsMap: Map):void {
    let locationClientImp = this.getLocationClientImp(argsMap);
    if (null != locationClientImp) {
      locationClientImp.destroy();

      this.locationClientMap.remove(this.getPluginKeyFromArgs(argsMap));
    }
  }
}

新建

AMapLocationClientImpl.ets作为高德地图的回调实现类

kotlin 复制代码
import {
  AMapLocation,
  AMapLocationErrorInfo,
  AMapLocationManagerImpl,
  AMapLocationOption,
  AMapLocationReGeocodeLanguage,
  AMapLocationType,
  IAMapLocationListener } from '@amap/amap_lbs_location'
import { geoLocationManager } from '@kit.LocationKit';
import { common } from '@kit.AbilityKit';
import { EventSink } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel';
import { HashMap } from '@kit.ArkTS';
import { MapUtils } from '../utils/MapUtils';
import { Any } from '@ohos/flutter_ohos';


const TAG: string = "AMapLocationClientImpl";
export class  AMapLocationClientImpl implements IAMapLocationListener{

  private mContext: common.Context | null  = null;
  private locationOption: AMapLocationOption | null = null;
  private locationClient: AMapLocationManagerImpl | null = null;
  private mEventSink: EventSink | null = null;

  private mPluginKey: string | null = null ;

  constructor(context: common.Context, pluginKey: string, eventSink: EventSink) {
    this.mContext = context;
    this.mPluginKey = pluginKey;
    this.mEventSink = eventSink;
    if (null == this.locationClient) {
      this.locationClient = new AMapLocationManagerImpl(context);
    }
  }

  /**
   * 开始定位
   */
  startLocation(): void {
    if (null == this.locationClient) {
      this.locationClient = new AMapLocationManagerImpl(this.mContext!);
    }
    if (null != this.locationOption) {
      this.locationClient.setLocationOption(AMapLocationType.Updating,this.locationOption);
      this.locationClient.setLocationListener(AMapLocationType.Updating,this);
      this.locationClient.startUpdatingLocation();
    }
  }

  /**
   * 停止定位
   */
  stopLocation():void {
    if (null != this.locationClient) {
      this.locationClient.stopUpdatingLocation();
      this.locationClient = null;
    }
  }

  destroy():void {
    if(null != this.locationClient) {
      this.locationClient.stopUpdatingLocation();
      this.locationClient = null;
    }
  }

  onLocationChanged(location: AMapLocation) {
    if (null == this.mEventSink) {
      return;
    }
    let result: HashMap = MapUtils.buildLocationResultMap(location, null);
    result.set("pluginKey", this.mPluginKey);
    this.mEventSink.success(result);
  }
  onLocationError(locationErrorInfo: AMapLocationErrorInfo){
    if (null == this.mEventSink) {
      return;
    }
    let result: HashMap = MapUtils.buildLocationResultMap(null, locationErrorInfo);
    result.set("pluginKey", this.mPluginKey);
    this.mEventSink.success(result);
  }


  /**
   * 设置定位参数
   *
   * @param optionMap
   */
  setLocationOption(optionMap: Map): void {
      if (null == this.locationOption) {
      this.locationOption =  {
          priority: geoLocationManager.LocationRequestPriority.FIRST_FIX, //定位优先配置选项
          scenario: geoLocationManager.LocationRequestScenario.UNSET, //定位场景设置
          timeInterval: 2, //定位时间间隔
          distanceInterval: 0, //位置报告距离间隔
          maxAccuracy: 20, //定位精度 单位:米
          allowsBackgroundLocationUpdates: false, //是否允许后台定位
          locatingWithReGeocode: true, //定位是否返回逆地理信息
          reGeocodeLanguage: AMapLocationReGeocodeLanguage.Chinese, //逆地址语言类型
          isOffset: true //是否加偏
        };
    }

    // if (optionMap.has("locationInterval")) {
    //   this.locationOption.timeInterval = optionMap.get("locationInterval") as number
    // }
    //
    //
    // if (optionMap.has("locationMode")) {
    //   try {
    //     locationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.values()[(int) optionMap.get("locationMode")]);
    //   } catch (Throwable e) {
    //   }
    // }
    //
    // if (optionMap.containsKey("geoLanguage")) {
    //   locationOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.values()[(int) optionMap.get("geoLanguage")]);
    // }
    //
    // if (optionMap.containsKey("onceLocation")) {
    //   locationOption.setOnceLocation((boolean) optionMap.get("onceLocation"));
    // }

    if (null != this.locationClient) {
        this.locationClient.setLocationOption(AMapLocationType.Updating,this.locationOption);
      }
    }

}

在pubspec.yaml配置到flutter插件入口类

同时修改

amap_flutter_location.dart中的setApiKey,增加ohosKey

一些内容写好后,还需要在高德地图后台申请鸿蒙的key,这里不详细赘述,按照高德官网的步骤就行。

写好测试工程,把插件引入,

然后安装使用amp_flutter_location的方式使用,只需要在鸿蒙平台多传入一个key就可以了

下面是写好的插件git地址

gitee.com/astevencui_...

相关推荐
指针满天飞8 分钟前
同步、异步、Promise、then、async/await
前端·javascript·vue.js
Alang13 分钟前
记一次错误使用 useEffect 导致电脑差点“报废”
前端·react.js
牛奶31 分钟前
前端学AI:LangGraph学习-基础概念
前端·langchain·ai编程
welkin35 分钟前
算法区间合并问题
前端·算法
Mintopia42 分钟前
Three.js高效几何体创建指南:BufferGeometry深度解析
前端·javascript·three.js
ak啊1 小时前
Webpack Loader 执行机制
前端·webpack·源码
牛马喜喜1 小时前
如何从零实现一个todo list(1)
前端
牛马喜喜1 小时前
Vue编写一个自己的树形组件
前端
Mintopia1 小时前
vue3 element-plus 二次封装Drawer抽屉,关闭时添加二次对话,开箱即用
前端·javascript·vue.js
悟空非空也1 小时前
超级简单,Trae 开发Chrome浏览器插件,AI编程时代来了
前端