鸿蒙React Native跨平台实践:完整项目构建与交付指南

# 鸿蒙React Native跨平台实践:完整项目构建与交付指南


从零开始构建React Native鸿蒙跨平台应用并成功交付开源项目,需要系统的流程规划和工程技术实践。本文将提供从项目初始化到开源交付的完整技术指南。


## 项目初始化与环境配置


### 工程结构规划


```bash

# 项目目录结构

my-harmony-app/

├── README.md

├── package.json

├── android/                    # Android原生代码

├── ios/                        # iOS原生代码

├── harmony/                    # 鸿蒙原生代码

├── src/

│   ├── components/            # 共享组件

│   ├── screens/              # 页面组件

│   ├── services/             # 业务服务

│   ├── utils/                # 工具函数

│   ├── styles/               # 样式文件

│   └── navigation/           # 导航配置

├── docs/                     # 项目文档

├── scripts/                  # 构建脚本

└── tests/                    # 测试文件

```


```json

// package.json 核心配置

{

  "name": "my-harmony-app",

  "version": "1.0.0",

  "description": "跨平台应用示例",

  "main": "src/index.js",

  "scripts": {

    "start": "react-native start",

    "android": "react-native run-android",

    "ios": "react-native run-ios",

    "harmony": "react-native harmony",

    "harmony:build": "react-native harmony build",

    "harmony:run": "react-native harmony run",

    "harmony:clean": "cd harmony && ohpm clean",

    "test": "jest",

    "lint": "eslint src --ext .js,.jsx,.ts,.tsx",

    "type-check": "tsc --noEmit",

    "build:all": "npm run android && npm run harmony:build",

    "precommit": "npm run lint && npm run type-check"

  },

  "dependencies": {

    "@ohos/react-native-harmony": "^0.72.6",

    "react": "18.2.0",

    "react-native": "0.72.6",

    "@react-navigation/native": "^6.1.9",

    "@react-navigation/stack": "^6.3.20",

    "@react-navigation/bottom-tabs": "^6.5.8",

    "react-native-safe-area-context": "^4.8.2",

    "react-native-gesture-handler": "^2.14.0",

    "react-native-reanimated": "^3.5.4",

    "react-native-screens": "^3.27.0",

    "axios": "^1.6.2",

    "redux": "^4.2.1",

    "@reduxjs/toolkit": "^1.9.7",

    "react-redux": "^8.1.3"

  },

  "devDependencies": {

    "@babel/core": "^7.23.2",

    "@babel/runtime": "^7.23.2",

    "@react-native/eslint-config": "^0.73.2",

    "@types/react": "^18.2.45",

    "@types/react-native": "^0.72.8",

    "@types/react-test-renderer": "^18.0.7",

    "@typescript-eslint/eslint-plugin": "^6.14.0",

    "@typescript-eslint/parser": "^6.14.0",

    "babel-jest": "^29.7.0",

    "eslint": "^8.55.0",

    "jest": "^29.7.0",

    "metro-react-native-babel-preset": "^0.76.8",

    "prettier": "^3.1.1",

    "react-test-renderer": "18.2.0",

    "typescript": "^5.3.3"

  },

  "engines": {

    "node": ">=18.0.0",

    "npm": ">=9.0.0"

  },

  "keywords": [

    "react-native",

    "harmonyos",

    "cross-platform",

    "mobile"

  ],

  "author": "Your Name",

  "license": "MIT",

  "repository": {

    "type": "git",

    "url": "https://github.com/username/my-harmony-app.git"

  },

  "bugs": {

    "url": "https://github.com/username/my-harmony-app/issues"

  },

  "homepage": "https://github.com/username/my-harmony-app#readme"

}

```


### 鸿蒙环境配置


