ReactNative项目OpenHarmony三方库集成实战:@react-native-oh-tpl/react-native-fast-image

欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

📋 前言

在移动应用开发中,图片加载是最常见也是最核心的功能之一。无论是电商应用的商品展示、社交应用的用户头像,还是新闻资讯的图文混排,都离不开高效的图片加载组件。React Native 原生的 Image 组件虽然能满足基本需求,但在性能优化、缓存管理、加载状态监听等方面存在不足。@react-native-oh-tpl/react-native-fast-image 是一个高性能的图片加载组件,专为 React Native 跨平台应用设计,支持 Android、iOS 和 HarmonyOS 三端,提供了优先级加载、智能缓存、加载状态监听等高级功能。

🎯 库简介

基本信息

  • 库名称 : @react-native-oh-tpl/react-native-fast-image
  • 版本信息 :
    • 8.6.3-0.4.17: 支持 RN 0.72 版本
  • 官方仓库: https://github.com/react-native-oh-library/react-native-fast-image
  • 主要功能 :
    • 📷 高性能图片加载,支持 GIF 和 WebP 格式
    • 💾 智能内存缓存和磁盘缓存管理
    • 📊 图片加载进度监听
    • 🎨 多种缩放模式支持
    • 🔄 图片预加载功能
    • 🎯 支持自定义请求头

为什么选择 FastImage?

特性 React Native Image FastImage
图片缓存 ⚠️ 基础支持 ✅ 智能缓存
加载优先级 ❌ 不支持 ✅ 支持
加载进度 ❌ 不支持 ✅ 支持
GIF/WebP ⚠️ 部分支持 ✅ 完整支持
内存管理 ⚠️ 手动管理 ✅ 自动优化
预加载 ❌ 不支持 ✅ 支持
HarmonyOS ❌ 不支持 ✅ 完整支持

兼容性验证

在以下环境验证通过:

  • RNOH : 0.72.96; SDK : HarmonyOS 6.0.0 Release SDK; IDE : DevEco Studio 6.0.0.858; ROM: 6.0.0.112

📦 安装步骤

1. 使用 npm 安装

在项目根目录执行以下命令,本文基于 RN 0.72.90 版本开发:

未使用ohos版本的fast-image,尝试过程中遇到了c++版本编译的问题,正在排查问题中。

bash 复制代码
# RN 0.72 版本推荐使用
npm install @react-native-oh-tpl/react-native-fast-image@8.6.3-0.4.17-rc.1

# 或者使用 yarn
yarn add @react-native-oh-tpl/react-native-fast-image@8.6.3-0.4.17-rc.1

2. 验证安装

安装完成后,检查 package.json 文件,应该能看到新增的依赖:

json 复制代码
{
  "dependencies": {
    "@react-native-oh-tpl/react-native-fast-image": "8.6.3-0.4.17-rc.1",
    // ... 其他依赖
  }
}

🔧 HarmonyOS 平台配置 ⭐

由于 HarmonyOS 暂不支持 AutoLink,需要手动配置原生端代码。本文采用直接链接源码的方式。

1. 在工程根目录的 oh-package.json5 添加 overrides 字段

打开 harmony/oh-package.json5,添加以下配置:

json5 复制代码
{
  // ... 其他配置
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

2. 引入原生端代码

目前 DevEco Studio 不支持通过源码引入外部 module,我们推荐使用直接链接源码的方式,将源码通过操作改成 harmony 工程的内部模块。

步骤 1:复制源码到 harmony 工程根目录

<RN工程>/node_modules/@react-native-oh-tpl/react-native-fast-image/harmony 目录下的源码 fast_image 复制到 harmony(鸿蒙壳工程)工程根目录下。

步骤 2:在 build-profile.json5 添加模块

打开 harmony/build-profile.json5,添加以下模块:

json5 复制代码
modules: [
  // ... 其他模块
  {
    name: 'fast_image',
    srcPath: './fast_image',
  }
]

💡 提示 :如果存在 build-profile.template.json5 文件,也需要同步添加上述模块配置。

步骤 3:修改 fast_image/oh-package.json5

打开 harmony/fast_image/oh-package.json5,修改 react-native-openharmony 版本与项目版本一致:

json5 复制代码
{
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}
步骤 4:修改fast_image目录下ts.ts名称

将ts.ts调整为ts.ets

步骤 5:在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json5 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  "@react-native-oh-tpl/react-native-fast-image": "file:../fast_image"
}
步骤 6:同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

