Introduce the example integration demo, export resolveAssetPath, harden resolveImageUrl for Android bundled assets, and update gitignore to exclude example build outputs. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .. | ||
| android | ||
| assets | ||
| ios | ||
| app.json | ||
| App.tsx | ||
| babel.config.js | ||
| index.js | ||
| metro.config.js | ||
| package-lock.json | ||
| package.json | ||
| patches | ||
| README.md | ||
| tsconfig.json | ||
MaskSegmentCanvas Example
这是一个完全模拟真实业务项目集成的 Demo,展示如何在你的 React Native 工程中接入 react-native-mask-segment-canvas。
与库本身 Demo 的区别
| 项目 | 引入方式 | 用途 |
|---|---|---|
根目录 App.tsx |
import ... from './src'(内部源码) |
库作者自测 |
| 本 example/ | import ... from 'react-native-mask-segment-canvas'(公开 API) |
业务集成参考 |
本 example 只依赖库的公开 API,不触碰 src/ 内部实现,是你接入时可以直接复制的模板。
快速开始
# 1. 进入 example 目录
cd example
# 2. 安装依赖(自动 link 父目录的库)
npm install
# 3. 应用 postinstall 补丁(patch-package 修补 react-native-fast-opencv)
# npm install 后自动执行,若未执行请手动:
npx patch-package
# 4. iOS:安装原生依赖
cd ios && pod install && cd ..
# 5. 启动 Metro
npm start
# 6. 另开终端运行
npm run ios
# 或
npm run android
文件说明
example/
├── App.tsx # ★ 核心:完整的集成示例页面
├── index.js # RN 入口(注册 gesture-handler + Buffer polyfill)
├── app.json # 应用名配置
├── package.json # 独立依赖配置,"react-native-mask-segment-canvas": "file:.."
├── metro.config.js # Metro 配置(watchFolders 指向父目录)
├── babel.config.js # Babel 配置(含 reanimated 插件)
├── tsconfig.json # TypeScript 配置
└── README.md # 本文件
App.tsx 覆盖的功能点
App.tsx 是一个可直接参考的完整页面,涵盖:
| 功能 | 对应代码位置 |
|---|---|
| PNG 预热 | useEffect → prewarmPngBgrCacheAsync |
| 状态管理 | watchState / isInteractive / isOutlineReady 等派生状态 |
| onWatch 回调 | handleWatch — 跟踪初始化阶段 |
| onPaintCallback | handlePaintCallback — 处理上色成功 / 未选笔刷两种场景 |
| onError 回调 | handleError — 捕获分割/加载失败 |
| Ref 操作 | save / reset / swap / clearAllPaint / session |
| setPaintColor | 预设笔刷色,通过 ref.setPaintColor 设置 |
| 自定义语义色表 | GYM_CUSTOM_COLORS 示例 + 模式切换 UI |
| Pipeline 精度切换 | pipelinePreset 低/中/高精度切换 |
| Toast 提示 | 未选笔刷时 brush_required 回调 + 自定义 Toast |
| 加载态/错误态 UI | PNG 预热加载、初始化 Loading、错误展示 |
| 草稿恢复 | sessionDraft 状态 + initialSession prop |
集成到自己项目
方式一:npm install(推荐生产环境)
npm install react-native-mask-segment-canvas
方式二:本地联调(开发阶段)
# 在库目录
npm link
# 在你的项目
npm link react-native-mask-segment-canvas
你的 metro.config.js 需要添加:
const path = require('path');
module.exports = mergeConfig(getDefaultConfig(__dirname), {
watchFolders: [path.resolve(__dirname, '../MaskSegmentApp')],
resolver: {
nodeModulesPaths: [path.resolve(__dirname, 'node_modules')],
},
});
方式三:file: 依赖(本 example 使用的方式)
{
"dependencies": {
"react-native-mask-segment-canvas": "file:../MaskSegmentApp"
}
}
必装 peerDependencies
npm install @shopify/react-native-skia react-native-reanimated react-native-fast-opencv react-native-fs buffer
# 若使用相册选图
npm install react-native-image-picker
# 安全区适配
npm install react-native-safe-area-context
postinstall 配置
你的 package.json 需要:
{
"scripts": {
"postinstall": "patch-package"
},
"devDependencies": {
"patch-package": "^8.0.1"
}
}
常见问题
npm install 后报模块找不到?
- 确认已执行
postinstall(npx patch-package) - 检查 Metro 配置中
watchFolders是否包含库目录
pod install 失败?
cd ios
bundle install
bundle exec pod install --repo-update
Android 编译错误?
cd android && ./gradlew clean && cd ..
运行时出现「重复模块」类错误(最常见)
在 monorepo、npm link、file:.. 场景下,经常会遇到下面这些「类似问题」:
SkiaPictureView must be a function (received 'undefined')createAnimatedNode: Animated node[...] already exists(含 UIFrameGuarded 变体)- 其他 Fabric ViewManager / native module 单例冲突
原因:Metro 同时加载了多份 @shopify/react-native-skia、react-native-reanimated、react-native-gesture-handler、react-native-fast-opencv、react-native-safe-area-context 等 peer 依赖。
推荐完整解决方案(直接复制到你的项目):
-
index.js 最顶部(必须在最前面):
import 'react-native-gesture-handler'; import 'react-native-reanimated'; import '@shopify/react-native-skia'; -
metro.config.js(使用 extraNodeModules + blockList 双保险):
const path = require('path'); const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const yourNodeModules = path.resolve(__dirname, 'node_modules'); const singletons = [ 'react', 'react-native', 'react-native-reanimated', '@shopify/react-native-skia', 'react-native-gesture-handler', 'react-native-fast-opencv', 'react-native-safe-area-context', 'react-native-fs', 'react-native-image-picker', ]; module.exports = mergeConfig(getDefaultConfig(__dirname), { watchFolders: [path.resolve(__dirname, '../MaskSegmentApp')], resolver: { nodeModulesPaths: [yourNodeModules], extraNodeModules: singletons.reduce((acc, p) => (acc[p] = path.resolve(yourNodeModules, p), acc), {}), blockList: singletons.map(p => new RegExp(`/MaskSegmentApp/node_modules/${p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}/`)), }, });example/metro.config.js已经是按这个标准模板写的,可直接参考。
做完上面两步后,必须:
- 重启 Metro(
npx react-native start --reset-cache) - 重新安装 app(建议先
cd android && ./gradlew clean或 iOS pod 后重跑)
这样能一次性解决所有「同类」重复模块导致的运行时错误。