HarmonyOS 鸿蒙Next Flutter框架多设备开发指导-视频通话场景

HarmonyOS 鸿蒙Next Flutter框架多设备开发指导-视频通话场景

1.1 场景概述

在移动应用开发中,视频通话是一种常见的实时通信功能。不同设备的屏幕形态各异,如直板机、PAD、PC、折叠屏等,同时系统状态栏、导航栏、软键盘等元素也会占据屏幕空间。为了确保视频通话界面在各种设备和场景下都能正常显示,提供流畅的用户体验。本文将详细介绍 RN 视频通话组件的实现原理、适配指导以及具体的场景案例。

1.1.1 使用场景

在实时通信应用、社交软件、远程协作工具中,视频通话是很常见的功能,希望在不同设备上视频通话界面都能正常显示和交互。下面是不同设备上视频通话界面的差异,包括:直板机、PAD、PC、折叠屏(阔折叠、双折叠、三折叠)、智慧屏、座舱。

1.1.2 常见问题

开发过程中视频通话界面在不同设备上会存在差异,可能会出现以下问题:

  • 摄像头画面被状态栏、导航栏遮挡
  • 小窗口(画中画)位置不当导致画面截断
  • 折叠屏设备折痕区域影响视频内容显示
  • 分屏场景下视频窗口被另一个应用遮挡
  • 横竖屏切换时视频布局错乱

1.1.3 多设备适配

1.1.3.1 视频通话多设备尺寸自适应适配

说明

根据断点布局实现视频通话界面的自适应:

横向断点 sm md lg xl
属性 适配竖屏手机,小窗口位于右上角 适配横屏平板,小窗口自适应位置 适配折叠屏,小窗口自适应位置 适配 PC 屏,小窗口自适应位置

1.1.3.2 视频通话多设备窗口变化适配

  • 适配点1:基于断点实现组件自适应在多设备布局适配,窗口响应(横竖屏、分屏、折叠开合等)

  • 适配点2:组件尺寸自适应覆盖拉伸、均分、占比、缩放、延伸、隐藏、折行。

1.2 开发指导

1.2.1 Flutter开发

1.2.1.1 关键能力

1.2.1.1.1 PlatformView 桥接相机与远端适配

Flutter 无法直接调用 HarmonyOS 的 CameraKit 和 MediaKit,因此通过 PlatformView + MethodChannel 实现原生能力嵌入。

相机预览 (CameraOhosView):原生侧通过 XComponent(type: SURFACE) 获取 Surface,交给 CameraKit 进行相机预览渲染。Flutter 侧通过 OhosView(viewType: ‘com.videocall.ohos/cameraView’) 嵌入。

远端视频 (RemoteVideoOhosView):原生侧同样使用 XComponent 提供 Surface 给 AVPlayer,模拟远端视频画面。Flutter 侧通过 OhosView(viewType: ‘com.videocall.ohos/remoteVideoView’) 嵌入。

1.2.1.1.2 相机宽高比自适应

相机预览的宽高比与屏幕不一定匹配,需要进行自适应处理以避免画面拉伸:

原生侧选择最优 Profile:遍历设备支持的所有预览分辨率,计算每个 Profile 的宽高比与屏幕宽高比的差值,选择差值最小的(见 CameraOhosView.ets 的 selectBestProfile 方法)。

Flutter 侧计算显示尺寸:通过 getCameraSize() 获取相机分辨率,结合屏幕尺寸计算出保持宽高比的最优显示区域,再通过 setXComponentRect() 通知原生侧调整 Surface 尺寸。

Future<void> _setupCameraAspectRatio() async {
  final cameraSize = await _cameraController?.getCameraSize();
  //根据横竖屏计算 cameraAspectRatio
  //按 cover 策略计算 displayWidth / displayHeight
  await _cameraController?.setXComponentRect(displayWidth.toInt(), displayHeight.toInt());
}
1.2.1.1.3 远端视频宽高比适配