3. 配置 CMakeLists 和引入 FastImagePackage

修改 entry/src/main/cpp/CMakeLists.txt
cmake 复制代码
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 FastImage 模块(源码方式)
+ add_subdirectory("${OH_MODULES}/@react-native-oh-tpl/react-native-fast-image/src/main/cpp" ./fast-image)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 FastImage 库
+ target_link_libraries(rnoh_app PUBLIC rnoh_fast_image)
修改 entry/src/main/cpp/PackageProvider.cpp
cpp 复制代码
#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "FastImagePackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        + std::make_shared<FastImagePackage>(ctx),
    };
}

4. 在 ArkTs 侧引入 FastImagePackage

打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:

typescript 复制代码
import type { RNPackageContext, RNPackage } from 'rnoh/ts';
+ import { FastImagePackage } from '@react-native-oh-tpl/react-native-fast-image/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    // ... 其他包
    + new FastImagePackage(ctx),
  ];
}

5. 同步并运行

点击 DevEco Studio 右上角的 sync 按钮,然后编译运行即可。

📖 API 详解

🔷 核心属性(Props)

FastImage 组件提供了丰富的属性配置,以下是详细的 API 说明:

1. source - 图片源配置 ⭐

source 是 FastImage 最核心的属性,用于配置图片的加载源。

typescript 复制代码
source: {
  uri: string;           // 图片 URL(必填)
  headers?: object;      // 自定义请求头(可选)
  priority?: 'low' | 'normal' | 'high';  // 加载优先级(可选)
  cache?: 'immutable' | 'web' | 'cacheOnly';  // 缓存策略(可选)
}
参数 类型 必填 说明 HarmonyOS 支持
uri string 远程图片的 URL 地址
headers object 自定义 HTTP 请求头,如 { Authorization: 'token' }
priority enum 加载优先级:lownormalhigh
cache enum 缓存策略:immutablewebcacheOnly

使用示例

typescript 复制代码
// 基础用法
<FastImage
  source={{ uri: 'https://example.com/image.jpg' }}
  style={{ width: 200, height: 200 }}
/>

// 带请求头
<FastImage
  source={{
    uri: 'https://example.com/protected-image.jpg',
    headers: { Authorization: 'Bearer token123' }
  }}
  style={{ width: 200, height: 200 }}
/>
2. defaultSource - 默认占位图

当图片加载中或加载失败时显示的默认图片。

typescript 复制代码
defaultSource: number;
类型 说明 HarmonyOS 支持
number 通过 require() 引入的本地图片

使用示例

typescript 复制代码
<FastImage
  source={{ uri: 'https://example.com/image.jpg' }}
  defaultSource={require('./placeholder.png')}
  style={{ width: 200, height: 200 }}
/>

⚠️ 注意defaultSource 只支持本地图片,不支持网络图片 URL。

3. resizeMode - 缩放模式 🎨

控制图片如何适应容器尺寸,提供多种缩放模式。

typescript 复制代码
resizeMode: 'contain' | 'cover' | 'stretch' | 'center';
模式 说明 效果描述
contain 等比缩放,完整显示 图片完整显示在容器内,可能有留白
cover 等比缩放,填满容器 图片填满容器,可能被裁剪
stretch 拉伸填满 图片拉伸以填满容器,可能变形
center 居中显示 图片原尺寸居中显示,超出部分裁剪

使用示例

typescript 复制代码
import FastImage from 'react-native-fast-image';

<FastImage
  source={{ uri: 'https://example.com/image.jpg' }}
  resizeMode={FastImage.resizeMode.cover}
  style={{ width: 200, height: 200 }}
/>
4. tintColor - 颜色着色 🎨

