Commit eb6d40f7 authored by Jawa Tang's avatar Jawa Tang

docs: add project technical documentation

parent dbd1e7fb
# CLAUDE.md
This file provides guidance to Claude Code when working with code in this repository.
## Project Overview
react-native-syan-image-picker 是一个 React Native 多图选择器开源库(v0.3.8),支持 iOS 和 Android 双端。
- iOS 端:封装 TZImagePickerController
- Android 端:封装 PictureSelector
- 支持多图选择、相机拍照、图片裁剪(矩形/圆形)、压缩、GIF、视频选择
- 提供 Callback 和 Promise 两种调用形式
## Architecture
```
index.js → JS 入口,暴露 API,合并默认参数
ios/
RNSyanImagePicker.h/m → iOS Native Module,实现 RCT_EXPORT_METHOD
TZImagePickerController/ → 第三方相册控件(TZ 开源库,完整嵌入)
android/
src/main/java/com/syanpicker/
RNSyanImagePickerModule.java → Android Native Module,@ReactMethod
RNSyanImagePickerPackage.java → Package 注册
```
### JS API
| 方法 | 说明 |
|------|------|
| `showImagePicker(options, callback)` | Callback 方式选图 |
| `asyncShowImagePicker(options)` | Promise 方式选图 |
| `openCamera(options, callback)` | Callback 方式拍照 |
| `asyncOpenCamera(options)` | Promise 方式拍照 |
| `openVideoPicker(options, callback)` | 选视频 |
| `deleteCache()` | 清除临时缓存 |
| `removePhotoAtIndex(index)` | 移除指定选中项 |
| `removeAllPhoto()` | 清空选中列表 |
### 返回数据结构
图片:`{ uri, width, height, size, base64? }`
视频:`{ uri, coverUri, fileName, size, duration, type }`
## Key Options
| 参数 | 默认值 | 说明 |
|------|--------|------|
| imageCount | 6 | 最大选择数 |
| isCamera | true | 允许内部拍照 |
| isCrop | false | 启用裁剪(imageCount=1 时生效) |
| CropW/CropH | 屏幕宽60% | 裁剪尺寸 |
| showCropCircle | false | 圆形裁剪 |
| compress | true | 启用压缩 |
| quality | 90 | 压缩质量 |
| enableBase64 | false | 返回 base64 |
| isRecordSelected | false | 保持选中状态(多次调用持久化) |
## Platform Notes
- iOS:图片缓存到 `NSTemporaryDirectory()/ImageCaches/`,UUID 命名的 jpg
- Android:通过 `ActivityEventListener` + `onActivityResult` 回调处理结果
- 取消选择时:Callback 返回 `"取消"`,Promise reject `"取消"`
# react-native-syan-image-picker
React Native 多图选择器开源库(v0.3.8,MIT)。支持 iOS/Android 双端,封装各端原生图片选择控件,提供统一的 JS API。
## 功能
- 多图选择(最多 N 张)
- 相机拍照
- 图片裁剪(矩形 / 圆形)
- 图片压缩
- GIF 支持
- 视频选择
- 选中状态持久化(跨多次调用保留已选)
- Base64 编码返回
## 安装
```bash
npm install react-native-syan-image-picker
react-native link react-native-syan-image-picker
```
iOS 需添加 `NSCameraUsageDescription``NSPhotoLibraryUsageDescription` 权限声明。
## 快速使用
```javascript
import SYImagePicker from 'react-native-syan-image-picker';
// Callback 方式
SYImagePicker.showImagePicker({ imageCount: 6 }, (err, photos) => {
if (err) return; // 用户取消
console.log(photos); // [{ uri, width, height, size }]
});
// Promise 方式
const photos = await SYImagePicker.asyncShowImagePicker({ imageCount: 1, isCrop: true });
```
## 平台实现
| 端 | 底层库 |
|----|--------|
| iOS | TZImagePickerController(完整嵌入,Obj-C) |
| Android | PictureSelector(通过 Gradle 依赖) |
# Architecture
## 整体结构
```
react-native-syan-image-picker/
├── index.js → JS 入口(NativeModules 桥接 + 默认参数)
├── package.json
├── ios/
│ ├── RNSyanImagePicker.h/.m → iOS Native Module(RCTBridgeModule)
│ ├── RNSyanImagePicker.podspec → CocoaPods 描述
│ ├── NSDictionary+SYSafeConvert.h/.m → 安全取值 Category
│ └── TZImagePickerController/ → 完整嵌入的第三方相册库
│ ├── TZImagePickerController.h/.m → 相册主控制器
│ ├── TZImageManager.h/.m → PHPhotoLibrary 封装
│ ├── TZPhotoPickerController.h/.m → 相册列表页
│ ├── TZPhotoPreviewController.h/.m → 预览页
│ ├── TZVideoPlayerController.h/.m → 视频播放页
│ ├── TZImageCropManager.h/.m → 裁剪管理
│ └── TZImagePickerController.bundle/ → 资源(图标、多语言)
└── android/
├── build.gradle
└── src/main/java/com/syanpicker/
├── RNSyanImagePickerModule.java → Android Native Module
└── RNSyanImagePickerPackage.java → Package 注册
```
## 数据流
```
JS: SYImagePicker.showImagePicker(options, callback)
→ 合并 defaultOptions
→ NativeModules.RNSyanImagePicker.showImagePicker(optionObj, callback)
→ iOS: RNSyanImagePicker.m → openImagePicker → TZImagePickerController
→ didFinishPickingPhotos → handleImageData → callback([null, photos])
→ Android: RNSyanImagePickerModule → openImagePicker → PictureSelector
→ onActivityResult → onGetResult → invokeSuccessWithResult
→ JS callback(err, photos)
```
## Native Module 实现要点
### iOS (RNSyanImagePicker.m)
- `RCT_EXPORT_MODULE()` — 注册为 `RNSyanImagePicker` 模块
- Callback 方式:保存 `RCTResponseSenderBlock`,完成后调 `callback(@[NSNull.null, photos])`
- Promise 方式:保存 `resolveBlock/rejectBlock`
- 图片处理:`UIImageJPEGRepresentation(image, quality/100)` 压缩,写到 `NSTemporaryDirectory()/ImageCaches/`
- 取消:统一返回字符串 `"取消"`
- 运行在主队列:`methodQueue` 返回 `dispatch_get_main_queue()`
### Android (RNSyanImagePickerModule.java)
- 继承 `ReactContextBaseJavaModule``getName()` 返回 `"RNSyanImagePicker"`
- 注册 `ActivityEventListener` 监听 `onActivityResult`
- 图片:`requestCode == PictureConfig.CHOOSE_REQUEST`,视频:`PictureConfig.REQUEST_CAMERA`
- 压缩/裁剪路径优先取 `media.getCompressPath()`,再取 `media.getPath()`
## 返回数据格式
**图片**
```json
{ "uri": "file:///tmp/ImageCaches/xxx.jpg", "width": 1080, "height": 1920, "size": 102400, "base64": "data:image/jpeg;base64,..." }
```
**视频**(iOS):
```json
{ "uri": "/tmp/xxx.mp4", "coverUri": "/tmp/ImageCaches/xxx.png", "fileName": "xxx.MOV", "size": 1024000, "duration": 30, "type": "video" }
```
# Dependencies
## JS
无额外 npm 运行时依赖,仅依赖 React Native 框架内置模块:
- `react-native``NativeModules``Dimensions`
## iOS
| 依赖 | 引入方式 | 用途 |
|------|---------|------|
| TZImagePickerController | 源码直接嵌入(`ios/TZImagePickerController/`) | 相册多选控件 |
| AssetsLibrary | 系统框架 | 图片资产(已弃用,保留兼容) |
| Photos (PHPhotoLibrary) | 系统框架(通过 TZImageManager) | 相册访问 |
| AVFoundation | 系统框架 | 相机权限检查 |
| React/RCTUtils | React Native 框架 | `RCTPresentedViewController()` |
iOS 权限声明(`Info.plist`):
- `NSCameraUsageDescription`
- `NSPhotoLibraryUsageDescription`
- `NSPhotoLibraryAddUsageDescription`
## Android
| 依赖 | 用途 |
|------|------|
| com.luck.picture.lib:PictureSelector | 图片/视频选择(通过 build.gradle 引入) |
| com.facebook.react:react-native | Bridge 接口(ReactApplicationContext 等) |
Android 权限(`AndroidManifest.xml`):
- `READ_EXTERNAL_STORAGE`
- `WRITE_EXTERNAL_STORAGE`
- `CAMERA`
## CocoaPods
```ruby
# RNSyanImagePicker.podspec
Pod::Spec.new do |s|
s.name = "RNSyanImagePicker"
s.source_files = "ios/**/*.{h,m}"
end
```
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment