HarmonyOS鸿蒙Next中RN如何在不改业务代码的前提下,不同平台引入不同的库

HarmonyOS鸿蒙Next中RN如何在不改业务代码的前提下,不同平台引入不同的库 【问题描述】:我Android端使用的rn-fetch-blob,现在鸿蒙化的库是react-native-blob-util,涉及到的代码太多了,使用平台判断来做逻辑处理不太行,有没有便捷一点的方式?

【版本信息】:

0.77的RN

“rn-fetch-blob”: “0.12.0” ,

@react-native-ohos/react-native-blob-util”: “0.19.8”

【尝试解决方案】:

尝试在一个文件中封装逻辑判断,业务代码中引入他,还是不行,运行会报错。


更多关于HarmonyOS鸿蒙Next中RN如何在不改业务代码的前提下,不同平台引入不同的库的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

尊敬的开发者,您好,关于您反馈的问题,可以参考下面的解决方案:

可以在@react-native-ohos/react-native-blob-util三方库的package.json中添加如下配置,进行重定向至rn-fetch-blob中:

{
  "harmony": {
    "alias": "rn-fetch-blob"
  }
}

完成上述配置后,当您的平台为Harmony OS平台时,引用rn-fetch-blob库时则会重定向至配置了harmony-alias的库,即@react-native-ohos/react-native-blob-util

重定向说明文档(此文档为gitcode上的说明文档):RN 三方库补丁化移植

更多关于HarmonyOS鸿蒙Next中RN如何在不改业务代码的前提下,不同平台引入不同的库的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


使用Metro 平台扩展名

Metro 是 React Native 的打包工具,它原生支持基于文件扩展名的平台特定代码。利用这个机制,可以为 HarmonyOS 创建专属的文件版本。

核心原理

通过配置 Metro,使其在打包 HarmonyOS 产物时,优先加载带有 .harmony.js 扩展名的文件,从而加载特定平台的实现。

https://gitcode.com/OpenHarmony-RN/ohos_react_native/blob/main/docs/zh-cn/03-%E8%B0%83%E6%B5%8B/%E8%B0%83%E8%AF%95%E8%B0%83%E6%B5%8B.md

你的场景在 RN 鸿蒙化里其实很常见:

Android:
rn-fetch-blob

HarmonyOS:
@react-native-ohos/react-native-blob-util

如果业务代码里已经有大量:

import RNFetchBlob from 'rn-fetch-blob'

确实不可能一个个改。

最推荐方案:Alias 映射(基本不改业务代码)

直接让:

import RNFetchBlob from 'rn-fetch-blob'

在鸿蒙编译时实际加载:

@react-native-ohos/react-native-blob-util

Metro配置

metro.config.js 中增加:

const path = require('path');

module.exports = {
  resolver: {
    extraNodeModules: {
      'rn-fetch-blob': path.resolve(
        __dirname,
        'node_modules/@react-native-ohos/react-native-blob-util'
      ),
    },
  },
};

这样业务代码无需修改。


更稳的方案:自定义兼容层

创建:

src/libs/RNFetchBlob/index.js

内容:

import { Platform } from 'react-native';

let BlobModule;

if (Platform.OS === 'harmony') {
  BlobModule = require('@react-native-ohos/react-native-blob-util').default;
} else {
  BlobModule = require('rn-fetch-blob').default;
}

export default BlobModule;

然后在 Babel 中配置别名:

module-resolver

把:

rn-fetch-blob

映射到:

src/libs/RNFetchBlob

配置示例:

plugins: [
  [
    'module-resolver',
    {
      alias: {
        'rn-fetch-blob': './src/libs/RNFetchBlob',
      },
    },
  ],
];

这样业务代码也完全不用改。


为什么你封装后还是报错

大概率是下面两种情况之一:

情况1

文件顶部直接 import

import RNFetchBlob from 'rn-fetch-blob'

即使:

if (Platform.OS === 'harmony')