```js

// scripts/setup-harmony.js

const { execSync } = require('child_process');

const fs = require('fs');

const path = require('path');


console.log('? 开始配置鸿蒙开发环境...');


// 检查必要工具

const requiredTools = ['node', 'npm', 'ohpm'];

const missingTools = [];


requiredTools.forEach(tool => {

  try {

    execSync(`${tool} --version`, { stdio: 'ignore' });

  } catch {

    missingTools.push(tool);

  }

});


if (missingTools.length > 0) {

  console.error(`❌ 缺少必要工具: ${missingTools.join(', ')}`);

  console.log('请先安装以下工具:');

  console.log('- Node.js: https://nodejs.org/');

  console.log('- ohpm: https://ohpm.openharmony.cn/');

  process.exit(1);

}


// 创建鸿蒙目录结构

const harmonyDir = path.join(__dirname, '..', 'harmony');

const requiredDirs = [

  'entry',

  'entry/src/main',

  'entry/src/main/js',

  'entry/src/main/js/components',

  'entry/src/main/js/services',

  'entry/src/main/resources'

];


requiredDirs.forEach(dir => {

  const fullPath = path.join(harmonyDir, dir);

  if (!fs.existsSync(fullPath)) {

    fs.mkdirSync(fullPath, { recursive: true });

    console.log(`? 创建目录: ${dir}`);

  }

});


// 生成鸿蒙配置文件

const configFiles = {

  'oh-package.json5': `{

  "license": "MIT",

  "description": "HarmonyOS原生模块",

  "devDependencies": {},

  "dependencies": {

    "@ohos/hvigor-ohos-plugin": "3.0.6"

  }

}`,

  'build-profile.json5': `{

  "app": {

    "signingConfigs": [],

    "products": [

      {

        "name": "default",

        "signingConfig": "default",

        "compileSdkVersion": 9,

        "compatibleSdkVersion": 9

      }

    ],

    "targets": [

      {

        "name": "default",

        "applyToProducts": ["default"]

      }

    ]

  },

  "modules": [

    {

      "name": "entry",

      "srcPath": "./entry",

      "targets": [

        {

          "name": "default",

          "applyToProducts": ["default"]

        }

      ]

    }

  ]

}`,

  'hvigorfile.ts': `import { appTasks } from '@ohos/hvigor-ohos-plugin';


export default {

  system: appTasks,

  plugins: []

};`

};


Object.entries(configFiles).forEach(([filename, content]) => {

  const filePath = path.join(harmonyDir, filename);

  if (!fs.existsSync(filePath)) {

    fs.writeFileSync(filePath, content);

    console.log(`? 生成文件: ${filename}`);

  }

});


console.log('✅ 鸿蒙环境配置完成!');

console.log('运行以下命令开始开发:');

console.log('1. cd harmony && ohpm install');

console.log('2. npm run harmony');

```


## 跨平台架构设计


### 平台适配层


```typescript

// src/platform/index.ts

import { Platform } from 'react-native';


export type PlatformType = 'ios' | 'android' | 'harmony' | 'web';


class PlatformAdapter {

  static getPlatform(): PlatformType {

    const platform = Platform.OS;

    

    // 鸿蒙平台检测

    if (platform === 'harmony' || 

        (typeof ohos !== 'undefined' && ohos.system)) {

      return 'harmony';

    }

    

    return platform as PlatformType;

  }

  

  static isHarmony(): boolean {

    return this.getPlatform() === 'harmony';

  }

  

  static isNative(): boolean {

    const platform = this.getPlatform();

    return platform === 'ios' || platform === 'android' || platform === 'harmony';

  }

  

  // 平台特定样式

  static createPlatformStyles(styles: Record): T {

    const platform = this.getPlatform();

    

    return {

      ...styles.base,

      ...(styles[platform] || {}),

      ...(this.isHarmony() ? styles.harmony : {})

    };

  }

  

  // 平台特定实现

  static withPlatformImplementation(

    implementations: Record T>

  ): T {

    const platform = this.getPlatform();

    const implementation = implementations[platform] || implementations.default;

    

    if (!implementation) {

      throw new Error(`No implementation for platform: ${platform}`);

    }

    

    return implementation();

  }

}


// 使用示例

const styles = PlatformAdapter.createPlatformStyles({

  base: {

    flex: 1,

    backgroundColor: '#FFFFFF'

  },

  ios: {

    paddingTop: 44

  },

  android: {

    paddingTop: 24

  },

  harmony: {

    paddingTop: 32,

    // 鸿蒙特有样式

    backdropFilter: 'blur(10px)'

  }

});


export default PlatformAdapter;

```


### 原生模块桥接