远端视频同样需要宽高比适配,采用 FIT(缩小至完全显示) 策略:

Future<void> _updateVideoArea({int retryCount = 0}) async {
  final videoSize = await _remoteVideoController?.getVideoSize();
  final diffW = windowWidth / videoWidth;
  final diffH = windowHeight / videoHeight;
  if (diffW <= diffH) {
    _remoteVideoWidthPercent = 1.0;
    _remoteVideoHeightPercent = diffW * videoHeight / windowHeight;
  } else {
    _remoteVideoHeightPercent = 1.0;
    _remoteVideoWidthPercent = diffH * videoWidth / windowWidth;
  }
}

配合 FractionallySizedBox 实现视频区域的动态缩放:

FractionallySizedBox(
  widthFactor: _remoteVideoWidthPercent,
  heightFactor: _remoteVideoHeightPercent,
  child: RemoteVideoOhosView(_onRemoteVideoViewCreated),
)

原生侧同时设置 VIDEO_SCALE_TYPE_FIT_CROP 保证视频在 Surface 内不拉伸。

1.2.1.1.4 画中画 (PiP)

通过 PipManager 封装 HarmonyOS 的 PiPWindow API,实现视频通话画中画功能:

模板类型:PiPWindow.PiPTemplateType.VIDEO_CALL

内容尺寸:从 XComponent 的 SurfaceRect 获取

状态流转:ABOUT_TO_START → STARTED → ABOUT_TO_STOP → STOPPED

Flutter 联动:状态变化通过 onPipStateChanged 回调 Flutter 侧,Flutter 根据状态切换大小窗画面

// Flutter 侧:监听 PiP 状态,实现大小窗切换
void _handlePipStateChange(String state, {required bool isCamera}) {
  if (state == 'STOPPED') {
    if (_isRemoteShow && isCamera) {
      _isRemoteShow = false;
      _remoteVideoController?.startPip();
    } else if (!_isRemoteShow && !isCamera) {
      _isRemoteShow = true;
      _cameraController?.startPip();
    }
  }
}
1.2.1.1.5 屏幕变化自适应

通过 WidgetsBindingObserver.didChangeMetrics 监听屏幕尺寸变化(如旋转、折叠屏展开),动态重新计算布局:

void didChangeMetrics() {
  super.didChangeMetrics();
  _onWindowSizeChanged(); // 重新计算相机宽高比 + 重启预览 + 更新远端视频区域
}
1.2.1.1.6 安全区适配

使用 Flutter 的 SafeArea 组件确保通话控制按钮不被系统状态栏、导航栏遮挡,同时视频画面全屏展示

Stack(children: [
  // 视频层:全屏
  Container(
    width: double.infinity,
    height: double.infinity,
    color: !_isRemoteShow ? Colors.black : Colors.transparent,
    child: CameraOhosView(_onCameraViewCreated),
  ),
  //控制层:安全区内
  Positioned.fill(
   child: SafeArea(child: Column(...))
  ),
])

1.2.1.2 指导案例

1.2.1.2.1 原生插件注册

在 EntryAbility.ets 中注册 VideoCallPlugin:

export default class EntryAbility extends FlutterAbility {
  configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    GeneratedPluginRegistrant.registerWith(flutterEngine)
    this.addPlugin(new VideoCallPlugin());
  }
}
1.2.1.2.2 PlatformView 工厂注册

在 VideoCallPlugin.ets 中注册两个 PlatformView 工厂:

export class VideoCallPlugin implements FlutterPlugin {
  onAttachedToEngine(binding: FlutterPluginBinding): void {
    // 注册相机预览 PlatformView
    binding.getPlatformViewRegistry()?.registerViewFactory(
      'com.videocall.ohos/cameraView',
      new CameraViewFactory(binding.getBinaryMessenger(), StandardMessageCodec.INSTANCE)
    );
    // 注册远端视频 PlatformView
    binding.getPlatformViewRegistry()?.registerViewFactory(
      'com.videocall.ohos/remoteVideoView',
      new RemoteVideoFactory(binding.getBinaryMessenger(), StandardMessageCodec.INSTANCE)
    );
  }
}
1.2.1.2.3 Flutter 侧嵌入 PlatformView

