在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、前置思考

1.1 一个包打天下 = 每个设备都背冗余

一个同时支持手机/平板/车机/手表的应用,如果把所有资源打进一个 HAP:

📱 手机用户: 下载了车机 UI 资源、手表表盘素材 → 浪费 30MB
🚗 车机用户: 下载了手机专属图标、平板高清图 → 浪费 25MB
⌚ 手表用户: 下载了全量 3D 素材 → 内存溢出直接闪退

每个设备只用 20% 的资源,却下载了 100% 的包——启动慢、占存储、体验差。

1.2 资源冗余的代价

❌ 包体积膨胀: 手机 App 50MB,其中 30MB 是其他设备的资源
❌ 启动变慢: HAP 解压全量资源,首帧延迟 +500ms
❌ 内存压力: 小内存设备加载大资源 → OOM
❌ 更新低效: 每次发版全量重下,流量浪费

1.3 鸿蒙的答案:资源条件分包 + 按需加载

四级策略:
① 设备特征识别: 运行时知道"我是谁"(deviceType/密度/能力)
② 资源条件分包: 按设备形态拆分资源(基础包 + 设备专属包)
③ 动态下载: 用到才下载(HSP 动态加载 / 按需下载)
④ 冗余剔除: 打包时排除非目标设备资源

二、核心原理

2.1 资源分包体系

应用包结构:
├── entry (基础 HAP)          ← 所有设备公共代码+公共资源
├── feature_phone (HSP)       ← 手机专属资源(大图/高清素材)
├── feature_car (HSP)         ← 车机专属资源(大触控UI)
├── feature_wearable (HSP)    ← 穿戴专属资源(表盘/微交互)
└── feature_tablet (HSP)      ← 平板专属资源(分栏布局素材)

安装时: 只装基础 HAP + 当前设备对应的 HSP
运行时: 按需动态加载其他 HSP(可选功能)

2.2 设备特征识别

识别维度:
① 设备形态: deviceInfo.deviceType
② 屏幕密度: deviceInfo.screenDensity(按密度加载图片)
③ 能力差异: canIUse(按能力加载功能模块)
④ 内存等级: 设备内存分级(低内存设备用精简资源)

识别结果 → 决定"加载哪个资源包" + "用哪份资源"

2.3 动态下载机制

按需下载三模式:
① HSP 动态加载: 功能模块按需 require
② 资源动态下载: 大素材(地图/3D)用到才下载
③ 条件加载: 满足条件才加载(车机才加载车机模块)

下载策略:
  首次进入功能 → 触发下载 → 缓存到本地 → 下次直读
  弱网 → 暂停 + 断点续传
  预加载 → 空闲 WiFi 下预取下一模块

三、源码/API 深度解析

3.1 设备特征识别

import { deviceInfo } from '@kit.BasicServicesKit';

// 识别设备特征 → 决定资源加载策略
class DeviceProfile {
  static getProfile(): ResourceProfile {
    const type: string = deviceInfo.deviceType;
    const density: number = deviceInfo.screenDensity;
    const memory: number = deviceInfo.memorySize;  // MB

    return {
      type: type,                 // phone/tablet/car/wearable/tv
      density: density,           // 160/240/320/480
      lowMemory: memory < 2048,   // 低内存设备
      // 按形态决定加载的资源集
      resourceSet: type === 'wearable' ? 'minimal'
        : type === 'car' ? 'car_ui'
        : type === 'tablet' ? 'tablet_hd'
        : 'standard'
    };
  }
}

3.2 资源条件分包(module 配置)

// 1. 基础包 (entry) module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",           // 入口模块(所有设备必装)
    "deviceTypes": ["phone", "tablet", "car", "wearable", "tv"]
  }
}

// 2. 车机专属包 (feature_car) module.json5
{
  "module": {
    "name": "feature_car",
    "type": "feature",         // 特性模块(按设备形态安装)
    "deviceTypes": ["car"]     // 只在车机安装
  }
}

// 3. 穿戴专属包 (feature_wearable)
{
  "module": {
    "name": "feature_wearable",
    "type": "feature",
    "deviceTypes": ["wearable"]
  }
}

3.3 HSP 动态加载

// 动态加载功能模块(用到才 require)
import { moduleManager } from '@kit.AbilityKit';

// 运行时按需加载车机模块
async function loadCarModule(): Promise<void> {
  // 只在车机上加载车机专属功能
  if (deviceInfo.deviceType !== 'car') { return; }

  try {
    // 动态导入 HSP 模块
    const carModule = await moduleManager.importModule('feature_car');
    carModule.startCarNavigation();   // 调用模块能力
  } catch (e) {
    LoggerUtil.error(TAG, '车机模块加载失败: ' + JSON.stringify(e));
  }
}

3.4 资源动态下载与冗余剔除

import { request } from '@kit.BasicServicesKit';

// 1. 大资源按需下载(地图包/3D 素材)
async function downloadResource(url: string, dest: string): Promise<void> {
  const context = getContext(this) as common.UIAbilityContext;
  // 检查本地缓存
  const cached = await FileUtil.exists(dest);
  if (cached) { return; }   // 已有缓存直接读

  // 后台下载(支持断点续传)
  const task = await request.downloadFile(context, {
    url: url,
    filePath: dest,
    background: true
  });
  await task.on('complete', () => {
    LoggerUtil.info(TAG, '资源下载完成: ' + dest);
  });
}

