HarmonyOS一杯冰美式的时间 -- FullScreenLaunchComponent

一、前言

最近在开发中,我们的元服务需要被其他应用通过FullScreenLaunchComponent拉起,我只能说当时上了5.0的当,FullScreenLaunchComponent也是Beta版本的!在实际开发中作为碰了几次灰,踩了不少坑,觉得有必要分享下,故有了此篇文章。

该系列依旧会带着大家,了解,开阔一些不怎么热门的API,也可能是偷偷被更新的API,也可以是好玩的,藏在官方文档的边边角角~当然也会有一些API,之前是我们辛辛苦苦的手撸代码,现在有一个API能帮我们快速实现的,希望大家能找宝藏。

如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏

二、FullScreenLaunchComponent的诞生背景

OK,步入正题把,在HarmonyOS开发中,我们可能会需要在一个应用中嵌入另一个应用的能力。比如,你的应用想要使用某个元服务提供的功能,但又不想让用户跳转到另一个应用,而是希望在自己的应用内无缝使用这个能力。

以前我们可能需要通过跳转的方式拉起另一个应用,这样用户体验就不够流畅。FullScreenLaunchComponent就是为了解决这个问题而生的,它允许我们以全屏方式拉起元服务,使得应用能够提供更友好的用户体验。虽然我不是很喜欢这个能力,因为真的坑到我了。

1. 什么是FullScreenLaunchComponent

FullScreenLaunchComponent是由ArkUI提供的组件,简单来说,它就是一个"容器",可以嵌入运行另一个元服务的UI。

当被拉起方授权使用方应用嵌入式运行元服务时,使用方应用可全屏嵌入式运行该服务;若未授权,则使用方应用将以跳出式方式拉起元服务。

三、基本使用

1. 版本说明

  • 该组件从API version 12开始支持
  • 该组件不支持在Wearable设备上使用(真的需要在穿戴设备使用这个功能吗????)
  • 5.0和6.0的表现非常不一样!

2. 使用方接入

使用方接入非常简单,只需要几行代码就能搞定:

typescript 复制代码
import { FullScreenLaunchComponent } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State appId: string = 'XXXXX'; // 元服务appId

  build() {
    Row() {
      Column() {
        FullScreenLaunchComponent({
          content: this.ColumnChild,  // 占位图标组件
          appId: this.appId,     // 元服务appId
          options: {},           // 拉起参数
          onTerminated: (info) => {
            // 元服务退出时的回调
            console.info(`onTerminated code: ${info.code.toString()}`);
          },
          onError: (err) => {
            // 发生异常时的回调
            console.error(`onError code: ${err.code}, message: ${err.message}`);
          },
          onReceive: (data) => {
            // 接收元服务传递的数据
            console.info(`onReceive, data: ${JSON.stringify(data)}`);
          }
        }).width("80vp").height("80vp")
      }
      .width('100%')
    }
    .height('100%')
  }
}

// 占位图标,点击后拉起元服务
@Builder
function ColumnChild() {
  Column() {
    Image($r('app.media.startIcon'))
    Text('test')
  }
}

可以看到,接入确实非常方便!只需要:

  1. 导入FullScreenLaunchComponent
  2. 传入appId(元服务的唯一标识)
  3. 传入content(占位图标组件)
  4. 可选:设置回调函数

3. 提供方实现

提供方需要继承EmbeddableUIAbility,这是必须的!否则系统无法保证元服务功能正常(刚开始,你继承或者不继承,都不影响不正常...)。

提供方入口文件:/src/main/ets/entryability/EntryAbility.ets

typescript 复制代码
import { AbilityConstant, Want, EmbeddableUIAbility } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends EmbeddableUIAbility {
  storage = new LocalStorage();
  
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
    // ⚠️ 重要:正常开发中getMainWindowSync可以正常使用,但如果需要提供给FullScreenLaunchComponent,
    // 在FullScreenLaunchComponent场景下getMainWindowSync会崩溃,必须使用try-catch,虽然你也拿不到,笑死了。
    try {
      let mainWindow = windowStage.getMainWindowSync();
    //TODO 做点什么
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'getMainWindowSync failed: %{public}s', JSON.stringify(err));
    }
    windowStage.loadContent('pages/Index', this.storage);
  }

  onWindowStageDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

