3312facd82
CAMERA_PORT_ANDROID.md lists only what the web build has that Android does not, one row per gap, with the web file to read next to the Android one. The plan alongside it is the sketch for a live camera with a Skia filter on the frame thread.
4.0 KiB
4.0 KiB
Kế hoạch: Real-time Skia filter trên camera live view dùng vision-camera v4
Vấn đề
expo-camera render camera preview lên native surface (PreviewView/SurfaceView) không thể intercept bằng Skia. Periodic capture bị từ chối vì mất live view.
Giải pháp
Dùng react-native-vision-camera@4.7.3 với useSkiaFrameProcessor — frame processor chạy native thread, mỗi frame camera được vẽ qua Skia với ColorMatrix trước khi hiển thị.
Các bước thực hiện
Bước 1: Cài react-native-vision-camera@4.7.3
npm install react-native-vision-camera@4.7.3
- v4.7.3 là latest v4, có export
useSkiaFrameProcessorvàframeProcessorprop trênCamera - v5+ đã xoá Skia integration, không dùng được
Bước 2: Thêm Expo Config Plugin
Sửa app.json:
- Thay
expo-cameraplugin bằngreact-native-vision-cameraplugin (v4 có plugin riêng) - Thêm
withEnableFrameProcessorsAndroidđể bật frame processor trên Android
"plugins": [
"react-native-vision-camera",
[
"expo-camera",
{
"cameraPermission": "..."
}
]
]
Cần kiểm tra: v4 có expo plugin riêng (withVisionCamera) hay dùng thẳng tên package.
Bước 3: Cập nhật App.tsx
- Import
useCameraPermissiontừreact-native-vision-camerathay vìuseCameraPermissionstừexpo-camera - Props:
hasPermission,requestPermission
Bước 4: Viết lại Viewfinder.tsx
Component mới dùng:
Cameratừ vision-camera với propframeProcessor={frameProcessor}useSkiaFrameProcessorhook — worklet chạy native, mỗi frame:- Tạo
Skia.Paint()vớiSkia.ColorFilter.MakeMatrix(colorMatrix) - Gọi
frame.render(paint)— vẽ frame qua color filter
- Tạo
colorMatrixlàSharedValuetừ react-native-reanimated (để worklet đọc được)- Grain noise, frame border, GPS watermark: giữ nguyên overlay React Native / Skia Canvas trên top
const App = () => {
const frameProcessor = useSkiaFrameProcessor((frame) => {
'worklet';
const paint = Skia.Paint();
paint.setColorFilter(Skia.ColorFilter.MakeMatrix(colorMatrixSV.value));
frame.render(paint);
}, [colorMatrixSV]);
return (
<Camera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
frameProcessor={frameProcessor}
/>
);
};
Bước 5: Loại bỏ expo-camera khỏi code
CameraView→Camera(vision-camera)- Xoá imports không dùng
- Giữ
expo-cameratrong package.json (không gỡ, tránh lỗi autolinking)
Bước 6: Re-prebuild & build APK
rm -rf android
npx expo prebuild --platform android
echo "sdk.dir=/home/locpham/android-sdk" > android/local.properties
cd android && ./gradlew assembleDebug
(Không chạy clean — tránh lỗi CMake codegen paths)
API đã xác nhận (v4.7.3)
| Export | Path |
|---|---|
Camera |
react-native-vision-camera |
useCameraDevice |
react-native-vision-camera |
useCameraPermission |
react-native-vision-camera |
useSkiaFrameProcessor |
react-native-vision-camera |
SkiaCameraCanvas |
react-native-vision-camera |
Expo plugin (withVisionCamera) |
lib/module/expo-plugin/withVisionCamera |
Rủi ro & Xử lý
| Rủi ro | Xử lý |
|---|---|
react-native-worklets-core conflict |
Đã có sẵn qua react-native-reanimated dependency |
CameraX dependency (NoClassDefFoundError) |
v4 dùng CameraX không phải Nitro — build an toàn hơn v5 |
CMake codegen paths lỗi sau clean |
Không dùng ./gradlew clean, dùng --rerun-tasks nếu cần |
| Frame processor không chạy trên Android | Bật flag qua Expo plugin: withEnableFrameProcessorsAndroid |
Kiểm thử
- Build APK thành công
- Camera live view hiển thị với filter:
- B&W/monochrome → true grayscale
- Saturation, temp, tint, exposure thay đổi real-time
- Grain noise, frame border, GPS watermark vẫn hoạt động
- Library mode không bị ảnh hưởng