```typescript

// src/native/HarmonyBridge.ts

import { NativeModules, Platform } from 'react-native';


interface HarmonyNativeModule {

  // 设备信息

  getDeviceInfo(): Promise;

  // 振动反馈

  vibrate(duration: number): Promise;

  // 获取鸿蒙能力

  getCapabilities(): Promise;

  // 文件系统操作

  readFile(path: string): Promise;

  writeFile(path: string, content: string): Promise;

}


interface DeviceInfo {

  deviceId: string;

  deviceType: 'phone' | 'tablet' | 'wearable' | 'tv';

  brand: string;

  model: string;

  apiLevel: number;

}


interface HarmonyCapabilities {

  hasDistributedData: boolean;

  hasArkUI: boolean;

  hasHapticFeedback: boolean;

  hasEdgeGesture: boolean;

}


class HarmonyBridge {

  private static instance: HarmonyBridge;

  private module: HarmonyNativeModule | null = null;

  

  private constructor() {

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

      this.module = NativeModules.HarmonyModule as HarmonyNativeModule;

    }

  }

  

  static getInstance(): HarmonyBridge {

    if (!HarmonyBridge.instance) {

      HarmonyBridge.instance = new HarmonyBridge();

    }

    return HarmonyBridge.instance;

  }

  

  // 安全的方法调用

  async callMethod(

    methodName: keyof HarmonyNativeModule,

    ...args: any[]

  ): Promise {

    if (!this.module) {

      console.warn(`Harmony模块不可用,跳过方法调用: ${methodName}`);

      return this.getFallbackValue(methodName, args);

    }

    <"s3.j9k5.org.cn"><"f7.j9k5.org.cn"><"z9.j9k5.org.cn">

    try {

      const method = this.module[methodName];

      if (typeof method !== 'function') {

        throw new Error(`方法不存在: ${methodName}`);

      }

      

      return await method(...args);

    } catch (error) {

      console.error(`调用Harmony原生方法失败 ${methodName}:`, error);

      return this.getFallbackValue(methodName, args);

    }

  }

  

  private getFallbackValue(methodName: string, args: any[]): any {

    const fallbacks: Record any> = {

      getDeviceInfo: () => ({

        deviceId: 'simulated_device',

        deviceType: 'phone',

        brand: 'Generic',

        model: 'Simulator',

        apiLevel: 8

      }),

      vibrate: () => {

        // 使用React Native的振动API

        if (NativeModules.Vibration) {

          NativeModules.Vibration.vibrate(args[0] || 50);

        }

      }

    };

    

    return fallbacks[methodName] ? fallbacks[methodName]() : null;

  }

  

  // 便捷方法

  async getDeviceInfo(): Promise {

    return this.callMethod('getDeviceInfo') || this.getFallbackValue('getDeviceInfo', []);

  }

  

  async triggerVibration(duration = 50): Promise {

    await this.callMethod('vibrate', duration);

  }

}


export default HarmonyBridge;

```


## 开发流程与工具集成


### 自动化构建脚本


```bash

#!/bin/bash

# scripts/build-all.sh


set -e


echo "? 开始构建跨平台应用..."


# 参数处理

BUILD_MODE="debug"

PLATFORM="all"

CLEAN_BUILD=false


while [[ $# -gt 0 ]]; do

  case $1 in

    --mode)

      BUILD_MODE="$2"

      shift 2

      ;;

    --platform)

      PLATFORM="$2"

      shift 2

      ;;

    --clean)

      CLEAN_BUILD=true

      shift

      ;;

    *)

      echo "未知参数: $1"

      exit 1

      ;;

  esac

done


# 清理构建

if [ "$CLEAN_BUILD" = true ]; then

  echo "? 清理构建缓存..."

  rm -rf android/app/build

  rm -rf ios/build

  rm -rf harmony/build

  npm run clean

fi


# 安装依赖

echo "? 安装依赖..."

npm ci


# 类型检查

echo "? 类型检查..."

npm run type-check


# 代码检查

echo "? 代码检查..."

npm run lint


# 运行测试

echo "? 运行测试..."

npm test -- --passWithNoTests


# 平台特定构建

build_platform() {

  case $1 in

    android)

      echo "? 构建Android应用..."

      cd android && ./gradlew assemble${BUILD_MODE^} || exit 1

      cd ..

      ;;

    ios)

      echo "? 构建iOS应用..."

      cd ios && xcodebuild \

        -workspace MyHarmonyApp.xcworkspace \

        -scheme MyHarmonyApp \

        -configuration ${BUILD_MODE^} \

        -destination 'generic/platform=iOS' \

        build || exit 1

      cd ..

      ;;

    harmony)

      echo "? 构建鸿蒙应用..."

      npm run harmony:build || exit 1

      ;;

    all)

      build_platform android

      build_platform ios

      build_platform harmony

      ;;

    *)

      echo "未知平台: $1"

      exit 1

      ;;

  esac

}


build_platform $PLATFORM


echo "✅ 构建完成!"

echo "构建产物位置:"

[ "$PLATFORM" = "all" ] || [ "$PLATFORM" = "android" ] && echo "- Android: android/app/build/outputs/apk/"

[ "$PLATFORM" = "all" ] || [ "$PLATFORM" = "ios" ] && echo "- iOS: ios/build/"

[ "$PLATFORM" = "all" ] || [ "$PLATFORM" = "harmony" ] && echo "- Harmony: harmony/build/outputs/"

```


