HarmonyOS 鸿蒙Next 如何解决Flutter使用platformview嵌入高德地图发生crash的问题
【问题现象】
Flutter使用platformview嵌入高德地图发生crash,堆栈如下:
Error message:is not callableStacktrace:at AmapBuilder (entry/src/main/ets/entryability/AmapComponent.ets:17:28)at build (../../../foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsXNode.js:178:1)at build (../../../foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsXNode.js:68:1)at makeNode (oh_modules/.ohpm/@ohos+flutter_ohos@loknt9ysirpmb5mk+bdd3twdaysmmfzjnv+4zuqiim8=/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/EmbeddingNodeController.ets:57:7)at __makeNode__ (../../../foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsXNode.js:605:1)at anonymous (oh_modules/.ohpm/@ohos+flutter_ohos@loknt9ysirpmb5mk+bdd3twdaysmmfzjnv+4zuqiim8=/oh_modules/@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicView.ets:243:5)at updateFunc (/usr1/hmos_for_system/src/increment/sourcecode/foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/stateMgmt.js:6740:1)at observeComponentCreation2 (/usr1/hmos_for_system/src/increment/sourcecode/foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/stateMgmt.js:6781:1)at buildNodeContainer (oh_modules/.ohpm/@ohos+flutter_ohos@loknt9ysirpmb5mk+bdd3twdaysmmfzjnv+4zuqiim8=/oh_modules/@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicView.ets:242:30)at anonymous (oh_modules/.ohpm/@ohos+flutter_ohos@loknt9ysirpmb5mk+bdd3twdaysmmfzjnv+4zuqiim8=/oh_modules/@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicView.ets:272:7)at ifElseBranchUpdateFunction (/usr1/hmos_for_system/src/increment/sourcecode/foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/stateMgmt.js:4286:1)at anonymous (oh_modules/.ohpm/@ohos+flutter_ohos@loknt9ysirpmb5mk+bdd3twdaysmmfzjnv+4zuqiim8=/oh_modules/@ohos/flutter_ohos/src/main/ets/view/DynamicView/dynamicView.ets:271:56)at updateFunc (/usr1/hmos_for_system/src/increment/sourcecode/foundation/arkui/ace_engine/frameworks/bridge/declarati
【背景知识】
Flutter中的Platformview(即平台视图)允许将原生视图嵌入到Flutter应用中;对应HarmonyOS平台,即可以将ArkUI组件嵌入到Flutter应用中,可以使用Dart代码对ArkUI组件控制。
【定位思路】
Platformview已相对成熟,我们走读问题代码进行定位。
@Component
struct AmapComponent {
@Prop params: Params
aboutToAppear(): void { ... }
build() {
Column(){
MapViewComponent()
}
.width('100%')
.height('100%')
}
}
@Builder
export function AmapBuilder() {
AmapComponent()
}
看到用于导出原生视图的AmapBuilder是无参的,但正确的用法需要传入Param,如下:
export declare class Params {
direction: Direction
platformView : PlatformView
}
此参数包含了原生视图相关信息,我们不需要手动去传入该参数,但缺少将导致原生视图在Flutter侧的渲染失败,并发生Crash,修改如下:
@Builder
export function AmapBuilder(params: Params) {
AmapComponent({ params: params })
}
【解决方案】
在背景知识中,我们了解了Platformview的用途,在针对那些未做HarmonyOS的插件且需要渲染UI的,就可以使用该技术。使用Platformview开发时,需要同时开发Native****侧和Flutter****侧,下面会分这两块介绍。
1.Native (HarmonyOS)侧
我们先做原生侧的UI开发,我们此处以高德地图为例,高德地图的开发参见Amap,这里不做赘述。
(1)新建AmapComponent,用于展示高德地图。
import { AMap, MapsInitializer, MapView, MapViewComponent, MapViewManager } from '[@amap](/user/amap)/amap_lbs_map3d';
import { Params } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformView';
@Component
struct AmapComponent {
@Prop params: Params
aboutToAppear(): void {
MapsInitializer.setApiKey("XXXXXXXXXXXXXXXXXX"); // 参考高德官方文档生成
MapViewManager.getInstance().registerMapViewCreatedCallback((mapview?: MapView, mapViewName?: string) => {
if (!mapview) {
return;
}
let mapView = mapview;
mapView.onCreate();
mapView.getMapAsync((map) => {
let aMap: AMap = map;
})
})
}
build() {
Column(){
MapViewComponent()
}
.width('100%')
.height('100%')
}
}
@Builder
export function AmapBuilder(params: Params) { // 需要通过@Builder的方式来导出原生组件
AmapComponent({ params: params }) // 注意这里的params参数必不可上
}
(2)新建CustomView类,把AmapComponent封装成PlatformView;其中MethodCallHandler是一个接口,用于Flutter端和Native端之间做方法调用通信。
@Observed // 注意这里,必须添加,用于Flutter监测原生UI的变化
export class CustomView extends PlatformView implements MethodCallHandler
核心接口函数实现,包装并返回上一步编写的Native UI组件。
getView(): WrappedBuilder<[Params]> {
return new WrappedBuilder(AmapBuilder); // 包装并返回上一步编写的原生UI组件
}
(3)创建工厂类CustomFactory,用于生产CustomView;CustomFactory需要继承PlatformViewFactory,表示Native UI的工厂类。
export class CustomFactory extends PlatformViewFactory {
message: BinaryMessenger;
constructor(message: BinaryMessenger, createArgsCodes: MessageCodec<Object>) {
super(createArgsCodes);
this.message = message;
}
public create(context: common.Context, viewId: number, args: Object): PlatformView {
return new CustomView(context, viewId, args, this.message); // 导出自定义的原生视图
}
}
(4)创建CustomPlugin类,用于应用启动时注册插件并将工厂类CustomFactory传递到Flutter侧。
export class CustomPlugin implements FlutterPlugin {
getUniqueClassName(): string {
return 'CustomPlugin';
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
binding.getPlatformViewRegistry()?.
registerViewFactory('com.example.ohos/customView', new CustomFactory(binding.getBinaryMessenger(), StandardMessageCodec.INSTANCE));
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {}
}
(5)在应用启动时注册CustomPlugin加载到Flutter中。
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
this.addPlugin(new CustomPlugin()); // 加载插件
}
}
2. Flutter侧
Flutter侧相对简单,我们需要用到HarmonyOS的Flutter提供的OhosView类,作为原生组件的桥接,我们先创建CustomOhosViewFlutter视图类,封装Navitve传递过来的UI组件。
class CustomOhosView extends StatefulWidget {
const CustomOhosView({Key? key}) : super(key: key);
@override
State<CustomOhosView> createState() => _CustomOhosViewState();
}
class _CustomOhosViewState extends State<CustomOhosView> {
@override
Widget build(BuildContext context) {
return _getPlatformFaceView();
}
Widget _getPlatformFaceView() {
return const OhosView( // 封装原生组件
viewType: 'com..example.ohos/customView', // 这里要与Native侧CustomPlugin中的保持一致
creationParams: <String, dynamic>{'initParams': 'hello world'},
creationParamsCodec: StandardMessageCodec(),
);
}
}
CustomOhosView的使用就和普通的Flutter组件一样了,我们直接在Flutter页面中使用它。
class _CustomExampleState extends State<CustomExample> {
String receivedData = '';
Widget _buildOhosView() {
return Expanded(
flex: 3,
child: Container(
color: Colors.blueAccent.withAlpha(60),
child: const CustomOhosView())); // 直接使用CustomOhosView
}
@override
Widget build(BuildContext context) {
return Column(children: [_buildOhosView(), _buildFlutterView()]);
}
Widget _buildFlutterView() {
return Expanded(
flex: 1,
child: Stack(alignment: AlignmentDirectional.bottomCenter, children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: const [
Text('This is Flutter View', style: TextStyle(fontSize: 20))
])
]));
}
}
效果示例图如下:
上半部分高德地图是用Native组件实现,下面白色的部分就是Flutter的UI视图。
针对HarmonyOS 鸿蒙Next中Flutter使用platformview嵌入高德地图发生crash的问题,以下是一些可能的解决方案:
-
检查SDK版本与兼容性:
- 确保高德地图SDK版本与HarmonyOS 鸿蒙Next兼容。
- 查阅高德地图开放平台提供的官方文档,确认SDK版本支持情况。
-
正确配置依赖与权限:
- 在鸿蒙项目中下载并解压高德地图SDK的对应版本。
- 配置必要的依赖项和权限,确保地图功能正常使用。
-
代码审查与调试:
- 审查代码中地图组件的初始化与使用方式,确保符合高德地图SDK的规范。
- 使用DevEco Studio的调试工具,查看崩溃时的日志,定位问题所在。
-
适配鸿蒙系统API:
- 适配鸿蒙系统的API,确保应用能够在新系统上稳定运行。
- 查阅HarmonyOS的官方文档,了解相关API的使用方法和注意事项。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。