HarmonyOS 鸿蒙Next 如何解决Flutter使用platformview嵌入高德地图发生crash的问题

发布于 1周前 作者 eggper 最后一次编辑是 5天前 来自 鸿蒙OS

【问题现象】

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视图。

1 回复

针对HarmonyOS 鸿蒙Next中Flutter使用platformview嵌入高德地图发生crash的问题,以下是一些可能的解决方案:

  1. 检查SDK版本与兼容性

    • 确保高德地图SDK版本与HarmonyOS 鸿蒙Next兼容。
    • 查阅高德地图开放平台提供的官方文档,确认SDK版本支持情况。
  2. 正确配置依赖与权限

    • 在鸿蒙项目中下载并解压高德地图SDK的对应版本。
    • 配置必要的依赖项和权限,确保地图功能正常使用。
  3. 代码审查与调试

    • 审查代码中地图组件的初始化与使用方式,确保符合高德地图SDK的规范。
    • 使用DevEco Studio的调试工具,查看崩溃时的日志,定位问题所在。
  4. 适配鸿蒙系统API

    • 适配鸿蒙系统的API,确保应用能够在新系统上稳定运行。
    • 查阅HarmonyOS的官方文档,了解相关API的使用方法和注意事项。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部