Flutter/OpenHarmony 三方库适配实战:google_maps_flutter 地图 Flutter/OpenHarmony 三方库适配实战google_maps_flutter 地图一、项目信息项目内容仓库名称google_maps_flutter仓库地址https://atomgit.com/oh-flutter/google_maps_flutter基于版本google_maps_flutter 2.19.0适配 TAG2.19.0-ohos-1.0.0OHOS 插件包google_maps_flutter_ohosOHOS 原生入口AMapFlutterMapPluginDart 注册类GoogleMapsFlutterOhosOHOS 地图 SDKamap/amap_lbs_map3d 11.1.104google_maps_flutter的 Dart API 定义了地图 Widget、相机、标记、折线、多边形和事件模型但 OpenHarmony 不提供 Google Maps 原生服务。本次适配保留GoogleMap的使用方式在 OHOS 平台使用高德地图 SDK 渲染原生地图。适配不是把 Dart 地图对象重写为 ArkTS 组件而是建立一层模型转换GoogleMap Widget | v Dart Platform Interface | v GoogleMapsFlutterOhos | v PlatformView 每个地图实例独立 MethodChannel | v AMapMethodChannel / Controller / Overlay Controller | v MapViewComponent AMap OHOS SDK二、适配边界本次实现支持使用GoogleMap创建原生地图 PlatformView。初始相机位置和onMapCreated回调。moveCamera、animateCamera和相机事件。Marker、Polyline、Polygon 的创建、更新和删除。地图点击、长按和基本手势事件。定位蓝点配置所需的能力接入。以下能力需要业务侧额外验证或暂不作为稳定能力需要精确匹配 Google Maps SDK 的高级瓦片能力。未在当前模拟器完成有效 Key 下的地图瓦片截图。路径规划、搜索、POI 和 Google 专有云服务。依赖特定 Google Maps 行为的业务插件。三、依赖与 TAG业务工程引用 AtomGit 仓库dependencies:google_maps_flutter:git:url:https://atomgit.com/oh-flutter/google_maps_flutter.gitpath:packages/google_maps_flutter/google_maps_flutterref:2.19.0-ohos-1.0.0执行flutter pub getOHOS 平台包在pubspec.yaml中同时声明原生插件类和 Dart 注册类flutter:plugin:platforms:ohos:package:com.amap.flutter.mappluginClass:AMapFlutterMapPlugindartPluginClass:GoogleMapsFlutterOhospluginClass负责注册 PlatformView 工厂dartPluginClass将GoogleMapsFlutterPlatform.instance指向 OHOS 实现。四、注册 PlatformView 工厂原生插件在引擎附加时注册地图视图类型constVIEW_TYPEplugins.flutter.io/google_maps;exportdefaultclassAMapFlutterMapPluginimplementsFlutterPlugin{onAttachedToEngine(binding:FlutterPluginBinding):void{AMapCreateListener.getInstance().init();ConvertUtil.init();binding.getPlatformViewRegistry()?.registerViewFactory(VIEW_TYPE,newAMapPlatformViewFactory(binding.getBinaryMessenger(),StandardMessageCodec.INSTANCE,),);}}地图工厂为每个viewId创建独立的AMapPlatformViewcreate(viewId:number,args:Object,messenger:BinaryMessenger,):PlatformView{returnnewAMapPlatformView(viewId,args,messenger);}每个视图使用自己的通道plugins.flutter.io/google_maps_viewId这种设计可以同时创建多张地图也避免一个地图的相机、覆盖物和点击事件错误地发送给另一个地图。五、ArkTS 地图组件PlatformView 最终渲染 ArkUI 的地图组件Componentexportdefaultstruct AMapView{Propparams:Params;customView:AMapPlatformViewthis.params.platformViewasAMapPlatformView;viewId:numberthis.customView.getViewId();aboutToDisappear():void{AMapCreateListener.getInstance().destroyView(this.viewId);}build():void{MapViewComponent({mapViewName:this.viewId.toString(),}).width(100%).height(100%);}}mapViewName与viewId一一对应。地图 SDK 创建AMap对象后通过事件通知对应的AMapMethodChannel通道再完成控制器初始化和初始参数应用。组件销毁时必须反注册监听并销毁 MapView否则页面退出后可能残留原生地图对象。六、地图就绪与方法分发AMapMethodChannel为每个视图创建MethodChannel并把方法分发给相机、Marker、Polyline、Polygon 等控制器constructor(viewId:number,args:Object,binaryMessenger:BinaryMessenger,){this.viewIdviewId;this.argsargsasMapstring,Object;this.channelnewMethodChannel(binaryMessenger,METHOD_CHANNEL_PREFIXviewId,);this.channel.setMethodCallHandler(this);this.registerAMapCreateEvent();}如果 Dart 在地图组件尚未创建时调用waitForMap原生侧缓存当前MethodResult等地图创建完成后统一回复if(call.methodUserEvent.METHOD_MAP_WAIT_FOR_MAP){if(this.aMap){result.success(null);}else{this.mapReadyResultresult;}return;}这种方式可以避免业务在onMapCreated之前过早控制相机时出现随机失败。七、隐私初始化和 Key 配置高德 SDK 要求在创建地图前处理隐私合规。宿主 Ability 在窗口创建阶段调用AMapFlutterMapPlugin.initializePrivacy(this.context);插件内部完成一次性初始化staticinitializePrivacy(context:common.Context):void{MapsInitializer.initialize(context);MapsInitializer.updatePrivacyShow(AMapPrivacyShowStatus.DidShow,AMapPrivacyInfoStatus.DidContain,context,);MapsInitializer.updatePrivacyAgree(AMapPrivacyAgreeStatus.DidAgree,context,);}隐私状态必须由宿主应用根据真实交互流程设置插件不能替业务绕过用户授权。地图还需要 OHOS Key。不要把 Key 写入源码应通过构建参数传入flutter build hap\--debug\--dart-defineAMAP_OHOS_KEY你的高德OHOS KeyKey 必须与 HAP 的 Bundle Name 和签名信息匹配。调试包与发布包应按地图服务提供方的规则分别配置。在线地图还需要网络权限使用定位蓝点时还需要声明定位权限、用途说明和usedScene{ module: { requestPermissions: [ { name: ohos.permission.INTERNET }, { name: ohos.permission.APPROXIMATELY_LOCATION }, { name: ohos.permission.LOCATION }, ], }, }八、Dart 业务示例业务代码继续使用原库 APIclassMapDemoPageextendsStatefulWidget{constMapDemoPage({super.key});overrideStateMapDemoPagecreateState()_MapDemoPageState();}class_MapDemoPageStateextendsStateMapDemoPage{GoogleMapController?_controller;overrideWidgetbuild(BuildContextcontext){returnGoogleMap(initialCameraPosition:constCameraPosition(target:LatLng(39.909187,116.397416),zoom:12,),markers:Marker{Marker(markerId:constMarkerId(demo),position:constLatLng(39.909187,116.397416),),},onMapCreated:(controller){_controllercontroller;},onTap:(position){debugPrint(map tap:$position);},);}overridevoiddispose(){_controller?.dispose();super.dispose();}}地图移动可以直接复用CameraUpdateawait_controller?.animateCamera(CameraUpdate.newLatLng(constLatLng(31.230416,121.473701),),);九、构建和结果验证结果flutter analyze --no-pub通过。2 个 Dart 测试通过。HAP 构建、安装和启动成功。PlatformView 工厂已注册地图容器已经创建。模拟器日志出现AMapErrorInvaildUserKey 10001。截图只能证明 Flutter 示例工程已经启动地图容器占位和“移动相机”按钮已经显示。由于当前测试 Key 与 Bundle Name/签名不匹配截图中的地图瓦片区域为空不能将其描述为地图渲染成功。业务接入时应在高德开放平台申请 OHOS Key。确认 Key 的 Bundle Name 与宿主 HAP 一致。调试签名和发布签名分别配置。通过--dart-define注入 Key 后重新构建安装。检查日志中不再出现10001再进行地图渲染验收。十、资源释放引擎分离时插件按顺序释放通道、定位监听和地图对象onDetachedFromEngine(binding:FlutterPluginBinding):void{AMapMethodChannel.releaseAll();AMapCreateListener.getInstance().unregisterMapViewCreatedCallback();LocationHelper.getInstance().stopAllLocate();AMapCreateListener.getInstance().clearAll();ConvertUtil.reset();}每个AMapMethodChannel也会解绑自身方法处理器并清空控制器。这样页面销毁、热重启或引擎重建时不会继续向旧地图发送方法调用。十一、代码提交与协作欢迎加入 CPF-Flutter 鸿蒙社区参与 FlutterOHOS 经验交流。