四、实际开发中的坑点

以下问题都是我们在作为提供方开发时遇到的,如果你是使用方,可能不会遇到这些问题,但了解这些限制也有助于更好地使用FullScreenLaunchComponent。

1. 状态栏高度获取问题

在HarmonyOS 6.0之前,我们在EmbeddableUIAbility中顶部的状态栏高度没有办法正确的获取。这个问题很隐蔽,因为不会报错,只是获取到的值不对,导致UI布局出现问题。

解决方案:

在6.0之前,我直接使用了固定的值。虽然不够优雅,但这是最稳妥的方案。如果你的应用需要适配多个版本,建议封装一个工具方法来处理状态栏高度的获取,避免在不同版本上出现显示问题。

2. Window相关API的异常处理

在正常开发中,我们一般会使用windowStage.getMainWindowSync()来获取主窗口,这个方法在普通场景下是可以正常工作的。但是,如果你的元服务需要提供给FullScreenLaunchComponent使用,getMainWindowSync()会崩!!!!!

很多地方习惯性地使用getMainWindow()或者windowStage.getMainWindowSync(),结果在FullScreenLaunchComponent场景下直接崩溃,当时真的是一脸懵逼。(这也促使我们在后面的代码规范中,禁止所有对window方法的直接使用)

这是因为FullScreenLaunchComponent内部默认方式下,提供方无真正的窗口承载,所以无法正常获取Window对象。如果你没有进行try-catch的话,哦吼,崩掉。

3. 调试困难问题

调试非常困难,特别是你需要调试的东西在启动流程(如onCreateonWindowStageCreate)的时候,没法进行调试。因为每次被使用方拉起时,都会创建一个新的Embeddable进程,没办法提前断点,或者断点启动,所以根本没有办法进行启动流程的调试。

我们只能通过日志来一点点排查问题,非常痛苦。

解决方案:

只能一点点的加日志输出。虽然调试体验不好,但这是跨进程架构带来的限制,我们只能通过日志来排查问题。

4. UIContext获取异常

因为提供方无真正的窗口承载,所以第2点说的window异常的,实际上获取的UIContext的获取也是异常的。我们在代码中大量使用了getUIContext()来获取UIContext,结果在FullScreenLaunchComponent场景下可能获取不到正确的值,导致很多功能异常。

最后我们修改了大量的使用Context的地方,部分改用applicationContext,才解决了这个问题。

在FullScreenLaunchComponent场景下,尽量避免使用UIContext,优先使用applicationContextUIAbilityContext。如果必须使用UIContext,一定要做好异常处理。

5. 不支持富文本组件

部分功能使用了RichText组件来显示富文本内容,然后发现RichText组件在FullScreenLaunchComponent中不支持。淦!

解决方案:

阿弥陀佛,我们直接重写了一套,富文本组件,搞心态。

6. EmbeddableUIAbilityContext的特殊性

作为提供方,我们必须继承EmbeddableUIAbility,但是EmbeddableUIAbility的上下文,是和普通的UIAbility的上下文UIAbilityContext不一样的,使用的是EmbeddableUIAbilityContext,虽然是有继承关系,但在某些API的使用上可能存在差异。

我们在开发时,有些原本在普通UIAbility中能正常工作的代码,在EmbeddableUIAbility中就不行了,就是因为上下文类型的差异导致的。

在使用上下文相关API时,要注意EmbeddableUIAbilityContextUIAbilityContext的差异,做好兼容处理。

五、能力范围与限制

官方文档其实也列出很多限制场景,如下:

1. 不支持的能力

组件方面:

  • FullScreenLaunchComponent:不支持嵌套拉起(总不能套娃吧...)
  • EmbeddedComponent:不支持嵌套拉起
  • RichText:不支持富文本组件
  • FolderStack:不支持(需要和宿主方窗口形成联动)
  • XComponent:不支持
  • FormLink:不支持
  • HyperLink:不支持
  • ContextMenu:不支持