将图片中所有非透明像素替换为指定颜色,常用于图标着色。

typescript 复制代码
tintColor: string | number;
类型 说明 示例
string 颜色字符串 '#FF0000''red''rgb(255,0,0)'
number 十六进制颜色值 0xFFFF0000

使用示例

typescript 复制代码
<FastImage
  source={{ uri: 'https://example.com/icon.png' }}
  tintColor="#007AFF"
  style={{ width: 24, height: 24 }}
/>

🔷 加载状态回调(Events)

FastImage 提供了完整的图片加载生命周期回调,方便开发者监控加载状态。

1. onLoadStart - 加载开始

图片开始加载时触发。

typescript 复制代码
onLoadStart: () => void;

使用示例

typescript 复制代码
<FastImage
  source={{ uri: imageUrl }}
  onLoadStart={() => {
    console.log('图片开始加载');
    setLoading(true);
  }}
/>
2. onProgress - 加载进度 📊

图片加载过程中持续触发,可用于显示加载进度条。

typescript 复制代码
onProgress: (event: OnProgressEvent) => void;

interface OnProgressEvent {
  nativeEvent: {
    loaded: number;   // 已加载字节数
    total: number;    // 总字节数
  };
}

使用示例

typescript 复制代码
<FastImage
  source={{ uri: imageUrl }}
  onProgress={(e) => {
    const progress = Math.round((e.nativeEvent.loaded / e.nativeEvent.total) * 100);
    console.log(`加载进度: ${progress}%`);
    setProgress(progress);
  }}
/>
3. onLoad - 加载成功 ✅

图片加载成功时触发,返回图片的尺寸信息。

typescript 复制代码
onLoad: (event: OnLoadEvent) => void;

interface OnLoadEvent {
  nativeEvent: {
    width: number;   // 图片原始宽度
    height: number;  // 图片原始高度
  };
}

使用示例

typescript 复制代码
<FastImage
  source={{ uri: imageUrl }}
  onLoad={(e) => {
    console.log(`图片加载成功,尺寸: ${e.nativeEvent.width}x${e.nativeEvent.height}`);
    setLoading(false);
    setImageSize({ width: e.nativeEvent.width, height: e.nativeEvent.height });
  }}
/>
4. onError - 加载失败 ❌

图片加载失败时触发。

typescript 复制代码
onError: () => void;

使用示例

typescript 复制代码
<FastImage
  source={{ uri: imageUrl }}
  onError={() => {
    console.log('图片加载失败');
    setLoading(false);
    setError(true);
  }}
/>
5. onLoadEnd - 加载结束

图片加载结束时触发(无论成功或失败)。

typescript 复制代码
onLoadEnd: () => void;

使用示例

typescript 复制代码
<FastImage
  source={{ uri: imageUrl }}
  onLoadEnd={() => {
    console.log('图片加载结束');
    setLoading(false);
  }}
/>

🔷 静态方法(Static Methods)

FastImage 提供了实用的静态方法,用于缓存管理。

1. FastImage.preload - 图片预加载 🔄 ⚠️

⚠️ HarmonyOS 不支持 : 此方法在 HarmonyOS 上未实现,调用会报错 Failed to download the task. Code: 8

提前加载图片到缓存中,后续显示时可直接从缓存读取。

typescript 复制代码
FastImage.preload(sources: Source[]): void;

interface Source {
  uri: string;
  headers?: object;
}

iOS/Android 使用示例

typescript 复制代码
import FastImage from 'react-native-fast-image';

// 预加载多张图片(仅 iOS/Android 支持)
FastImage.preload([
  { uri: 'https://example.com/image1.jpg' },
  { uri: 'https://example.com/image2.jpg' },
]);

HarmonyOS 替代方案

typescript 复制代码
// HarmonyOS 上直接加载图片,不使用预加载
<FastImage
  source={{ uri: 'https://example.com/image.jpg' }}
  style={{ width: 200, height: 200 }}
/>
2. FastImage.clearMemoryCache - 清除内存缓存 🧹

清除所有图片的内存缓存,释放内存空间。

typescript 复制代码
FastImage.clearMemoryCache(): Promise<void>;

