本文我们扩展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地址