
开源贡献指南:向HarmonyOS5 RN适配仓库提交PR的完整流程
准备工作:开发环境搭建
- 基础环境配置
安装HarmonyOS开发工具
npm install -g @ohos/hpm-cli
hpm config set registry https://repo.harmonyos.com/npm/
安装React Native依赖
npm install -g react-native-cli
npx react-native init RNTestApp --template react-native-template-typescript
- 克隆适配仓库
Fork主仓库到个人账号
git clone https://github.com/{your-username}/react-native-harmony
cd react-native-harmony
添加官方上游仓库
git remote add upstream https://github.com/harmonyos/rn-harmony-adapter.git
代码修改实战流程
- 创建功能分支
git checkout -b fix/image-component
- 实现一个适配模块(示例:Image组件适配)
// src/components/ImageHarmony.tsx
import React from ‘react’;
import { requireNativeComponent, Platform } from ‘react-native’;
const RNTHarmonyImage = requireNativeComponent(‘RNTHarmonyImage’);
interface HarmonyImageProps {
source: { uri: string };
resizeMode?: ‘cover’ | ‘contain’ | ‘stretch’;
onLoad?: () => void;
onError?: (error: { nativeEvent: { error: string } }) => void;
}
const ImageHarmony: React.FC<HarmonyImageProps> = (props) => {
// 处理图片资源类型
const resolveUri = () => {
if (Platform.OS === ‘harmony’) {
// Harmony特定路径处理
return props.source.uri.replace(‘file://’, ‘/entry/resources/rawfile/’);
}
return props.source.uri;
};
return (
<RNTHarmonyImage
{…props}
source={{ uri: resolveUri() }}
onImageLoad={props.onLoad}
onImageError={props.onError}
/>
);
};
export default ImageHarmony;
- 添加原生端支持代码
// src/main/cpp/image/RNTHarmonyImage.cpp
#include “RNTHarmonyImage.h”
#include <hilog/log.h>
static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
LOG_CORE, 0xD001800, “RNTHarmonyImage”
};
RNTHarmonyImage::RNTHarmonyImage(napi_env env, napi_value exports) {
napi_property_descriptor descriptors[] = {
DECLARE_NAPI_FUNCTION(“load”, Load),
DECLARE_NAPI_FUNCTION(“setResizeMode”, SetResizeMode)
};
napi_define_class(env, “RNTHarmonyImage”, NAPI_AUTO_LENGTH,
Constructor, nullptr,
sizeof(descriptors) / sizeof(*descriptors),
descriptors, &constructor_);
}
napi_value RNTHarmonyImage::Constructor(napi_env env, napi_callback_info info) {
// …构造器实现
}
napi_value RNTHarmonyImage::Load(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
// 获取图片路径
char uri[1024];
size_t strLength;
napi_get_value_string_utf8(env, args[0], uri, sizeof(uri), &strLength);
// 使用系统Image组件加载
auto image = std::make_shared<OHOS::Ace::Image>();
image->SetSrc(uri);
// 加载成功回调
napi_value jsCallback;
napi_create_function(env, "onImageLoad", NAPI_AUTO_LENGTH,
[](napi_env env, napi_callback_info info) {},
nullptr, &jsCallback);
napi_value argv[] = { jsCallback };
napi_call_function(env, nullptr, args[0], 1, argv, nullptr);
return nullptr;
}
- 添加单元测试
// tests/components/ImageHarmony.test.tsx
import React from ‘react’;
import { render } from ‘@testing-library/react-native’;
import ImageHarmony from ‘…/…/src/components/ImageHarmony’;
describe(‘ImageHarmony Component’, () => {
it(‘handles local resources correctly’, () => {
const { getByTestId } = render(
<ImageHarmony
source={{ uri: ‘file:///entry/logo.png’ }}
testID=“test-image”
/>
);
const image = getByTestId('test-image');
expect(image.props.source.uri).toContain('/entry/resources/rawfile/');
});
it(‘triggers onLoad event’, () => {
const onLoadMock = jest.fn();
render(
<ImageHarmony
source={{ uri: ‘file:///entry/logo.png’ }}
onLoad={onLoadMock}
/>
);
// 模拟原生端加载成功
const event = new Event('onImageLoad');
fireEvent(getByTestId('test-image'), 'onImageLoad', event);
expect(onLoadMock).toHaveBeenCalledTimes(1);
});
});
测试与验证流程
- 本地调试脚本
#!/bin/bash
test-adapter.sh
构建TypeScript
npm run build
运行HarmonyOS模拟器
hdc shell am start -a com.example.rnapp
运行单元测试
npm test
启动调试服务器
npm run debug – --port 8088
安装测试应用
hdc install dist/rn-harmony-adapter.hap
- 测试覆盖率检查
生成测试覆盖率报告
npx jest --coverage
覆盖率不足时处理方案
if [ $(node -pe “require(‘./coverage/coverage-summary.json’).total.lines.pct < 85”) == “true” ]; then
echo “Coverage below 85% - adding tests…”
自动生成测试桩
npx jest-coverage-ratchet --threshold 85
exit 1
fi
提交PR规范
- 代码提交前检查
运行格式检查
npx lint-staged
修复代码风格问题
npm run fix
检查API兼容性
npm run api-check
- PR描述模板
该PR解决的问题
- 修复React Native Image组件在HarmonyOS上的资源路径问题 (Issue #423)
- 添加本地资源文件加载支持
技术解决方案
- 添加路径转换器处理资源定位
uri.replace('file://', '/entry/resources/rawfile/')
- 实现原生加载回调机制
napi_call_function(env, nullptr, args[0], 1, argv, nullptr);
测试验证
测试场景 | 结果 |
---|---|
本地资源加载 | ✅ |
网络资源加载 | 🔜 |
加载事件回调 | ✅ |
兼容性检查
设备 | HarmonyOS版本 | 结果 |
---|---|---|
MatePad Pro | 5.0 | ✅ |
P50 Pro | 4.0 | ✅ |
WATCH 3 | 5.1 | 🔜 |
文档更新
更新了 docs/components/image.md
使用说明
- 提交命令
提交更改
git add src/components/ImageHarmony.tsx
git commit -m “fix(image): resolve local resource path issue”
推送到个人分支
git push origin fix/image-component
创建PR(需访问GitHub网页界面)
open https://github.com/harmonyos/rn-harmony-adapter/compare
PR审查后处理流程
- 响应审查建议
检出你的分支
git checkout fix/image-component
进行修改
…修改代码…
添加修改到上次提交
git add .
git commit --amend --no-edit
强制推送更新
git push origin fix/image-component -f
- 冲突解决方法
拉取上游最新代码
git fetch upstream main
变基到最新代码
git rebase upstream/main
- 合并后清理
删除本地分支
git checkout main
git branch -D fix/image-component
更新主仓库
git pull upstream main
重置本地fork仓库
git push origin main --force
最佳实践指南
- 模块化开发规范
// 推荐架构
src/
├── components/ // React组件
├── modules/ // 功能模块
├── natives/ // 原生模块
│ ├── harmonyos/ // HarmonyOS实现
│ └── android/ // Android实现(兼容)
└── utils/ // 公共工具
- 兼容性处理模式
// 多平台兼容代码示例
export const resolveResource = (uri: string) => {
if (Platform.OS === ‘harmony’) {
return uri.replace(‘file://’, ‘/entry/resources/rawfile/’);
}
if (Platform.OS === ‘android’) {
return res:/${uri.split('://')[1]}
;
}
return uri;
};
// 功能降级处理
export const getDeviceInfo = () => {
if (Platform.OS === ‘harmony’) {
return getHarmonyDeviceInfo(); // Harmony专用API
}
// 其他平台使用React Native实现
return {
deviceId: DeviceInfo.getUniqueId(),
brand: Platform.constants.Brand,
};
};
贡献者奖励机制
- 官方致谢途径
• 贡献者墙:在仓库README展示贡献者
• 特别标签:标注"First-time Contributor"等标签
• 证书认证:发放数字贡献证书(示例脚本生成)
generate_certificate.py
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime
def generate_contribution_cert(name, contribution):
# 创建证书模板
img = Image.open(‘cert_template.png’)
draw = ImageDraw.Draw(img)
# 添加贡献者信息
font = ImageFont.truetype('HarmonySans.ttf', 60)
draw.text((500, 500), name, fill=(0, 0, 0), font=font)
# 添加贡献描述
draw.text((500, 700), contribution, fill=(0, 0, 0), font=font)
# 添加日期
date_str = datetime.now().strftime("%Y/%m/%d")
draw.text((1000, 1000), date_str, fill=(0, 0, 0), font=font)
# 保存证书
img.save(f'certificates/{name.replace(" ", "_")}_contrib.png')
- 持续贡献路线
graph TD
A[首次贡献] -->|修复问题单| B(基本贡献者)
B -->|提交3个PR| C[活跃贡献者]
C -->|模块维护| D[核心维护者]
D -->|架构设计| E[项目委员会]
常见问题解决方案
- 编译问题排错
日志分析脚本
#!/bin/bash
analyze-build-log.sh
LOG_FILE=${1:-build.log}
查找错误模式
grep -Ei ‘error:|fail|exception’ $LOG_FILE | head -n 10
分析资源问题
if grep -q ‘Resource not found’ $LOG_FILE; then
echo “资源未找到问题,尝试以下方案:”
echo “1. 检查resource目录是否存在”
echo “2. 运行’hpm res update’更新资源索引”
fi
- 许可证合规检查
许可证验证脚本
npx license-checker --summary --excludePrivatePackages
添加开源许可证头
for file in $(find src -name “.ts"); do
if ! grep -q “SPDX-License-Identifier” $file; then
echo "/\n * SPDX-License-Identifier: MIT\n */” > temp.txt
cat $file >> temp.txt
mv temp.txt $file
fi
done
通过这个完整指南,开发者可以系统性地学习如何为HarmonyOS的React Native适配器贡献代码,解决社区提出的问题,共同推动跨平台开发技术生态的发展。