使用示例

typescript 复制代码
import FastImage from 'react-native-fast-image';

// 清除内存缓存
const clearCache = async () => {
  try {
    await FastImage.clearMemoryCache();
    console.log('内存缓存已清除');
  } catch (error) {
    console.error('清除内存缓存失败:', error);
  }
};
3. FastImage.clearDiskCache - 清除磁盘缓存 🧹

清除所有图片的磁盘缓存,释放存储空间。

typescript 复制代码
FastImage.clearDiskCache(): Promise<void>;

使用示例

typescript 复制代码
import FastImage from 'react-native-fast-image';

// 清除磁盘缓存
const clearDiskCache = async () => {
  try {
    await FastImage.clearDiskCache();
    console.log('磁盘缓存已清除');
  } catch (error) {
    console.error('清除磁盘缓存失败:', error);
  }
};

// 清除所有缓存
const clearAllCache = async () => {
  await Promise.all([
    FastImage.clearMemoryCache(),
    FastImage.clearDiskCache(),
  ]);
  console.log('所有缓存已清除');
};

💻 完整代码示例

下面是一个完整的示例,展示了 FastImage 的所有 API 应用场景:

typescript 复制代码
import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  TouchableOpacity,
  SafeAreaView,
  ActivityIndicator,
} from 'react-native';
import FastImage, { OnLoadEvent, OnProgressEvent } from 'react-native-fast-image';