通过 OhosView 将原生视图嵌入 Flutter 布局:

// 相机预览
OhosView(
  viewType: 'com.videocall.ohos/cameraView',
  onPlatformViewCreated: _onPlatformViewCreated,
  creationParams: const <String, dynamic>{},
  creationParamsCodec: const StandardMessageCodec(),
);
// 远端视频
OhosView(
  viewType: 'com.videocall.ohos/remoteVideoView',
  onPlatformViewCreated: _onPlatformViewCreated,
  creationParams: const <String, dynamic>{},
  creationParamsCodec: const StandardMessageCodec(),
);
1.2.1.2.4 相机宽高比适配步骤
  1. 原生侧在 startCamera() 中调用 selectBestProfile() 选择与屏幕宽高比最匹配的分辨率
  2. Flutter 侧通过 getCameraSize() 获取选中的分辨率
  3. 根据屏幕尺寸和相机分辨率计算 cover 策略下的显示宽高
  4. 通过 setXComponentRect() 设置原生 Surface 尺寸
  5. 屏幕旋转/折叠时,在 didChangeMetrics 中重新执行上述流程
1.2.1.2.5 画中画集成步骤
  1. 原生侧创建 PipManager,传入 XComponentController 和 UIAbilityContext
  2. 配置 PiPConfiguration,模板类型设为 VIDEO_CALL
  3. 注册 stateChange 回调,通过 MethodChannel 通知 Flutter
  4. Flutter 侧在 Controller 中监听 pipStateStream,根据 STOPPED 状态实现大小窗切换逻辑
1.2.1.2.6 响应式布局适配

根据屏幕高度动态调整控件尺寸,适配不同形态设备:

final screenHeight = MediaQuery.of(context).size.height;
final isSmallHeight = screenHeight < 600;
final iconSize = isSmallHeight ? 28.0 : 56.0;
final topMarginPercent = isSmallHeight ? 0.10 : 0.20;
final bottomMarginPercent = isSmallHeight ? 0.10 : 0.20;

1.2.1.3 示例代码

视频通话的Sample示例代码地址:example,开发者可以通过该地址查看完整的视频通话示例代码,并根据自己的需求进行修改和扩展。


更多关于HarmonyOS 鸿蒙Next Flutter框架多设备开发指导-视频通话场景的实战教程也可以访问 https://www.itying.com/category-92-b0.html

2 回复

在HarmonyOS Next中,使用Flutter框架开发多设备视频通话,需通过Flutter插件封装鸿蒙原生API(如OHOS::Media::AVPlayer、OHOS::DistributedHardware::DeviceManager)。利用分布式软总线实现设备发现与连接,通过Flutter MethodChannel调用native音视频采集与渲染接口。注意在Flutter UI侧适配不同屏幕尺寸与折叠状态。

更多关于HarmonyOS 鸿蒙Next Flutter框架多设备开发指导-视频通话场景的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


该指南系统梳理了HarmonyOS Next上基于Flutter框架实现视频通话多设备适配的关键方案。通过PlatformView+MethodChannel桥接原生CameraKit与MediaKit,结合断点布局(sm/md/lg/xl)实现从小屏手机到折叠屏、PC的界面自适应。核心适配点包括相机与远端视频宽高比匹配、SafeArea安全区覆盖、屏幕形态变化监听(didChangeMetrics)和画中画(PiP)状态同步。示例代码展示了OhosView工厂注册、相机最优Profile选择、大小窗切换逻辑等,有效解决了遮挡、变形、窗口截断等常见问题。整体为多设备视频通话场景提供了可落地的开发范式。

回到顶部