问题描述
在 OpenHarmony 5.0.0.71 上安装应用后,iconfont 图标完全不显示。困扰了我好几天!!
根本原因
在 HarmonyOS/OpenHarmony 中使用自定义字体(包括 IconFont),必须在 ArkTS 侧显式注册字体 。仅靠 font.json 配置文件是不够的,这是与 Android/iOS 最大的区别。
根据 Ant Design Mobile RN 官方文档(Badge 组件示例),字体必须通过以下两步配置:
- 在
resources/base/profile/font.json中声明字体 - 在
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 ✅ 字体文件
关键要点
-
双重配置机制:
font.json:声明字体元数据Index.ets中的fontResourceByFontFamily:实际加载字体资源
-
路径一致性:
font.json中:"file": "rawfile/iconfont.ttf"(相对路径)Index.ets中:$rawfile("iconfont.ttf")(直接引用)
-
名称一致性:
font.json中的nameIndex.ets中fontResourceByFontFamily的键名- React Native 组件中的
fontFamily - 三者必须完全一致
-
不需要手动调用 API:
- 不需要在 EntryAbility.ets 中使用
font.registerFont() - 不需要在 Index.ets 的
aboutToAppear中手动注册 - 通过
fontResourceByFontFamily配置即可自动加载
- 不需要在 EntryAbility.ets 中使用
常见错误
❌ 错误做法 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. 安装到设备并测试图标显示
参考资料
-
Ant Design Mobile RN 官方文档:
- Badge 组件示例中的字体配置方法
- 明确要求在
Index.ets中使用fontResourceByFontFamily注册字体
-
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 只需将字体文件放入指定目录即可使用的方式完全不同。理解这一点是解决问题的关键。