react native for OpenHarmony iconfont 图标不显示问题

问题描述

在 OpenHarmony 5.0.0.71 上安装应用后,iconfont 图标完全不显示。困扰了我好几天!!

根本原因

在 HarmonyOS/OpenHarmony 中使用自定义字体(包括 IconFont),必须在 ArkTS 侧显式注册字体 。仅靠 font.json 配置文件是不够的,这是与 Android/iOS 最大的区别。

根据 Ant Design Mobile RN 官方文档(Badge 组件示例),字体必须通过以下两步配置:

  1. 在 resources/base/profile/font.json 中声明字体
  2. 在 Index.ets 的 RNApp 配置中通过 fontResourceByFontFamily 显式注册

正确的修复方案

1. 字体文件位置

确保字体文件在正确位置:

复制代码
harmony/entry/src/main/resources/rawfile/iconfont.ttf

2. 创建字体配置文件

位置 :harmony/entry/src/main/resources/base/profile/font.json

内容:

json 复制代码
{
  "font": [
    {
      "name": "iconfont",
      "file": "rawfile/iconfont.ttf"
    }
  ]
}

关键点:

  • file 路径必须是 rawfile/iconfont.ttf(相对于 resources 目录)
  • name 字段必须与后续 React Native 中使用的 fontFamily 一致

3. 在 Index.ets 中注册字体(关键步骤)

位置 :harmony/entry/src/main/ets/pages/Index.ets

修改内容:

typescript 复制代码
RNApp({
  rnInstanceConfig: {
    createRNPackages,
    enableNDKTextMeasuring: true,
    enableBackgroundExecutor: false,
    enableCAPIArchitecture: true,
    arkTsComponentNames: [],
    // ⚠️ 关键:必须显式注册字体资源
    fontResourceByFontFamily: {
      'iconfont': $rawfile("iconfont.ttf"),
    }
  },
  // ...其他配置
})

说明:

  • fontResourceByFontFamily 是必需的,这是 HarmonyOS 加载自定义字体的核心机制
  • 键名 'iconfont' 必须与 font.json 中的 name 字段一致
  • $rawfile("iconfont.ttf") 直接引用 rawfile 目录下的文件

4. React Native 组件使用

IconFont.tsx:

typescript 复制代码
const IconFont: React.FC<IconFontProps> = ({ name, size = 16, color = '#000', style }) => {
  const iconCode = IconFontMap[name];

  // fontFamily 必须与 font.json 和 Index.ets 中注册的名称完全一致
  const fontFamily = Platform.select({
    harmony: 'iconfont',
    android: 'iconfont',
    ios: 'iconfont',
    default: 'iconfont',
  });

  return (
    <Text
      style={[
        {
          fontFamily: fontFamily,
          fontSize: size,
          color: color,
          includeFontPadding: false,
          textAlignVertical: 'center',
        },
        style,
      ]}
      allowFontScaling={false}>
      {iconCode}
    </Text>
  );
};

最终目录结构

复制代码
harmony/entry/src/main/
├── ets/pages/
│   └── Index.ets  ✅ 在此注册 fontResourceByFontFamily
├── resources/
│   ├── base/profile/
│   │   └── font.json  ✅ 字体配置文件
│   └── rawfile/
│       └── iconfont.ttf  ✅ 字体文件

关键要点

  1. 双重配置机制:

    • font.json:声明字体元数据
    • Index.ets 中的 fontResourceByFontFamily:实际加载字体资源
  2. 路径一致性:

    • font.json 中:"file": "rawfile/iconfont.ttf"(相对路径)
    • Index.ets 中:$rawfile("iconfont.ttf")(直接引用)
  3. 名称一致性:

    • font.json 中的 name
    • Index.ets 中 fontResourceByFontFamily 的键名
    • React Native 组件中的 fontFamily
    • 三者必须完全一致
  4. 不需要手动调用 API:

    • 不需要在 EntryAbility.ets 中使用 font.registerFont()
    • 不需要在 Index.ets 的 aboutToAppear 中手动注册
    • 通过 fontResourceByFontFamily 配置即可自动加载