### 持续集成配置


```yaml

# .github/workflows/ci-cd.yml

name: CI/CD Pipeline


on:

  push:

    branches: [main, develop]

  pull_request:

    branches: [main]


jobs:

  test:

    runs-on: ubuntu-latest

    strategy:

      matrix:

        node-version: [18.x, 20.x]

    

    steps:

    - uses: actions/checkout@v3

    

    - name: Use Node.js ${{ matrix.node-version }}

      uses: actions/setup-node@v3

      with:

        node-version: ${{ matrix.node-version }}

        cache: 'npm'

    

    - name: Install dependencies

      run: npm ci

    

    - name: Type check

      run: npm run type-check

    

    - name: Lint code

      run: npm run lint

    

    - name: Run tests

      run: npm test -- --passWithNoTests --coverage

    

    - name: Upload coverage

      uses: codecov/codecov-action@v3

      with:

        file: ./coverage/lcov.info

    

  build-android:

    runs-on: ubuntu-latest

    needs: test

    

    steps:

    - uses: actions/checkout@v3

    

    - name: Set up JDK 17

      uses: actions/setup-java@v3

      with:

        java-version: '17'

        distribution: 'temurin'

    

    - name: Install dependencies

      run: npm ci

    

    - name: Build Android

      run: |

        cd android

        ./gradlew assembleDebug

      env:

        ANDROID_HOME: ${{ secrets.ANDROID_HOME }}

    

    - name: Upload APK

      uses: actions/upload-artifact@v3

      with:

        name: android-apk

        path: android/app/build/outputs/apk/debug/

    

  build-harmony:

    runs-on: ubuntu-latest

    needs: test

    if: false # 鸿蒙构建在CI中需要特殊环境

    

    steps:

    - uses: actions/checkout@v3

    

    - name: Setup Harmony SDK

      run: |

        # 这里需要配置鸿蒙SDK环境

        echo "Harmony构建需要特殊配置"

    

    - name: Build Harmony

      run: npm run harmony:build

```


## 开源项目交付准备


### 项目文档规范


```markdown

# MyHarmonyApp - 跨平台应用示例


## ? 特性


- 支持 iOS、Android、HarmonyOS 三端

- 基于 React Native 开发

- 完整的 TypeScript 支持

- 现代化的 UI/UX 设计

- 完善的测试覆盖


## ? 快速开始


### 环境要求


- Node.js >= 18.0.0

- npm >= 9.0.0

- React Native CLI

- 各平台开发环境


### 安装


```bash

git clone https://github.com/username/my-harmony-app.git

cd my-harmony-app

npm install

```


### 运行应用


```bash

# 运行 iOS

npm run ios


# 运行 Android

npm run android


# 运行 HarmonyOS

npm run harmony


# 构建所有平台

npm run build:all

```


## ?️ 项目结构


```

src/

├── components/     # 可复用组件

├── screens/        # 页面组件

├── services/       # API服务

├── navigation/     # 导航配置

├── utils/          # 工具函数

├── styles/         # 样式文件

└── types/          # TypeScript类型定义

```


## ? 开发指南


### 添加新功能


1. 创建相关组件/服务

2. 添加类型定义

3. 编写单元测试

4. 更新文档


### 代码规范


- 使用 TypeScript

- 遵循 ESLint 规则

- 提交前运行测试

- 编写清晰的注释


## ? 贡献指南


请阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 了解如何参与项目开发。


## ? 许可证


本项目基于 MIT 许可证开源。

```


### 发布与版本管理


