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 清除磁盘缓存
相关推荐
华科易迅18 分钟前
Vue如何集成封装Axios
前端·javascript·vue.js
不是az20 分钟前
CSS知识点记录
前端·javascript·css
昵称暂无11 小时前
.NET 高级开发 | i18n 原理、实现一个 i18n 框架
javascript·c#·.net
h_jQuery1 小时前
vue使用gm-crypto对数据进行sm4加密处理
前端·javascript·vue.js
阿赛工作室2 小时前
Vue中onBeforeUnmount不触发的解决方案
前端·javascript·vue.js
浩星2 小时前
electron系列1:Electron不是玩具,为什么桌面应用需要它?
前端·javascript·electron
疯笔码良3 小时前
【Vue】自适应布局
javascript·vue.js·css3
浩星3 小时前
electron系列2:搭建专业Electron开发环境
javascript·typescript·electron
酒鼎4 小时前
学习笔记(12-02)事件循环 - 实战案例 —⭐
前端·javascript
小恰学逆向4 小时前
【爬虫JS逆向之旅】某球网参数“md5__1038”逆向
javascript·爬虫