常见错误

❌ 错误做法 1:只配置 font.json

json 复制代码
// 只有这个配置是不够的
{
  "font": [{"name": "iconfont", "file": "rawfile/iconfont.ttf"}]
}

❌ 错误做法 2:font.json 路径错误

json 复制代码
{
  "font": [
    {"name": "iconfont", "file": "font/iconfont.ttf"}  // ❌ 错误路径
  ]
}

❌ 错误做法 3:缺少 fontResourceByFontFamily

typescript 复制代码
RNApp({
  rnInstanceConfig: {
    createRNPackages,
    enableNDKTextMeasuring: true,
    // ❌ 缺少 fontResourceByFontFamily 配置
    arkTsComponentNames: []
  },
})

✅ 正确做法:双重配置

json 复制代码
// font.json
{
  "font": [{"name": "iconfont", "file": "rawfile/iconfont.ttf"}]
}
typescript 复制代码
// Index.ets
RNApp({
  rnInstanceConfig: {
    // ...
    fontResourceByFontFamily: {
      'iconfont': $rawfile("iconfont.ttf"),
    }
  },
})

测试步骤

bash 复制代码
# 1. 清理并重新构建
cd harmony
hvigorw clean
hvigorw assembleHap

# 2. 安装到设备并测试图标显示

参考资料

  1. Ant Design Mobile RN 官方文档:

    • Badge 组件示例中的字体配置方法
    • 明确要求在 Index.ets 中使用 fontResourceByFontFamily 注册字体
  2. OpenHarmony 字体系统:

    • font.json:声明性配置
    • fontResourceByFontFamily:实际资源绑定

版本信息

  • OpenHarmony: 5.0.0.71
  • React Native OpenHarmony: 0.72.5
  • Ant Design Mobile RN: 3.2.0

总结

核心原理:HarmonyOS 的字体加载采用"声明 + 注册"的双重机制,缺一不可。这与 Android/iOS 只需将字体文件放入指定目录即可使用的方式完全不同。理解这一点是解决问题的关键。

相关推荐
程序猿追8 小时前
kotlin-retry 接入鸿蒙后,怎样确认它真的会停止重试
开发语言·kotlin·harmonyos
懿路向前12 小时前
HarmonyOS 粒子特效实战:emitter.size 是双刃剑:粒子精确定位 [0,0] 与条带随机出生(HarmonyOS)
华为·harmonyos
马剑威(威哥爱编程)12 小时前
【共创稿事节】HarmonyOS 7 Agent 开发实战 04:云端 RAG 搭企业私有知识库问答
人工智能·华为·harmonyos
贾伟康13 小时前
【晨迹相机|20】HarmonyOS ArkTS AppGallery 发布复查实战:核对包名、版本、设备、素材和离线声明
harmonyos·arkts·appgallery·发布审核·上架复查
特立独行的猫a13 小时前
用仓颉写桌面应用:从 npx 建工程到串口实时示波器
开源·harmonyos·tauri·仓颉·cj-tarui
懿路向前15 小时前
HarmonyOS 粒子特效实战:马赛克切块提速 17.6×~38×:desiredRegion 重复读盘与一次解码管线(HarmonyOS)
华为·harmonyos
天府云创17 小时前
Agentic开发时代到来——鸿蒙PC三大原生开发工具公测
华为·操作系统·harmonyos·鸿蒙系统·cli·deveco·agentic
程序猿追17 小时前
Fleks 鸿蒙适配:从八个小球看实体和组件的变化
华为·harmonyos
Sunny_GMF17 小时前
Markdown 导出 HTML 实战:2.6MB 编辑器快照如何瘦身 71%(DOM 净化 + CSSOM 运行时裁剪)
编辑器·html·ai编程·harmonyos
m0_7381858217 小时前
Flutter 鸿蒙化实战:the_apple_sign_in 适配 OpenHarmony,Apple 登录
flutter·华为·harmonyos·鸿蒙