ArkUI-X微前端方案实战:鸿蒙多端应用的拆分与集成

进修的泡芙
发布于 2025-6-11 22:20
浏览
0收藏

引言

随着鸿蒙生态的快速发展,多端(手机、平板、车机、PC)协同的应用场景日益增多。传统单体应用架构在跨端开发中面临代码冗余、维护困难、迭代效率低等问题。ArkUI-X微前端方案通过主应用-子应用架构,将大型应用拆分为独立开发、独立部署的子应用,结合ArkUI-X的模块联邦能力,实现多端代码复用与灵活集成。本文以“电商多端商城”场景为例,手把手教你实现ArkUI-X微前端方案,附完整代码与关键逻辑解析。

一、场景背景与技术目标

1.1 需求场景

开发一个支持手机、平板、PC三端的鸿蒙电商应用,核心功能包括:
首页(商品列表、搜索)

商品详情页(多端适配的详情展示)

购物车(跨设备状态同步)

1.2 技术目标
独立开发:子应用(首页、详情、购物车)由不同团队维护;

跨端复用:核心组件(如商品卡片)在多端共享;

灵活集成:主应用动态加载子应用,支持按需分发;

状态共享:购物车数据在多端实时同步。

二、技术架构设计

ArkUI-X微前端方案采用主应用(Host)+ 子应用(SubApp)模式,通过以下核心机制实现集成:
模块 职责

主应用 负责全局路由、公共资源(如主题、导航栏)、子应用注册与加载
子应用 独立开发的功能模块(如首页、详情页),通过entry导出页面组件
模块联邦 主应用通过ModuleManager动态加载子应用代码包,实现跨应用代码共享
状态管理 使用AppStorage全局状态管理跨子应用数据(如购物车)
跨端适配 ArkUI-X的@MediaQuery与@Extend实现多端布局差异化

技术架构图:

[主应用] ←→ [模块联邦] ←→ [子应用A(首页)]

   └─[状态管理] ←───────┘

   └─[模块联邦] ←→ [子应用B(详情页)]

   └─[模块联邦] ←→ [子应用C(购物车)]

三、环境准备与项目初始化

3.1 开发环境
DevEco Studio 4.1+

鸿蒙SDK 4.1+(支持ArkUI-X)

Node.js 18+(用于子应用打包)

3.2 项目结构

micro-front-demo/
├── host-app/ # 主应用
├── entry/ # 主应用入口

├── modules/ # 子应用注册配置

└── oh-package.json5 # 主应用包配置

├── sub-app-home/ # 首页子应用
├── sub-app-detail/ # 详情页子应用
└── sub-app-cart/ # 购物车子应用

四、主应用实现:注册与加载子应用

4.1 注册子应用(host-app)

主应用通过ModuleManager注册子应用,指定子应用的入口模块与加载路径。

// host-app/entry/src/main/ets/pages/MainAbility.ets
import abilityAccessCtrl from ‘@ohos.abilityAccessCtrl’;
import moduleManager from ‘@ohos.moduleManager’;
import router from ‘@ohos.router’;