也没用。

因为:

Bundle阶段已经解析模块

找不到就直接报错。


情况2

Harmony侧根本没安装

rn-fetch-blob

Metro解析失败。

例如:

import RNFetchBlob from 'rn-fetch-blob'

编译时:

Unable to resolve module rn-fetch-blob

根本到不了运行时判断。


如果是 RN 0.77

我更推荐:

Babel Alias
+
module-resolver

方案。

因为:

  • 不改业务代码
  • 不需要大量 Platform.OS 判断
  • Android继续用 rn-fetch-blob
  • Harmony自动切换 react-native-blob-util

这种方式也是很多大型 RN 鸿蒙化项目(几万行以上代码)的常见做法。

需要注意

还要确认:

@react-native-ohos/react-native-blob-util

与:

rn-fetch-blob 0.12.0

API 是否完全兼容。

虽然大部分接口保持一致,但以下能力可能存在差异:

  • fs
  • fetch
  • session
  • androidDownloadManager
  • media scanner
  • content uri

如果项目大量使用这些高级能力,建议先做一轮 API 差异验证。

对于你这种已有大量历史代码的项目,我建议优先采用 Babel Alias 映射方案,基本可以做到:

业务代码 0 改动
Android 正常
Harmony 自动切换实现

这是成本最低、维护性最好的做法。

这种场景建议不要在每个业务文件里写平台判断,而是在依赖解析层做一次别名或垫片。

如果业务代码里大量 import/require 的还是 rn-fetch-blob,可以保留这个模块名,然后在鸿蒙构建的 Metro 配置里把 rn-fetch-blob alias 到一个本地 shim 文件;shim 里再统一 export @react-native-ohos/react-native-blob-util。这样业务侧 import 路径不变,只改构建配置和一个适配文件。

思路大概是:

  1. 新建一个 rn-fetch-blob.ohos.ts 或 src/shims/rn-fetch-blob.ts,里面把 react-native-blob-util 的能力按旧库常用 API 重新导出。
  2. 在 metro.config.js 的 resolver.extraNodeModules 或 resolveRequest 里,针对 HarmonyOS 构建把 ‘rn-fetch-blob’ 指到这个 shim。
  3. 只在 shim 里处理 API 差异,例如路径常量、download/config/fetch 返回值差异,不要把差异扩散到业务层。
  4. 如果两边 API 不完全兼容,先覆盖业务实际用到的子集;否则直接 alias 到新库可能仍会因为字段名或返回结构不同运行时报错。

一句话:入口用“模块别名 + 平台 shim”,业务代码继续写 rn-fetch-blob;适配差异集中在 shim 文件里。

在HarmonyOS Next中,可利用React Native的Platform.select()方法,或通过文件命名约定(如MyModule.harmony.ts)自动匹配平台。也可在metro.config.js中通过resolve.alias映射不同平台的库文件,业务代码无需改动。

利用 Metro 的平台文件扩展名即可零侵入替换。

  1. 创建两个封装文件,如 src/utils/BlobUtil.js(原有)和 src/utils/BlobUtil.harmony.js(鸿蒙版)。
    • BlobUtil.js 中直接 export * from 'rn-fetch-blob'
    • BlobUtil.harmony.jsexport * from '@react-native-ohos/react-native-blob-util'
  2. 修改工程根目录 metro.config.js,在 resolver.sourceExts 最前面加入 'harmony',例如:
    resolver: {
      sourceExts: ['harmony', 'js', 'jsx', 'ts', 'tsx', ...],
    },
    
  3. 业务代码统一导入封装文件 import BlobUtil from '@/utils/BlobUtil',无需任何平台判断。Metro 打包时会自动优先选择 .harmony.js 后缀文件。

如果之前因直接判平台并 require 报错,本质上是因为两个 native module 被同时引入导致冲突或未注册。该方案通过 Metro 编译时按平台分离,彻底避免此问题。

回到顶部