```json

// scripts/release.js

const { execSync } = require('child_process');

const fs = require('fs');

const path = require('path');

const readline = require('readline');


const rl = readline.createInterface({

  input: process.stdin,

  output: process.stdout

});

<"j2.j9k5.org.cn"><"n5.j9k5.org.cn"><"w1.j9k5.org.cn">

class ReleaseManager {

  constructor() {

    this.version = this.getCurrentVersion();

  }

  

  getCurrentVersion() {

    const packageJson = JSON.parse(

      fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')

    );

    return packageJson.version;

  }

  

  async prompt(question) {

    return new Promise(resolve => {

      rl.question(question, answer => {

        resolve(answer);

      });

    });

  }

  

  async run() {

    console.log(`? 当前版本: ${this.version}`);

    

    // 选择发布类型

    const releaseType = await this.prompt(

      '选择发布类型 (major/minor/patch): '

    );

    

    if (!['major', 'minor', 'patch'].includes(releaseType)) {

      console.error('❌ 无效的发布类型');

      process.exit(1);

    }

    

    // 确认版本号

    const newVersion = this.calculateNewVersion(releaseType);

    const confirm = await this.prompt(

      `确认发布版本 ${newVersion}? (y/N): `

    );

    

    if (confirm.toLowerCase() !== 'y') {

      console.log('❌ 发布取消');

      process.exit(0);

    }

    

    // 运行测试

    console.log('? 运行测试...');

    execSync('npm test', { stdio: 'inherit' });

    

    // 更新版本号

    this.updateVersion(newVersion);

    

    // 生成更新日志

    this.generateChangelog(newVersion);

    

    // 提交更改

    execSync(`git add .`, { stdio: 'inherit' });

    execSync(`git commit -m "release: v${newVersion}"`, { stdio: 'inherit' });

    execSync(`git tag v${newVersion}`, { stdio: 'inherit' });

    

    // 推送

    execSync('git push', { stdio: 'inherit' });

    execSync(`git push origin v${newVersion}`, { stdio: 'inherit' });

    

    console.log(`✅ 版本 ${newVersion} 发布成功!`);

    rl.close();

  }

  

  calculateNewVersion(releaseType) {

    const [major, minor, patch] = this.version.split('.').map(Number);

    

    switch (releaseType) {

      case 'major':

        return `${major + 1}.0.0`;

      case 'minor':

        return `${major}.${minor + 1}.0`;

      case 'patch':

        return `${major}.${minor}.${patch + 1}`;

    }

  }

  

  updateVersion(newVersion) {

    const packagePath = path.join(__dirname, '..', 'package.json');

    const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));

    

    packageJson.version = newVersion;

    fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2));

    

    console.log(`? 更新版本号: ${newVersion}`);

  }

  

  generateChangelog(newVersion) {

    const changelogPath = path.join(__dirname, '..', 'CHANGELOG.md');

    let changelog = '';

    

    if (fs.existsSync(changelogPath)) {

      changelog = fs.readFileSync(changelogPath, 'utf8');

    }

    

    const newEntry = `## ${newVersion} (${

      new Date().toISOString().split('T')[0]

    })\n\n- TODO: 添加更新内容\n\n`;

    

    fs.writeFileSync(changelogPath, newEntry + changelog);

    console.log('? 更新变更日志');

  }

}


// 运行发布流程

const manager = new ReleaseManager();

manager.run().catch(console.error);

```


## 质量保障与测试


### 测试配置


```javascript

// jest.config.js

module.exports = {

  preset: 'react-native',

  setupFiles: [

    '/jest/setup.js'

  ],

  setupFilesAfterEnv: [

    '@testing-library/jest-native/extend-expect'

  ],

  transform: {

    '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest'

  },

  transformIgnorePatterns: [

    'node_modules/(?!(react-native|@react-native|@react-navigation|@testing-library)/)'

  ],

  moduleNameMapper: {

    '^@/(.*)$': '/src/$1'

  },

  testMatch: [

    '/src/**/__tests__/**/*.{js,jsx,ts,tsx}',

    '/src/**/*.{spec,test}.{js,jsx,ts,tsx}'

  ],

  collectCoverageFrom: [

    'src/**/*.{js,jsx,ts,tsx}',

    '!src/**/*.d.ts',

    '!src/**/__tests__/**',

    '!src/**/index.{js,ts}'

  ],

  coverageThreshold: {

    global: {

      branches: 80,

      functions: 80,

      lines: 80,

      statements: 80

    }

  },

  reporters: [

    'default',

    ['jest-junit', {

      outputDirectory: 'test-results',

      outputName: 'junit.xml'

    }]

  ]

};

```


### 组件测试示例


```typescript

// src/components/Button/__tests__/Button.test.tsx

import React from 'react';

import { render, fireEvent } from '@testing-library/react-native';

import Button from '../Button';


describe('Button Component', () => {

  it('渲染正确文本', () => {

    const { getByText } = render(

请使用浏览器的分享功能分享到微信等