Node-API接口方面:

  • 页面间转场:不支持
  • 组件内隐式共享元素转场:不支持
  • componentUtils:不支持(获取的位置信息是EmbeddableUIAbility的WindowProxy的信息)
  • UIContext:不支持(提供方无真正的窗口承载)
  • DragController:不支持(依赖UIContext)
  • 注册自定义字体:不支持

2. 部分支持的能力

弹窗组件:

  • 警告弹窗、列表选择弹窗、自定义弹窗:部分支持
  • 若在FullScreenLaunchComponent中设置showInSubWindowtrue,弹窗将基于FullScreenLaunchComponent的宿主窗口对齐
  • 仅限于窗口对齐,其他能力可能受限

Navigation组件:

  • 部分支持
  • 如果FullScreenLaunchComponent未设置模态或沉浸式,Navigation无法扩展到安全区
  • 无法路由到宿主方的页面中

3. 其他约束

安全能力约束:

  • FullScreenLaunchComponent能力无法独立提供安全保障机制
  • 提供方应用需要结合使用其他ArkUI的能力进行安全保护
  • 如果存在安全方面的诉求,建议优先使用其他方案

嵌套约束:

  • FullScreenLaunchComponent暂不支持嵌套
  • 不支持A应用(UIAbility)->B应用(EmbeddableUIAbility)->C应用(EmbeddableUIAbility)这种嵌套能力依赖

事件处理机制约束:

  • FullScreenLaunchComponent不支持通用事件,会将事件经过坐标转换后传递给提供方EmbeddableUIAbility处理
  • 宿主进程与提供方进程的交互默认均是异步处理
  • 某些事件(如按键事件、焦点事件)支持同步处理,但支持超时等待机制

页面渲染效果体验约束:

  • 闪白现象:创建并拉起另一个进程是耗时的,使用方在等待过程中会感知到FullScreenLaunchComponent的背景色(默认是白色)
  • 渲染显示不同步现象:当使用方应用页面快速变化时(如横竖屏切换),会出现使用方页面渲染过程和FullScreenLaunchComponent组件中展示的内容不同步的情况

消减闪白问题的方法:

typescript 复制代码
FullScreenLaunchComponent({
  content: ColumnChild,
  appId: this.appId,
  options: {},
})
.backgroundColor('#F5F5F5')  // 根据提供方页面背景色设置,实现无跳变感知
.width('100%')
.height('100%')

六、总结

总的来说,FullScreenLaunchComponent是一个很强大的组件,使用方接入确实非常方便(苦了我们这些提供方),虽然存在一些限制和坑点,但FullScreenLaunchComponent的效果其实还不错的,有时候都感知不到是到了我们的元服务里面,以为就是自己~

好了,关于FullScreenLaunchComponent的内容我们就介绍到这里。虽然使用方接入很方便,但作为提供方在实际开发中确实有不少坑,希望这篇文章能帮助到正在开发或准备开发可被FullScreenLaunchComponent接入的元服务的开发者。

七、最后

因为篇幅原因,我们先到这,哈、下一篇还没想好写什么,如果你有想看的也可以在评论区,或者私信给我,马上写~咕咕咕。

如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏

相关推荐
威哥爱编程20 小时前
鸿蒙开发:那些让我熬秃头的“灵异事件”
harmonyos·arkts·arkui
威哥爱编程20 小时前
2026年的IT圈,看看谁在“裸泳”,谁在“吃肉”
后端·ai编程·harmonyos
奔跑的露西ly21 小时前
【HarmonyOS NEXT】进程与线程的理解
华为·harmonyos
REDcker1 天前
Android WebView 升级 - WebViewUpgrade 库使用详解
android·华为·harmonyos·webview
行者961 天前
Flutter跨平台开发:颜色选择器适配OpenHarmony
flutter·harmonyos·鸿蒙
baobao熊1 天前
【Harmony OS 6】IBest-ORM库使用详解(一)
华为·harmonyos
行者961 天前
Flutter鸿蒙跨平台开发:实现高性能可拖拽排序列表组件
flutter·harmonyos·鸿蒙
baobao熊1 天前
【Harmony OS 6】地图操作系列-路程规划
华为·harmonyos
行者961 天前
Flutter FloatingActionButton在OpenHarmony平台的深度适配与优化实践
flutter·harmonyos·鸿蒙