@Entry
@Component
struct MainAbility {
aboutToAppear() {
this.registerSubApps();
// 注册子应用

private async registerSubApps() {
try {
// 注册首页子应用(手机/平板/PC通用入口)
await moduleManager.registerModule({
moduleName: ‘sub-app-home’,
entry: ‘entry/src/main/ets/pages/HomePage.ets’, // 子应用入口文件
description: ‘电商首页模块’
});

  // 注册详情页子应用(支持多端适配)
  await moduleManager.registerModule({
    moduleName: 'sub-app-detail',
    entry: 'entry/src/main/ets/pages/DetailPage.ets',
    description: '商品详情模块'
  });

  // 注册购物车子应用(状态敏感模块)
  await moduleManager.registerModule({
    moduleName: 'sub-app-cart',
    entry: 'entry/src/main/ets/pages/CartPage.ets',
    description: '购物车模块'
  });

catch (err) {

  console.error('子应用注册失败:', err);

}

build() {
Column() {
// 全局导航栏
Navbar({ title: ‘鸿蒙商城’ })
.onClickBack(() => router.back())

  // 主应用路由占位符(子应用页面在此渲染)
  Router() {
    // 默认跳转首页
    HomePage()
      .path('/home')
      .build()
    
    // 子应用路由(通过moduleManager动态加载)
    // 实际由子应用注册后自动注册到主应用路由

.width(‘100%’)

  .height('100%')

}

4.2 公共资源管理(host-app)

主应用维护全局样式与主题,供子应用继承:

// host-app/entry/src/main/resources/base/profile/global_style.ets
@Extend(Text) function baseText() {
.fontSize(16)
.fontColor(‘#333’)
@Extend(Button) function primaryBtn() {

.width(120)
.height(40)
.backgroundColor(‘#007DFF’)
.fontColor(Color.White)
// 子应用可通过@Extend继承或覆盖

五、子应用实现:独立开发与导出

5.1 首页子应用(sub-app-home)

首页子应用负责商品列表展示,通过AppStorage同步全局搜索关键词:

// sub-app-home/entry/src/main/ets/pages/HomePage.ets
import appStorage from ‘@ohos.app.storage’;
import router from ‘@ohos.router’;

@Entry
@Component
struct HomePage {
@State keyword: string = ‘’;
@State goodsList: Array<{id: number, name: string, price: number}> = [];

aboutToAppear() {
// 监听全局搜索关键词(来自主应用或其他子应用)
appStorage.on(‘searchKeyword’, (value) => {
this.keyword = value;
this.fetchGoodsList();
});

this.fetchGoodsList();

// 模拟获取商品列表

private async fetchGoodsList() {
// 实际调用分布式接口获取多端数据
this.goodsList = [
id: 1, name: 手机(搜索词:${this.keyword}), price: 3999 },

id: 2, name: 平板(搜索词:${this.keyword}), price: 2999 }

];

build() {

Column() {
  // 子应用独立导航栏(可覆盖主应用样式)
  Navbar({ title: '商品列表' })
    .onEditQuery((query) => {
      this.keyword = query;
      appStorage.set('searchKeyword', query); // 同步到全局状态
    })

  // 商品列表(使用ArkUI-X多端适配布局)
  List() {
    ForEach(this.goodsList, (item) => {
      ListItem() {
        Row() {
          Image($r('app.media.goods_img'))
            .width(100)
            .height(100)
          Column() {
            Text(item.name)
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
            Text(¥${item.price})
              .fontSize(16)
              .fontColor('#FF0000')

.margin({ left: 10 })

.width(‘100%’)

        .padding(10)

})

.width(‘90%’)

  .layoutWeight(1)

.width(‘100%’)

.height('100%')

// 跳转到详情页(调用主应用路由)

private goToDetail(id: number) {
router.pushUrl({
url: ‘pages/DetailPage’,
params: { goodsId: id }
});
}

5.2 购物车子应用(sub-app-cart)

购物车子应用管理全局购物车状态,支持跨设备同步:

// sub-app-cart/entry/src/main/ets/pages/CartPage.ets
import appStorage from ‘@ohos.app.storage’;
import promptAction from ‘@ohos.promptAction’;

@Entry
@Component
struct CartPage {
@State cartItems: Array<{id: number, name: string, count: number}> = [];
@State totalPrice: number = 0;

aboutToAppear() {
// 初始化购物车数据(从全局状态加载)
this.loadCartData();

// 监听购物车变化(跨子应用更新)
appStorage.on('cartUpdated', (newItems) => {
  this.cartItems = newItems;
  this.calculateTotal();
});

// 加载购物车数据

private loadCartData() {
const defaultItems = [
id: 1, name: ‘手机’, count: 1 },

id: 2, name: ‘平板’, count: 2 }

];
this.cartItems = appStorage.get('cartItems', defaultItems);

// 计算总价

private calculateTotal() {
this.totalPrice = this.cartItems.reduce((sum, item) => sum + item.count * 1000, 0);
// 增加商品数量(触发全局状态更新)

private increaseCount(id: number) {
const newItems = this.cartItems.map(item => {
if (item.id === id) item.count += 1;
return item;
});
this.cartItems = newItems;
appStorage.set(‘cartItems’, newItems); // 同步到全局状态
appStorage.emit(‘cartUpdated’, newItems); // 通知其他子应用
build() {

Column() {
  Text('购物车')
    .fontSize(24)
    .fontWeight(FontWeight.Bold)
    .margin(10)

  List() {
    ForEach(this.cartItems, (item) => {
      ListItem() {
        Row() {
          Text(item.name)
            .fontSize(16)
          Blank()
          Text(¥${item.count * 1000})
            .fontSize(16)
            .fontColor('#FF0000')

.width(‘100%’)

        .padding(10)

.onClick(() => this.increaseCount(item.id))

    })

.width(‘90%’)

  .layoutWeight(1)

  Text(总价:¥${this.totalPrice})
    .fontSize(20)
    .fontWeight(FontWeight.Bold)
    .margin({ bottom: 20 })

.width(‘100%’)

.height('100%')

}

六、跨应用通信:状态共享与事件总线

6.1 全局状态管理(AppStorage)

使用AppStorage实现跨子应用数据共享,支持:
数据持久化(跨应用重启)

状态变更通知(监听on事件)

默认值回退(避免空值)

6.2 自定义事件总线(扩展方案)

对于复杂事件(如跨应用导航),可通过EventTarget实现自定义事件总线:

// host-app/entry/src/main/ets/utils/EventBus.ets
export class EventBus {
private static instance: EventBus;
private eventTarget = new EventTarget();

static getInstance() {
if (!this.instance) {
this.instance = new EventBus();
return this.instance;

// 发送事件

emit(eventName: string, data?: any) {
this.eventTarget.dispatchEvent(new CustomEvent(eventName, { detail: data }));
// 监听事件

on(eventName: string, callback: (data: any) => void) {
this.eventTarget.addEventListener(eventName, callback);
// 移除监听

off(eventName: string, callback: (data: any) => void) {
this.eventTarget.removeEventListener(eventName, callback);
}

// 使用示例(子应用触发主应用返回)
EventBus.getInstance().emit(‘backToHome’);

七、多端适配:响应式布局实践

ArkUI-X提供@MediaQuery与@Extend实现多端布局差异化,以商品卡片为例:

// 通用商品卡片组件(sub-app-home/components/GoodsCard.ets)
@Component
export struct GoodsCard {
@Prop goods: {name: string, price: number};

build() {
Column() {
Image($r(‘app.media.goods_img’))
.width(this.isPC ? 150 : 100)
.height(this.isPC ? 150 : 100)

  Text(this.goods.name)
    .fontSize(this.isPC ? 20 : 16)
  
  Text(¥${this.goods.price})
    .fontSize(this.isPC ? 18 : 14)
    .fontColor('#FF0000')

.width(this.isPC ? ‘30%’ : ‘100%’) // PC端一行显示3个,手机端占满宽度

.padding(this.isPC ? 20 : 10)
.margin({ right: this.isPC ? 10 : 0 })

// 媒体查询:判断当前设备类型

@MediaQuery(function() {
.isPC() {
…this.build()
})

八、总结与最佳实践

8.1 关键经验
子应用独立性:子应用需避免直接依赖主应用API,通过AppStorage和事件总线通信;

状态最小化:全局状态仅存储必要数据(如购物车),避免过度耦合;

多端测试:使用DevEco Studio的“多端预览”功能,验证不同设备的渲染效果;

性能优化:子应用代码包需控制在5MB以内(鸿蒙APK限制),大资源使用远程加载。

8.2 扩展方向
动态加载:结合鸿蒙的BundleManager实现子应用按需下载;

权限隔离:敏感操作(如支付)由主应用统一鉴权;

错误监控:主应用捕获子应用异常,上报至监控平台。

分类
收藏
回复
举报
回复
    相关推荐