// 2. 打包冗余剔除(构建配置)
// build-profile.json5 中按设备剔除无用资源:
// {
//   "products": [
//     { "name": "phone",  "excludeResources": ["car_assets", "wear_assets"] },
//     { "name": "car",    "excludeResources": ["phone_wallpapers", "wear_assets"] }
//   ]
// }

四、企业级实战落地

4.1 按需加载落地清单

阶段 动作 验收
资源盘点 梳理各设备资源清单 冗余资源清单完成
分包设计 基础包+设备专属 HSP 包结构合理
按需加载 HSP 动态 require 用到才加载
动态下载 大资源断点下载 弱网可恢复
冗余剔除 构建排除非目标资源 包体积显著下降

4.2 完整示例:分设备包体积对比

@Entry
@ComponentV2
struct ResourceOnDemandDemo {
  @Local deviceType: string = 'phone';
  @Local sizeCompare: SizeRow[] = [];
  @Local strategyNote: string = '';

  aboutToAppear(): void {
    this.deviceType = deviceInfo.deviceType;
    this.initCompare();
  }

  private initCompare(): void {
    // 全量打包 vs 按需加载 对比
    this.sizeCompare = [
      { type: '手机', fullSize: 86, onDemand: 42, saved: 44 },
      { type: '车机', fullSize: 86, onDemand: 38, saved: 48 },
      { type: '平板', fullSize: 86, onDemand: 52, saved: 34 },
      { type: '手表', fullSize: 86, onDemand: 21, saved: 65 }
    ];

    const notes: string[] = [];
    notes.push('当前设备: ' + this.deviceType);
    notes.push('资源包: entry(基础) + feature_' + this.deviceType + '(专属)');
    notes.push('冗余剔除: 已排除 ' + this.excludedCount() + ' 个非本设备资源');
    notes.push('动态加载: 大资源按需下载,弱网断点续传');
    this.strategyNote = notes.join('\n');
  }

  private excludedCount(): number {
    const total = 12;  // 假设共 12 个设备专属资源
    const mine = 3;    // 本设备只用 3 个
    return total - mine;
  }

  build() {
    Column({ space: 12 }) {
      Text('📦 多端资源按需加载').fontSize(20).fontWeight(FontWeight.Bold)
      Text('当前设备: ' + this.deviceType).fontSize(14).fontColor('#4FC3F7')

      // 包体积对比表
      ForEach(this.sizeCompare, (r: SizeRow) => {
        Row({ space: 8 }) {
          Text(r.type).fontSize(12).width(60)
          Column({ space: 4 }) {
            Progress({ value: r.onDemand, total: r.fullSize }).width('100%').color('#4FC3F7')
            Text('全量 ' + r.fullSize + 'MB → 按需 ' + r.onDemand + 'MB (省 ' + r.saved + 'MB)')
              .fontSize(10).fontColor('rgba(255,255,255,0.6)')
          }.layoutWeight(1)
        }
        .width('100%')
      }, (r: SizeRow) => r.type)

      if (this.strategyNote !== '') {
        Text(this.strategyNote).fontSize(12).lineHeight(20)
          .fontColor('rgba(255,255,255,0.7)').width('100%')
          .padding(12).backgroundColor('rgba(79,195,247,0.08)').borderRadius(8)
      }
    }
    .width('100%').height('100%').padding(16)
    .backgroundColor('#0D1B2A')
  }
}

4.3 包体积优化效果

设备 全量包 按需加载后 节省
手机 86MB 42MB 51%
车机 86MB 38MB 56%
平板 86MB 52MB 40%
手表 86MB 21MB 76%

五、问题排查与性能优化

问题 原因 解决
手表 OOM 全量资源加载 最小资源集
启动慢 解压全量资源 条件分包
功能模块缺失 HSP 未加载 运行时 importModule
下载失败 弱网无重试 断点续传 + 队列重试
资源加载错包 设备特征识别错误 deviceType 兜底判断
更新全量重下 无差分更新 资源版本化 + 增量更新

5.1 按需加载优化要点

1. 设备特征一次识别、全局缓存(避免反复系统调用)
2. 动态加载结果缓存(加载过的 HSP 不再重复 require)
3. 下载队列管理(并行 2~3 个,弱网降速)
4. 空闲预加载(WiFi + 充电时预取下一模块)
5. 资源版本校验(本地缓存版本 vs 服务端版本)

六、高阶总结与最佳实践

  1. 分设备打包:基础包 + 设备专属 HSP,让每个设备只装自己的。
  2. 运行时识别:deviceType + 密度 + 内存,识别决定加载策略。
  3. 用才加载:HSP 动态 require + 大资源按需下载,别让用户为不用买单。
  4. 打包剔除:构建时排除非目标设备资源,从源头减负。
  5. 下载体验:断点续传 + 弱网降级 + 空闲预加载,让按需加载无感。

一句话记住:按需加载 = 特征识别(我是谁)+ 条件分包(装谁的)+ 动态加载(用才下)+ 冗余剔除(删没用的)——每个设备只背自己需要的资源,包小、启动快、不 OOM。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