function FastImageDemo() {
  const [loading, setLoading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [error, setError] = useState(false);
  const [imageSize, setImageSize] = useState({ width: 0, height: 0 });

  const imageUrl = 'https://res8.vmallres.com/pimages/uomcdn/CN/pms/202205/gbom/6941487259298/428_428_D7BFF22D4678EB68440F914B352214C4mp_tds.png';

  // 注意:FastImage.preload() 在 HarmonyOS 上不支持
  // 如需预加载功能,请在 iOS/Android 平台使用

  // 清除内存缓存
  const handleClearMemoryCache = async () => {
    await FastImage.clearMemoryCache();
    console.log('内存缓存已清除');
  };

  // 清除磁盘缓存
  const handleClearDiskCache = async () => {
    await FastImage.clearDiskCache();
    console.log('磁盘缓存已清除');
  };

  return (
    <SafeAreaView style={styles.container}>
      <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContent}>
        <Text style={styles.title}>🚀 FastImage 图片加载演示</Text>

        {/* 1. 基础图片加载 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>1️⃣ 基础图片加载</Text>
          <Text style={styles.description}>展示最基本的图片加载功能</Text>
          <FastImage
            style={styles.image}
            source={{ uri: imageUrl }}
            resizeMode={FastImage.resizeMode.contain}
          />
        </View>

        {/* 2. 带加载状态的图片 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>2️⃣ 加载状态监听</Text>
          <Text style={styles.description}>展示加载进度和状态回调</Text>
          <View style={styles.imageContainer}>
            <FastImage
              style={styles.image}
              source={{ uri: imageUrl }}
              resizeMode={FastImage.resizeMode.cover}
              defaultSource={require('./assets/placeholder.png')}
              onLoadStart={() => {
                setLoading(true);
                setError(false);
                setProgress(0);
                console.log('onLoadStart: 图片开始加载');
              }}
              onProgress={(e: OnProgressEvent) => {
                const loaded = e.nativeEvent.loaded;
                const total = e.nativeEvent.total;
                const percent = Math.round((loaded / total) * 100);
                setProgress(percent);
                console.log(`onProgress: 已加载 ${loaded}/${total} (${percent}%)`);
              }}
              onLoad={(e: OnLoadEvent) => {
                setLoading(false);
                setImageSize({
                  width: e.nativeEvent.width,
                  height: e.nativeEvent.height,
                });
                console.log(`onLoad: 加载成功,尺寸 ${e.nativeEvent.width}x${e.nativeEvent.height}`);
              }}
              onError={() => {
                setLoading(false);
                setError(true);
                console.log('onError: 加载失败');
              }}
              onLoadEnd={() => {
                console.log('onLoadEnd: 加载结束');
              }}
            />
            {loading && (
              <View style={styles.loadingOverlay}>
                <ActivityIndicator size="large" color="#007AFF" />
                <Text style={styles.progressText}>{progress}%</Text>
              </View>
            )}
            {error && (
              <View style={styles.errorOverlay}>
                <Text style={styles.errorText}>❌ 加载失败</Text>
              </View>
            )}
          </View>
          <Text style={styles.infoText}>图片尺寸: {imageSize.width}x{imageSize.height}</Text>
        </View>

        {/* 3. 不同缩放模式 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>3️⃣ 缩放模式对比</Text>
          <Text style={styles.description}>展示不同的 resizeMode 效果</Text>
          <View style={styles.resizeModeContainer}>
            <View style={styles.resizeModeItem}>
              <FastImage
                style={styles.smallImage}
                source={{ uri: imageUrl }}
                resizeMode={FastImage.resizeMode.contain}
              />
              <Text style={styles.resizeModeLabel}>contain</Text>
            </View>
            <View style={styles.resizeModeItem}>
              <FastImage
                style={styles.smallImage}
                source={{ uri: imageUrl }}
                resizeMode={FastImage.resizeMode.cover}
              />
              <Text style={styles.resizeModeLabel}>cover</Text>
            </View>
            <View style={styles.resizeModeItem}>
              <FastImage
                style={styles.smallImage}
                source={{ uri: imageUrl }}
                resizeMode={FastImage.resizeMode.stretch}
              />
              <Text style={styles.resizeModeLabel}>stretch</Text>
            </View>
            <View style={styles.resizeModeItem}>
              <FastImage
                style={styles.smallImage}
                source={{ uri: imageUrl }}
                resizeMode={FastImage.resizeMode.center}
              />
              <Text style={styles.resizeModeLabel}>center</Text>
            </View>
          </View>
        </View>

        {/* 4. 图片着色 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>4️⃣ 图片着色效果</Text>
          <Text style={styles.description}>使用 tintColor 为图片着色</Text>
          <View style={styles.tintColorContainer}>
            <View style={styles.tintColorItem}>
              <FastImage
                style={styles.iconImage}
                source={{ uri: imageUrl }}
                tintColor="#FF0000"
              />
              <Text style={styles.tintColorLabel}>红色</Text>
            </View>
            <View style={styles.tintColorItem}>
              <FastImage
                style={styles.iconImage}
                source={{ uri: imageUrl }}
                tintColor="#00FF00"
              />
              <Text style={styles.tintColorLabel}>绿色</Text>
            </View>
            <View style={styles.tintColorItem}>
              <FastImage
                style={styles.iconImage}
                source={{ uri: imageUrl }}
                tintColor="#0000FF"
              />
              <Text style={styles.tintColorLabel}>蓝色</Text>
            </View>
            <View style={styles.tintColorItem}>
              <FastImage
                style={styles.iconImage}
                source={{ uri: imageUrl }}
                tintColor="#007AFF"
              />
              <Text style={styles.tintColorLabel}>主题色</Text>
            </View>
          </View>
        </View>

        {/* 5. 静态方法 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>5️⃣ 缓存管理</Text>
          <Text style={styles.description}>使用静态方法管理缓存(注意:预加载在 HarmonyOS 上不支持)</Text>
          <View style={styles.buttonContainer}>
            <TouchableOpacity style={styles.button} onPress={handleClearMemoryCache}>
              <Text style={styles.buttonText}>清除内存缓存</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.button} onPress={handleClearDiskCache}>
              <Text style={styles.buttonText}>清除磁盘缓存</Text>
            </TouchableOpacity>
          </View>
        </View>

        {/* 6. 带请求头的图片 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>6️⃣ 自定义请求头</Text>
          <Text style={styles.description}>支持携带自定义 HTTP 请求头</Text>
          <FastImage
            style={styles.image}
            source={{
              uri: imageUrl,
              headers: {
                'User-Agent': 'FastImageDemo/1.0',
              },
            }}
            resizeMode={FastImage.resizeMode.cover}
          />
          <Text style={styles.infoText}>已添加自定义 User-Agent 请求头</Text>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  scrollView: {
    flex: 1,
  },
  scrollContent: {
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#333',
    textAlign: 'center',
    marginBottom: 30,
  },
  section: {
    backgroundColor: '#fff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 8,
  },
  description: {
    fontSize: 14,
    color: '#666',
    marginBottom: 12,
  },
  image: {
    width: '100%',
    height: 200,
    borderRadius: 8,
    backgroundColor: '#f0f0f0',
  },
  imageContainer: {
    position: 'relative',
  },
  loadingOverlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(255, 255, 255, 0.8)',
    borderRadius: 8,
  },
  progressText: {
    marginTop: 8,
    fontSize: 16,
    fontWeight: 'bold',
    color: '#007AFF',
  },
  errorOverlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(255, 255, 255, 0.8)',
    borderRadius: 8,
  },
  errorText: {
    fontSize: 16,
    color: '#FF3B30',
  },
  infoText: {
    fontSize: 12,
    color: '#999',
    marginTop: 8,
    textAlign: 'center',
  },
  resizeModeContainer: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'space-between',
  },
  resizeModeItem: {
    width: '48%',
    alignItems: 'center',
    marginBottom: 12,
  },
  smallImage: {
    width: '100%',
    height: 100,
    borderRadius: 8,
    backgroundColor: '#f0f0f0',
  },
  resizeModeLabel: {
    marginTop: 4,
    fontSize: 12,
    color: '#666',
  },
  tintColorContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
  },
  tintColorItem: {
    alignItems: 'center',
  },
  iconImage: {
    width: 50,
    height: 50,
    borderRadius: 8,
    backgroundColor: '#f0f0f0',
  },
  tintColorLabel: {
    marginTop: 4,
    fontSize: 12,
    color: '#666',
  },
  buttonContainer: {
    gap: 10,
  },
  button: {
    backgroundColor: '#007AFF',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
});

export default FastImageDemo;

⚠️ 注意事项与最佳实践

1. 性能优化建议

  • 使用预加载 : 对于即将展示的图片,使用 FastImage.preload() 提前加载到缓存
  • 合理使用缓存: 根据业务场景选择合适的缓存策略
  • 及时清理缓存 : 在适当时机调用 clearMemoryCache()clearDiskCache() 释放资源
  • 使用占位图 : 设置 defaultSource 提升用户体验

2. 图片加载最佳实践

typescript 复制代码
// ✅ 推荐:完整的加载状态处理
<FastImage
  source={{ uri: imageUrl }}
  defaultSource={require('./placeholder.png')}
  onLoadStart={() => setLoading(true)}
  onLoad={() => setLoading(false)}
  onError={() => setError(true)}
  onLoadEnd={() => setLoading(false)}
/>

// ❌ 不推荐:缺少状态处理
<FastImage source={{ uri: imageUrl }} />

3. HarmonyOS 特殊处理

  • 确保原生代码正确链接
  • 注意 source.prioritysource.cache 属性暂不支持
  • 在 HarmonyOS 设备上测试图片加载效果
  • 注意不同设备的屏幕适配

4. 遗留问题

问题 状态 Issue
source.cache 属性不支持 ⚠️ 待修复 issue#57
source.priority 属性不支持 ⚠️ 待修复 issue#56

🧪 测试验证

1. 执行构建命令

package.json中新增启动命令

复制代码
  "scripts": {
    "harmony": "react-native bundle-harmony --dev",
  },
bash 复制代码
npm run harmony

2. 测试要点

  • 基础加载: 确认图片能正常加载显示
  • 加载状态 : 验证 onLoadStartonProgressonLoadonErroronLoadEnd 回调
  • 缩放模式 : 测试不同 resizeMode 的显示效果
  • 图片着色 : 验证 tintColor 效果
  • 缓存管理: 测试预加载和缓存清除功能
  • 占位图 : 验证 defaultSource 显示效果

3. 常见问题排查

问题 1: 图片不显示

  • 检查 source.uri 是否正确
  • 确认原生代码是否正确链接
  • 查看控制台是否有错误信息

问题 2: 加载进度不更新

  • 确认服务器是否支持返回 Content-Length
  • 检查 onProgress 回调是否正确绑定

问题 3: 缓存清除无效

  • 确认 clearMemoryCacheclearDiskCache 是否正确调用
  • 检查是否有其他地方重新加载了图片

问题 4: 预加载报错 Failed to download the task. Code: 8

  • ⚠️ 原因 : FastImage.preload() 方法在 HarmonyOS 上未实现
  • 解决: 避免使用预加载功能,直接加载图片即可

问题 5: 占位图不显示

  • ⚠️ 原因 : defaultSource 在 HarmonyOS 上需要使用特殊格式
  • 解决 : 使用 asset:// 协议,详见下方说明

4. HarmonyOS 特殊限制说明 ⚠️

4.1 预加载功能不支持

FastImage.preload() 在 HarmonyOS 上未实现,调用会报错:

typescript 复制代码
// ❌ 错误用法(HarmonyOS 不支持)
FastImage.preload([
  { uri: 'https://example.com/image1.jpg' },
  { uri: 'https://example.com/image2.jpg' },
]);

// ✅ 正确做法:直接加载图片
<FastImage
  source={{ uri: 'https://example.com/image.jpg' }}
  style={{ width: 200, height: 200 }}
/>
4.2 占位图使用特殊格式

defaultSource 在 HarmonyOS 上不支持 require() 方式,需要使用 asset:// 协议:

步骤 1: 将占位图放到 HarmonyOS 资源目录

复制代码
harmony/entry/src/main/resources/rawfile/placeholder.png

步骤 2 : 使用 asset:// 协议引用

typescript 复制代码
// ❌ 错误用法(require 返回 number,HarmonyOS 不支持)
<FastImage
  source={{ uri: imageUrl }}
  defaultSource={require('./placeholder.png')}
/>

// ✅ 正确用法(使用 asset:// 协议)
<FastImage
  source={{ uri: imageUrl }}
  defaultSource="asset://placeholder.png"
  style={{ width: 200, height: 200 }}
/>

💡 提示 : asset:// 协议会自动映射到 rawfile 目录下的文件。

📊 API 支持情况总览

属性支持

属性 说明 HarmonyOS 支持
source.uri 图片 URL
source.headers 自定义请求头
source.priority 加载优先级
source.cache 缓存策略
defaultSource 默认占位图 ✅ (特殊格式)
resizeMode 缩放模式
tintColor 颜色着色
onLoadStart 加载开始回调
onProgress 加载进度回调
onLoad 加载成功回调
onError 加载失败回调
onLoadEnd 加载结束回调

静态方法支持

方法 说明 HarmonyOS 支持
FastImage.preload 预加载图片
FastImage.clearMemoryCache 清除内存缓存
FastImage.clearDiskCache 清除磁盘缓存
相关推荐
朵朵奇葩向阳开#2 小时前
【无标题】
javascript·typescript·ruby·laravel·perl·composer
暖阳常伴2 小时前
全栈vue/react+node.js,云服务器windows部署全流程
vue.js·react.js·node.js
网络点点滴2 小时前
组件通信-provide和inject
javascript·vue.js·ecmascript
大雷神2 小时前
HarmonyOS APP<玩转React>开源教程十二:ModuleCard 模块卡片组件
react.js·开源·harmonyos
早點睡3902 小时前
ReactNative项目OpenHarmony三方库集成实战:@react-native-oh-tpl/masked-view
javascript·react native·react.js
摸鱼的春哥2 小时前
Agent教程20:更适合编程工具的记忆方案——情景摘要
前端·javascript·后端
架构师李肯3 小时前
TypeScript与React全栈实战:从架构搭建到项目部署,避开常见陷阱
react.js·架构·typescript
Hamm11 小时前
不想花一分钱玩 OpenClaw?来,一起折腾这个!
javascript·人工智能·agent
Setsuna_F_Seiei11 小时前
AI 对话应用之 JS 的流式接口数据处理
前端·javascript·ai编程