Conversation
…ocessing features
…guide, and enhance example app
…ormat selection logic
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis PR makes preprocessing automatic and simplifies the JS API, adds a new Swift iOS native module for scanning/preprocessing, updates Android native/build settings, overhauls docs and example (Expo) app, and adjusts CI, lint, and packaging configs. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant App as Example App (Expo)
participant JS as JS API
participant Native as Native Module (iOS / Android)
participant Engine as Vision / ML Kit
User->>App: Pick image + select formats
App->>JS: scan({ path, formats })
JS->>Native: scanFromPath(path, formats, { auto-preprocess })
rect rgba(154,208,245,0.12)
Note right of Native: Automatic preprocessing candidates
Native->>Native: Scale image if large
Native->>Native: Build candidates: Original, Grayscale, Contrast, Rotations (90/180/270)
end
loop For each candidate until found or exhausted
Native->>Engine: Detect barcodes (requested formats)
Engine-->>Native: Results or none
end
alt Codes found
Native-->>JS: [payloadStrings]
JS-->>App: results
App-->>User: show codes & timing
else None found
Native-->>JS: []
JS-->>App: none
App-->>User: inform no codes
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
| symbologies.append(.ean8) | ||
| case "UPC_A": | ||
| symbologies.append(contentsOf: [.ean13, .upce]) // UPC-A via EAN-13 + UPC-E | ||
| case "UPC_E": |
There was a problem hiding this comment.
Limit UPC_A mapping to .ean13; including .upce broadens results beyond the requested format.
Prompt for AI agents
Address the following comment on ios/ImageCodeScanner.swift at line 189:
<comment>Limit UPC_A mapping to .ean13; including .upce broadens results beyond the requested format.</comment>
<file context>
@@ -1 +1,323 @@
+ symbologies.append(.ean8)
+ case "UPC_A":
+ symbologies.append(contentsOf: [.ean13, .upce]) // UPC-A via EAN-13 + UPC-E
+ case "UPC_E":
+ symbologies.append(.upce)
+ case "PDF_417":
</file context>
|
|
||
| // Always add rotated versions | ||
| if let rotated90 = rotateImage(originalImage, degrees: 90) { | ||
| imagesToTry.append(("Rotated 90°", rotated90)) |
There was a problem hiding this comment.
Rotate the scaled baseImage instead of the original to reduce memory/CPU usage.
Prompt for AI agents
Address the following comment on ios/ImageCodeScanner.swift at line 160:
<comment>Rotate the scaled baseImage instead of the original to reduce memory/CPU usage.</comment>
<file context>
@@ -1 +1,323 @@
+
+ // Always add rotated versions
+ if let rotated90 = rotateImage(originalImage, degrees: 90) {
+ imagesToTry.append(("Rotated 90°", rotated90))
+ }
+ if let rotated180 = rotateImage(originalImage, degrees: 180) {
</file context>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
scripts/validate-package.js (1)
10-32: Enforce lockfile presence in requiredFiles (aligns with PR goal).
Add yarn.lock so validation guards deterministic CI installs.'CHANGELOG.md', + 'yarn.lock', 'tsconfig.json',CHANGELOG.md (1)
50-50: Broken release tag v0.1.0 – please create or correct it before mergingThe changelog entry in
CHANGELOG.mdpoints to a non-existent GitHub release tag (HTTP 404). You must either publish a release/tagv0.1.0in the repository or update this link to reference the correct existing version.• File: CHANGELOG.md
Line 50:[0.1.0]: https://github.com/nguyenthanhan/react-native-image-code-scanner/releases/tag/v0.1.0• Action: Create the
v0.1.0tag under the GitHub “Releases” tab or adjust the URL to the accurate tag name.README.md (2)
381-386: Docs inconsistency: “Real-time preprocessing option toggles” vs always-on preprocessing.If the library doesn’t expose toggles, clarify that the example shows informational UI only.
Apply:
-- Real-time preprocessing option toggles +- Automatic preprocessing (always on; no manual toggles required)
85-91: Add Photo Library usage string for gallery access.Most pickers require
NSPhotoLibraryUsageDescription(and optionallyNSPhotoLibraryAddUsageDescriptionif saving).Apply:
<key>NSCameraUsageDescription</key> <string>This app needs access to camera to scan barcodes</string> +<key>NSPhotoLibraryUsageDescription</key> +<string>This app needs access to your photos to pick images for scanning</string>
🧹 Nitpick comments (20)
scripts/validate-package.js (5)
38-45: Gate “Found” logs behind a verbose flag to reduce CI noise.
Keeps summaries clean while still allowing detail when needed.- } else { - console.log(`✅ Found: ${file}`); - } + } else { + if (process.env.VALIDATE_VERBOSE) console.log(`✅ Found: ${file}`); + }
53-79: Harden package.json checks for modern packaging and determinism.
Allow exports, typings; add license and packageManager checks; make the “validated” message conditional.- if (!packageJson.name) { + if (!packageJson.name) { errors.push('❌ package.json: missing "name" field'); } if (!packageJson.version) { errors.push('❌ package.json: missing "version" field'); } - if (!packageJson.main) { - errors.push('❌ package.json: missing "main" field'); - } - if (!packageJson.types) { - errors.push('❌ package.json: missing "types" field'); - } + if (!packageJson.main && !packageJson.exports) { + errors.push('❌ package.json: missing "main" or "exports" field'); + } + if (!packageJson.types && !packageJson.typings) { + errors.push('❌ package.json: missing "types"/"typings" field'); + } if (!packageJson.repository) { warnings.push('⚠️ package.json: missing "repository" field'); } if (!packageJson.keywords || packageJson.keywords.length === 0) { warnings.push('⚠️ package.json: missing or empty "keywords" field'); } if (!packageJson.peerDependencies) { errors.push('❌ package.json: missing "peerDependencies" field'); } + if (!packageJson.license) { + warnings.push('⚠️ package.json: missing "license" field'); + } + if (!packageJson.packageManager) { + warnings.push('⚠️ package.json: missing "packageManager" (e.g., "yarn@<version>")'); + } - - console.log('✅ package.json structure validated'); + + // Only claim validation success if no new issues were added by this block. + console.log( + errors.length === 0 && warnings.length === 0 + ? '✅ package.json structure validated' + : 'ℹ️ package.json checked; see issues recorded above' + );
86-91: Flag common build artifacts as unwanted.
Add dist (and keep as a warning) to avoid accidental publishes.-const unwantedDirs = ['modules', 'build', 'lib', '.turbo']; +const unwantedDirs = ['modules', 'build', 'lib', 'dist', '.turbo'];
103-103: Use console.error for error lines.
Better severity signaling in CI logs.- errors.forEach((error) => console.log(' ' + error)); + errors.forEach((error) => console.error(' ' + error));
108-108: Use console.warn for warnings.
Improves log clarity.- warnings.forEach((warning) => console.log(' ' + warning)); + warnings.forEach((warning) => console.warn(' ' + warning));example/README.md (1)
97-99: Align “automatic preprocessing” messaging across the README.These bullets say preprocessing is automatic, but elsewhere the README still mentions toggling preprocessing (Features, Usage step 3, Troubleshooting). Unify to avoid confusing users.
Apply these doc tweaks (outside this hunk) for consistency:
- - ⚙️ **Preprocessing Options**: Image enhancement for better recognition - - 🎯 **Real-time Configuration**: Toggle preprocessing options on the fly + - ⚙️ **Automatic Preprocessing**: Built-in image enhancement (contrast, grayscale, auto-rotations) + - 🎯 **Real-time Configuration**: Choose barcode formats; preprocessing runs automatically-3. **Configure Preprocessing**: Enable/disable image enhancement options +3. **Preprocessing**: Runs automatically; no configuration needed-**No Barcodes Detected:** -- Try enabling preprocessing options +**No Barcodes Detected:** +- Preprocessing is automatic; verify image quality and orientationsrc/NativeImageCodeScanner.ts (1)
5-13: Optional refactor – loosen the nativeoptionsparam for future flexibilityThe JS wrapper already hides manual preprocessing (always supplies its own
nativeOptions), so there’s no contract drift for existing callers. However, relaxing the spec signature now will:
- Decouple the internal TurboModule API from manual-preprocessing concerns
- Allow any future callers (or generated bindings) to omit
optionsentirely- Align better with RN codegen conventions around optional parameters
Proposed change in src/NativeImageCodeScanner.ts:
export interface Spec extends TurboModule { scanFromPath( path: string, formats: string[], - options: { - enhanceContrast: boolean; - convertToGrayscale: boolean; - tryRotations: boolean; - } + options?: { + enhanceContrast?: boolean; + convertToGrayscale?: boolean; + tryRotations?: boolean; + } | null ): Promise<string[]>; }No updates to
src/index.tsxare required—the wrapper still passes its defaultnativeOptions.eslint.config.mjs (2)
18-19: Reconsider ignoring example/ if you want it linted.**Ignoring
example/**skips lint on the demo app. If you intended to lint it, drop it from ignores or add a dedicated block with different rules.
27-33: Prettier options OK; consider pinning via eslint-config-prettier and a .prettierrc for editor parity.To avoid drift across tools, mirror these options in a
.prettierrcand keepeslint-config-prettierin dev deps.CHANGELOG.md (1)
21-27: “Optional disable switch” claim may not match current iOS implementation.Swift code unconditionally applies preprocessing and ignores the
optionsparameter. Either add an option to disable preprocessing in native code or adjust wording to “always-on preprocessing.”ios/ImageCodeScanner.swift (2)
112-112: Prefer RCTLog over print for RN-friendly logging.Switch
RCTLogInfo(import React/RCTLog.h) or guard with a debug flag.
292-322: Dead code: fallback never invoked.Either call
tryQRCodeFallbackafter all Vision attempts (for QR-only) or remove it.COMPATIBILITY.md (1)
56-64: Android SDK levels may be outdated soon.Consider targeting/compiling with the latest SDK (e.g., 34+) to satisfy Play requirements; document min/target separately.
README.md (2)
248-255: TypeScript enum caveat.If
BarcodeFormatis a string enum, cast is fine. If numeric,Object.valuesreturns mixed types. Ensure it’s string-valued or filter.Optional tweak:
- formats: Object.values(BarcodeFormat), // All supported formats + formats: Object.values(BarcodeFormat) as BarcodeFormat[], // All supported formats
97-101: Android SDK versions: consider updating compileSdk.Docs say
compileSdkVersion 33+. Align with current Android SDK level used in the project to avoid build warnings.example/App.tsx (3)
98-101: Normalize file:// URIs before scanning (Android safety).Some Android paths from ImagePicker include file://; native code often expects a raw path. Normalize before calling scan.
Apply this diff:
- const results = await ImageCodeScanner.scan({ - path: selectedImage, + const scanPath = + Platform.OS === 'android' && selectedImage.startsWith('file://') + ? selectedImage.slice(7) + : selectedImage; + const results = await ImageCodeScanner.scan({ + path: scanPath, formats: selectedFormats, });
25-32: Remove unused enabled flags in BARCODE_FORMATS.The enabled property isn’t read; it can mislead future readers.
Apply this diff:
-const BARCODE_FORMATS = [ - { key: BarcodeFormat.QR_CODE, label: 'QR Code', enabled: true }, - { key: BarcodeFormat.CODE_128, label: 'Code 128', enabled: false }, - { key: BarcodeFormat.CODE_39, label: 'Code 39', enabled: false }, - { key: BarcodeFormat.EAN_13, label: 'EAN-13', enabled: false }, - { key: BarcodeFormat.PDF_417, label: 'PDF417', enabled: false }, - { key: BarcodeFormat.DATA_MATRIX, label: 'Data Matrix', enabled: false }, -]; +const BARCODE_FORMATS = [ + { key: BarcodeFormat.QR_CODE, label: 'QR Code' }, + { key: BarcodeFormat.CODE_128, label: 'Code 128' }, + { key: BarcodeFormat.CODE_39, label: 'Code 39' }, + { key: BarcodeFormat.EAN_13, label: 'EAN-13' }, + { key: BarcodeFormat.PDF_417, label: 'PDF417' }, + { key: BarcodeFormat.DATA_MATRIX, label: 'Data Matrix' }, +];
34-284: Consolidate App implementations into a single source of truthWe’ve confirmed there are two distinct
App.tsxfiles in the example project, but only the root one is used as Expo’s entrypoint (example/package.json→"main": "App.tsx"). Maintaining both risks UI/style drift over time.Key locations:
example/package.json(defines"main": "App.tsx")example/App.tsx(active entrypoint)example/src/App.tsx(unused duplicate)Recommended refactors:
- Remove or archive
example/src/App.tsx, and consolidate any needed code into the rootApp.tsx- Or have the root
App.tsxre-export fromsrc/App.tsxand updatepackage.jsonif you prefer thesrcstructure- Ensure styles, fonts, and UI logic reside in a single file to prevent divergence
example/src/App.tsx (1)
105-109: Normalize file:// URIs before scanning (Android safety).Same concern as the other App: strip file:// when present.
Apply this diff:
- const results = await ImageCodeScanner.scan({ - path: selectedImage, + const scanPath = + Platform.OS === 'android' && selectedImage.startsWith('file://') + ? selectedImage.slice(7) + : selectedImage; + const results = await ImageCodeScanner.scan({ + path: scanPath, formats: selectedFormats, // Preprocessing is always enabled automatically for optimal results });src/index.tsx (1)
27-42: Harden formats handling and avoid redundant toString; add path normalization.
- Filter formats against known values; fallback if empty.
- Pass formats directly (already strings).
- Normalize file:// paths to raw paths before native call.
Apply this diff:
- const { path, formats = [BarcodeFormat.QR_CODE] } = options; + const { path, formats = [BarcodeFormat.QR_CODE] } = options; if (!path) { return Promise.reject(new Error('Image path is required')); } - const effectiveFormats = - Array.isArray(formats) && formats.length > 0 - ? formats - : [BarcodeFormat.QR_CODE]; + const allowed = new Set<string>(Object.values(BarcodeFormat)); + const normalizedFormats = + Array.isArray(formats) && formats.length > 0 + ? formats.filter((f) => allowed.has(f)) + : [BarcodeFormat.QR_CODE]; + const effectiveFormats = + normalizedFormats.length > 0 ? normalizedFormats : [BarcodeFormat.QR_CODE]; // Note: Preprocessing is always enabled in native implementation // The native code automatically tries multiple preprocessing techniques - const nativeOptions = { + const nativeOptions = { enhanceContrast: true, convertToGrayscale: true, tryRotations: true, }; return ImageCodeScanner.scanFromPath( - path, - effectiveFormats.map((f) => f.toString()), + path.startsWith('file://') ? path.slice(7) : path, + effectiveFormats, nativeOptions );Also applies to: 44-48
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (15)
CHANGELOG.md(2 hunks)COMPATIBILITY.md(1 hunks)README.md(14 hunks)eslint.config.mjs(1 hunks)example/App.tsx(1 hunks)example/README.md(1 hunks)example/babel.config.js(1 hunks)example/package.json(1 hunks)example/src/App.tsx(9 hunks)ios/ImageCodeScanner.mm(0 hunks)ios/ImageCodeScanner.swift(1 hunks)package.json(2 hunks)scripts/validate-package.js(4 hunks)src/NativeImageCodeScanner.ts(1 hunks)src/index.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- ios/ImageCodeScanner.mm
🧰 Additional context used
🧬 Code graph analysis (3)
example/App.tsx (1)
example/src/App.tsx (1)
App(36-257)
ios/ImageCodeScanner.swift (1)
android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt (4)
convertToGrayscale(77-93)name(19-265)enhanceContrast(48-75)scanFromPath(101-260)
scripts/validate-package.js (1)
eslint.config.mjs (1)
__dirname(9-9)
🪛 LanguageTool
COMPATIBILITY.md
[grammar] ~23-~23: There might be a mistake here.
Context: ...sions | React Version | Compatibility | |--------------|---------------| | 17.x ...
(QB_NEW_EN)
[grammar] ~24-~24: There might be a mistake here.
Context: ...ility | |--------------|---------------| | 17.x | ✅ Supported | | 18.x ...
(QB_NEW_EN)
[grammar] ~25-~25: There might be a mistake here.
Context: ...-------| | 17.x | ✅ Supported | | 18.x | ✅ Supported (Recommende...
(QB_NEW_EN)
[grammar] ~26-~26: There might be a mistake here.
Context: ....x | ✅ Supported (Recommended) | | 19.x | ✅ Supported (Beta) | #...
(QB_NEW_EN)
[grammar] ~31-~31: There might be a mistake here.
Context: ...eact Native | Package Version | Status | |----------|-------------|--------------...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: ...------------|-----------------|--------| | SDK 49 | 0.72.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~33-~33: There might be a mistake here.
Context: ... | Supported (requires prebuild) | | SDK 50 | 0.73.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~34-~34: There might be a mistake here.
Context: ... | Supported (requires prebuild) | | SDK 51 | 0.74.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~35-~35: There might be a mistake here.
Context: ... | Supported (requires prebuild) | | SDK 52 | 0.79.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~44-~44: There might be a mistake here.
Context: ...rements - Minimum iOS Version: 13.4 - Xcode: 14.0 or higher - Swift: 5.0...
(QB_NEW_EN)
[grammar] ~45-~45: There might be a mistake here.
Context: ...sion**: 13.4 - Xcode: 14.0 or higher - Swift: 5.0 or higher - **Frameworks Re...
(QB_NEW_EN)
[grammar] ~46-~46: There might be a mistake here.
Context: ...4.0 or higher - Swift: 5.0 or higher - Frameworks Required: - Vision Framew...
(QB_NEW_EN)
[grammar] ~47-~47: There might be a mistake here.
Context: ...5.0 or higher - Frameworks Required: - Vision Framework (iOS 11+) - Core Imag...
(QB_NEW_EN)
[grammar] ~48-~48: There might be a mistake here.
Context: ...quired**: - Vision Framework (iOS 11+) - Core Image (iOS 5+) - UIKit (iOS 2+) ...
(QB_NEW_EN)
[grammar] ~49-~49: There might be a mistake here.
Context: ...mework (iOS 11+) - Core Image (iOS 5+) - UIKit (iOS 2+) - Core Graphics (iOS 2+...
(QB_NEW_EN)
[grammar] ~50-~50: There might be a mistake here.
Context: ...- Core Image (iOS 5+) - UIKit (iOS 2+) - Core Graphics (iOS 2+) ### Android Requ...
(QB_NEW_EN)
[grammar] ~55-~55: There might be a mistake here.
Context: ...Minimum SDK**: 21 (Android 5.0 Lollipop) - Target SDK: 33+ (Android 13+) - **Comp...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...pop) - Target SDK: 33+ (Android 13+) - Compile SDK: 33+ - Kotlin: 1.6.0+ ...
(QB_NEW_EN)
[grammar] ~57-~57: There might be a mistake here.
Context: ...33+ (Android 13+) - Compile SDK: 33+ - Kotlin: 1.6.0+ - Gradle: 7.0+ - **...
(QB_NEW_EN)
[grammar] ~58-~58: There might be a mistake here.
Context: ...Compile SDK*: 33+ - Kotlin: 1.6.0+ - Gradle: 7.0+ - **Android Gradle Plugin...
(QB_NEW_EN)
[grammar] ~59-~59: There might be a mistake here.
Context: ... - Kotlin: 1.6.0+ - Gradle: 7.0+ - Android Gradle Plugin: 7.0+ - **Depend...
(QB_NEW_EN)
[grammar] ~60-~60: There might be a mistake here.
Context: ...: 7.0+ - Android Gradle Plugin: 7.0+ - Dependencies: - Google ML Kit Barcod...
(QB_NEW_EN)
[grammar] ~61-~61: There might be a mistake here.
Context: ...radle Plugin**: 7.0+ - Dependencies: - Google ML Kit Barcode Scanning: 17.3.0+ ...
(QB_NEW_EN)
[grammar] ~62-~62: There might be a mistake here.
Context: ... Google ML Kit Barcode Scanning: 17.3.0+ - AndroidX Camera Core: 1.3.1+ ### Node.j...
(QB_NEW_EN)
[grammar] ~67-~67: There might be a mistake here.
Context: ... Node.js: >=18.0.0 (LTS recommended) - npm: >=8.0.0 - Yarn: >=1.22.0 or >...
(QB_NEW_EN)
[grammar] ~68-~68: There might be a mistake here.
Context: ...0.0 (LTS recommended) - npm: >=8.0.0 - Yarn: >=1.22.0 or >=3.0.0 (Berry) ## ...
(QB_NEW_EN)
[grammar] ~155-~155: There might be a mistake here.
Context: ... Testing The library is tested against: - React Native 0.70.x (Old Architecture) -...
(QB_NEW_EN)
[grammar] ~156-~156: There might be a mistake here.
Context: ...- React Native 0.70.x (Old Architecture) - React Native 0.75.x (Both Architectures)...
(QB_NEW_EN)
[grammar] ~157-~157: There might be a mistake here.
Context: ...React Native 0.75.x (Both Architectures) - React Native 0.79.x (New Architecture) -...
(QB_NEW_EN)
[grammar] ~158-~158: There might be a mistake here.
Context: ...- React Native 0.79.x (New Architecture) - Latest React Native release ## Known Is...
(QB_NEW_EN)
[grammar] ~184-~184: There might be a mistake here.
Context: ... Latest 3 minor versions of React Native - Security Updates: Latest 6 minor versi...
(QB_NEW_EN)
[grammar] ~185-~185: There might be a mistake here.
Context: ... Latest 6 minor versions of React Native - Best Effort: Older versions on case-by...
(QB_NEW_EN)
[grammar] ~186-~186: There might be a mistake here.
Context: ...ative - Best Effort: Older versions on case-by-case basis ## Reporting Compat...
(QB_NEW_EN)
[grammar] ~194-~194: There might be a mistake here.
Context: ...nner/issues) 3. Create a new issue with: - React Native version - Package versio...
(QB_NEW_EN)
[grammar] ~195-~195: There might be a mistake here.
Context: ...ew issue with: - React Native version - Package version - Platform (iOS/Andro...
(QB_NEW_EN)
[grammar] ~196-~196: There might be a mistake here.
Context: ...eact Native version - Package version - Platform (iOS/Android) - Architecture...
(QB_NEW_EN)
[grammar] ~197-~197: There might be a mistake here.
Context: ...kage version - Platform (iOS/Android) - Architecture (Old/New) - Error messag...
(QB_NEW_EN)
[grammar] ~198-~198: There might be a mistake here.
Context: ...iOS/Android) - Architecture (Old/New) - Error messages/logs ## Resources - [Re...
(QB_NEW_EN)
CHANGELOG.md
[grammar] ~17-~17: There might be a mistake here.
Context: ...preprocessing** for optimal recognition: - Contrast enhancement - Grayscale conve...
(QB_NEW_EN)
[grammar] ~18-~18: There might be a mistake here.
Context: ...al recognition: - Contrast enhancement - Grayscale conversion - Multiple rotati...
(QB_NEW_EN)
[grammar] ~19-~19: There might be a mistake here.
Context: ...ast enhancement - Grayscale conversion - Multiple rotation attempts (0°, 90°, 180...
(QB_NEW_EN)
[grammar] ~20-~20: There might be a mistake here.
Context: ... rotation attempts (0°, 90°, 180°, 270°) - Ultra-simple API - just pass image pat...
(QB_NEW_EN)
[grammar] ~31-~31: There might be a mistake here.
Context: ...ng** enabled by default for best results - Smart retry logic with multiple image en...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: ...th multiple image enhancement techniques - No additional setup required for Android...
(QB_NEW_EN)
[grammar] ~33-~33: There might be a mistake here.
Context: ...No additional setup required for Android - Minimal iOS setup with just pod install ...
(QB_NEW_EN)
[grammar] ~34-~34: There might be a mistake here.
Context: ... Minimal iOS setup with just pod install - Expo integration with proper prebuild ...
(QB_NEW_EN)
[grammar] ~35-~35: There might be a mistake here.
Context: ...egration** with proper prebuild workflow - Modern example app using Expo Image Pi...
(QB_NEW_EN)
[grammar] ~36-~36: There might be a mistake here.
Context: ...** using Expo Image Picker and StatusBar - Simplified API - just pass image path ...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...API** - just pass image path and formats - Performance metrics and timing measure...
(QB_NEW_EN)
[grammar] ~40-~40: There might be a mistake here.
Context: ...g measurements ### Example App Features - Modern Expo-based example application - ...
(QB_NEW_EN)
[grammar] ~41-~41: There might be a mistake here.
Context: ... - Modern Expo-based example application - Barcode format selection UI with real-ti...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...rmat selection UI with real-time toggles - Automatic preprocessing info with option...
(QB_NEW_EN)
[grammar] ~43-~43: There might be a mistake here.
Context: ...essing info with optional disable switch - Improved error handling and user feedbac...
(QB_NEW_EN)
README.md
[grammar] ~35-~35: There might be a mistake here.
Context: ...nality) ## 📋 Supported Barcode Formats | Format | iOS | Android | | ------...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...Formats | Format | iOS | Android | | ----------- | --- | ------- | | QR Cod...
(QB_NEW_EN)
[grammar] ~38-~38: There might be a mistake here.
Context: ...ndroid | | ----------- | --- | ------- | | QR Code | ✅ | ✅ | | Code 128...
(QB_NEW_EN)
[grammar] ~39-~39: There might be a mistake here.
Context: ... ------- | | QR Code | ✅ | ✅ | | Code 128 | ✅ | ✅ | | Code 39 ...
(QB_NEW_EN)
[grammar] ~40-~40: There might be a mistake here.
Context: ...| ✅ | | Code 128 | ✅ | ✅ | | Code 39 | ✅ | ✅ | | Code 93 ...
(QB_NEW_EN)
[grammar] ~41-~41: There might be a mistake here.
Context: ...| ✅ | | Code 39 | ✅ | ✅ | | Code 93 | ✅ | ✅ | | EAN-13 ...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...| ✅ | | Code 93 | ✅ | ✅ | | EAN-13 | ✅ | ✅ | | EAN-8 ...
(QB_NEW_EN)
[grammar] ~43-~43: There might be a mistake here.
Context: ...| ✅ | | EAN-13 | ✅ | ✅ | | EAN-8 | ✅ | ✅ | | UPC-A ...
(QB_NEW_EN)
[grammar] ~44-~44: There might be a mistake here.
Context: ...| ✅ | | EAN-8 | ✅ | ✅ | | UPC-A | ✅ | ✅ | | UPC-E ...
(QB_NEW_EN)
[grammar] ~45-~45: There might be a mistake here.
Context: ...| ✅ | | UPC-A | ✅ | ✅ | | UPC-E | ✅ | ✅ | | PDF417 ...
(QB_NEW_EN)
[grammar] ~46-~46: There might be a mistake here.
Context: ...| ✅ | | UPC-E | ✅ | ✅ | | PDF417 | ✅ | ✅ | | Data Mat...
(QB_NEW_EN)
[grammar] ~47-~47: There might be a mistake here.
Context: ...| ✅ | | PDF417 | ✅ | ✅ | | Data Matrix | ✅ | ✅ | | Aztec ...
(QB_NEW_EN)
[grammar] ~48-~48: There might be a mistake here.
Context: ...| ✅ | | Data Matrix | ✅ | ✅ | | Aztec | ✅ | ✅ | | ITF ...
(QB_NEW_EN)
[grammar] ~49-~49: There might be a mistake here.
Context: ...| ✅ | | Aztec | ✅ | ✅ | | ITF | ✅ | ✅ | | Codabar ...
(QB_NEW_EN)
[grammar] ~50-~50: There might be a mistake here.
Context: ...| ✅ | | ITF | ✅ | ✅ | | Codabar | ✅ | ✅ | ## Compat...
(QB_NEW_EN)
[grammar] ~55-~55: There might be a mistake here.
Context: ... | | -------------------- | ---------------...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...-------------------------------------- | | 0.70.x - 0.74.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~57-~57: There might be a mistake here.
Context: ...Supported | | 0.75.x - 0.79.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~58-~58: There might be a mistake here.
Context: ...Supported (including New Architecture) | | 0.80.x+ | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~63-~63: There might be a mistake here.
Context: ...quirements - React Native: >=0.70.0 - React: >=17.0.0 - iOS: 13.4+ - **A...
(QB_NEW_EN)
[grammar] ~64-~64: There might be a mistake here.
Context: ...Native**: >=0.70.0 - React: >=17.0.0 - iOS: 13.4+ - Android: minSdkVersio...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a mistake here.
Context: ...0 - React: >=17.0.0 - iOS: 13.4+ - Android: minSdkVersion 21+ - Node:...
(QB_NEW_EN)
[grammar] ~66-~66: There might be a mistake here.
Context: ...: 13.4+ - Android: minSdkVersion 21+ - Node: >=18 ## Installation ```bash n...
(QB_NEW_EN)
[grammar] ~177-~177: There might be a mistake here.
Context: .... Original Image: First scan attempt 2. Grayscale Conversion: Improves detecti...
(QB_NEW_EN)
[grammar] ~178-~178: There might be a mistake here.
Context: ...mproves detection in colored backgrounds 3. Contrast Enhancement: Better recogniti...
(QB_NEW_EN)
[grammar] ~179-~179: There might be a mistake here.
Context: ...etter recognition in low-contrast images 4. Rotation Attempts: Tries 0°, 90°, 180°...
(QB_NEW_EN)
[grammar] ~274-~274: There might be a mistake here.
Context: ... | Required | Description | | --------- | ------------- | -------- |...
(QB_NEW_EN)
[grammar] ~275-~275: There might be a mistake here.
Context: ...-- | -------- | ---------------------- | | options | ScanOptions | Yes |...
(QB_NEW_EN)
[grammar] ~320-~320: There might be a mistake here.
Context: ... automatically - Smart Retry Logic: If initial scan fails, automatically tries...
(QB_NEW_EN)
[grammar] ~390-~390: There might be a mistake here.
Context: ...testing, but barcode scanning won't work - ⚡ Prebuild Mode: Full functionality ...
(QB_NEW_EN)
[grammar] ~391-~391: There might be a mistake here.
Context: ...scanning (requires Xcode/Android Studio) - 📖 **See [QUICK_START.md](./example/QUIC...
(QB_NEW_EN)
[grammar] ~392-~392: There might be a mistake here.
Context: ...RT.md)** for detailed setup instructions Platform Support: - 📱 iOS: Full ...
(QB_NEW_EN)
[grammar] ~396-~396: There might be a mistake here.
Context: ... iOS: Full camera and gallery access - 🤖 Android: Full camera and gallery ...
(QB_NEW_EN)
[grammar] ~397-~397: There might be a mistake here.
Context: ...ndroid**: Full camera and gallery access - 🌐 Web: Photo library access (camera...
(QB_NEW_EN)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (16)
scripts/validate-package.js (2)
6-8: Banner log LGTM.
Clear start message; no functional change.
49-52: JSON parsing block LGTM.
Readable and correctly scoped.example/package.json (1)
20-21: Expo dependency bump verified
- example/package.json shows:
- expo @~52.0.0
- expo-image-picker @~16.0.3
- expo-status-bar @~2.0.1
- .yarnrc.yml exists and has
nodeLinker: node-modules, so Yarn PnP won’t interfere with React Native tooling.Everything looks compatible with Expo 52.0.0. You can proceed, and as recommended, run
expo doctorandexpo prebuild --cleanwithin the example project to catch any remaining integration issues early.example/babel.config.js (1)
1-6: LGTM — minimal and correct Babel config for Expo.package.json (3)
4-4: Description update matches the new “automatic preprocessing” positioning.
85-104: Dev toolchain upgrades: verify full build and test environment on Node 18• React Native and CLI versions are correctly pegged to 0.79.2 and 15.0.0, respectively
•react-native-builder-bob(^0.40.13) and yourcodegenConfigblock are present in package.json
• Sandbox shows Node v24.3.0—please switch to Node 18.x (the RN 0.79 LTS recommendation) and ensure:
– A clean library build:
bash npx react-native-builder-bob build
– All tests (Jest preset for RN 0.79) pass:
bash npm test
• Finally, confirm that your codegen outputs are generated correctly under Bob’s build
106-108: No docs update needed: minimum versions already documentedThe minimum peer dependency versions (React >=17.0.0 and React Native >=0.70.0) are already reflected in the docs:
- README.md (lines 63–64):
“React Native: >=0.70.0” and “React: >=17.0.0”- COMPATIBILITY.md (lines 119–120):
"react": ">=17.0.0",and"react-native": ">=0.70.0"No additional changes required.
src/NativeImageCodeScanner.ts (1)
1-2: Import style change is fine.ios/ImageCodeScanner.swift (1)
8-13: Obj-C Shim Verified – No Further Action Required
I’ve confirmed thatios/ImageCodeScanner.mm(line 4) contains the required
RCT_EXTERN_MODULE(ImageCodeScanner, NSObject)shim, and your Swift class in
ios/ImageCodeScanner.swiftimplements bothmoduleName()and
requiresMainQueueSetup(). The native module is correctly exposed to React Native.COMPATIBILITY.md (2)
18-20: Forward-looking compatibility entries require tentative markingPlease update the COMPATIBILITY.md table (lines 18–20) to treat future compatibility as provisional:
For React Native 0.80.x+
• Change the Expo SDK column from “🔜 0.1.x” to “🔜 SDK 53” (the latest stable Expo SDK is 53) (expo.dev)
• Change the support column from “Ready when released” to “Tentative: confirm at SDK 53 stable release”For React Native 0.79.x / Expo SDK 52
• Clarify that SDK 52 is the current latest stable SDK fully supported by React Native 0.79.x (reactnative.dev)Once Expo SDK 53 and React Native 0.80.x+ are officially released and validated, update these entries with the final compatibility status.
65-70: All version requirements are in sync
- package.json
.engines.node>= 18 matches COMPATIBILITY.md’s Node.js >= 18.0.0 requirement.- package.json
.peerDependencies.react>= 17.0.0 and.peerDependencies.react-native>= 0.70.0 align with the React >= 17 and RN >= 0.70 entries in the docs.- GitHub Actions CI (publish.yml) installs Node 18 via
actions/setup-node@v4(node-version: '18'), satisfying the docs’ Node requirement.No further updates needed.
example/App.tsx (1)
327-333: Verify RN min version for gap style.gap in Flexbox requires newer RN. Confirm COMPATIBILITY.md declares a supported RN version where gap works across platforms.
example/src/App.tsx (2)
127-142: Nice guard: enforce at least one format.Prevents empty format arrays and avoids confusing scans.
303-307: Verify RN min version for gap style.gap requires recent RN; ensure compatibility matrix reflects this.
src/index.tsx (2)
36-43: Confirm native option keys match both platforms.Ensure enhanceContrast, convertToGrayscale, and tryRotations align with the native module signatures on iOS and Android.
20-23: API simplification looks good.Reducing ScanOptions to path and formats matches the example apps and docs.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)
149-156: Broken condition references undefinedsteps.cocoapods-cacheThis will evaluate against a non-existent step and can break the job. Either add the cache step with id
cocoapods-cacheor remove that part of the condition.Option A — add cache step (recommended):
build-ios: runs-on: macos-latest @@ - name: Cache turborepo for iOS uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 @@ + - name: Cache cocoapods + id: cocoapods-cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: | + example/ios/Pods + example/vendor/bundle + key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }} + restore-keys: | + ${{ runner.os }}-cocoapods- @@ - - name: Install cocoapods - if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true' + - name: Install cocoapods + if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true' run: | cd example bundle install bundle exec pod repo update --verbose bundle exec pod install --project-directory=iosOption B — simplify condition:
- - name: Install cocoapods - if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true' + - name: Install cocoapods + if: env.turbo_cache_hit != 1
🧹 Nitpick comments (9)
.github/actions/setup/action.yml (4)
12-15: Addcorepack installto honor repo’s Yarn version earlyEnsures the Yarn version from packageManager is prepared before caching/installs; fails fast if misconfigured.
- name: Enable Corepack run: corepack enable shell: bash + + - name: Prepare Yarn from packageManager + run: corepack install + shell: bash
20-27: Broaden cache key inputs to avoid stale cachesInclude Yarn config and plugins; these affect resolution.
with: path: | **/node_modules .yarn/cache .yarn/install-state.gz - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '!node_modules/**') }} + key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '.yarnrc.yml', '.yarn/plugins/**', '!node_modules/**') }} restore-keys: | ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} ${{ runner.os }}-yarn-
29-35: Ensure project cache is used (aligns with caching .yarn/cache)Without disabling the global cache here, Yarn may ignore .yarn/cache.
- name: Install dependencies if: steps.yarn-cache.outputs.cache-hit != 'true' run: yarn install --immutable shell: bash env: NODE_OPTIONS: --max-old-space-size=4096 + YARN_ENABLE_GLOBAL_CACHE: "false"
36-44: Mirror cache key improvements for save stepKeep save/restore keys consistent.
with: path: | **/node_modules .yarn/cache .yarn/install-state.gz - key: ${{ steps.yarn-cache.outputs.cache-primary-key }} + key: ${{ steps.yarn-cache.outputs.cache-primary-key }}Note: No change to the key expression; ensure the restore and save key inputs remain in sync after the earlier key update.
.github/workflows/ci.yml (2)
13-18: AddYARN_ENABLE_GLOBAL_CACHE: falsefor deterministic, repo-local cachingMatches env workflow and the composite action’s .yarn/cache strategy.
env: # Increase Node.js memory to prevent allocation errors NODE_OPTIONS: --max-old-space-size=4096 # Ensure Yarn uses immutable installs YARN_ENABLE_IMMUTABLE_INSTALLS: true + # Use project cache to match CI caching + YARN_ENABLE_GLOBAL_CACHE: false
70-85: Harden turbo cache detection stepFail fast on command errors and avoid unbound var pitfalls.
- name: Check turborepo cache for Android - run: | + run: | + set -euo pipefail TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir=\"${{ env.TURBO_CACHE_DIR }}\" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status") if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then echo "turbo_cache_hit=1" >> $GITHUB_ENV fiApply the same hardening to the iOS check (Lines 135-141).
.github/workflows/env.yml (3)
6-17: Trailing spaces detected; fix to satisfy lintersYAMLlint flags trailing whitespace on Lines 9, 13, 17.
NODE_OPTIONS: --max-old-space-size=4096 - + # Yarn settings for better CI performance YARN_ENABLE_IMMUTABLE_INSTALLS: true YARN_ENABLE_GLOBAL_CACHE: false - + # Disable telemetry for various tools NEXT_TELEMETRY_DISABLED: 1 TURBO_TELEMETRY_DISABLED: 1 - +
22-29: More trailing spaces (YAMLlint) and minor enhancementClean Lines 24 and 27; optionally output memory and versions in a single step to reduce overhead.
- name: Check Node version run: node --version - + - name: Check Yarn version run: yarn --version - + - name: Check available memory run: free -hOptional consolidation:
+ - name: Environment summary + run: | + echo "Node: $(node --version)" + echo "Yarn: $(yarn --version)" + echo "Memory:" + free -h
1-17: Make this reusable workflow effective by invoking itCurrently it’s defined but not used. If you intend to run it before CI, add a job in CI that “uses” this workflow.
Example in .github/workflows/ci.yml:
jobs: + preflight: + uses: ./.github/workflows/env.yml + lint:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (3)
.github/actions/setup/action.yml(2 hunks).github/workflows/ci.yml(1 hunks).github/workflows/env.yml(1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/env.yml
[error] 9-9: trailing spaces
(trailing-spaces)
[error] 13-13: trailing spaces
(trailing-spaces)
[error] 17-17: trailing spaces
(trailing-spaces)
[error] 24-24: trailing spaces
(trailing-spaces)
[error] 27-27: trailing spaces
(trailing-spaces)
🔇 Additional comments (1)
.github/workflows/ci.yml (1)
115-123: Verify Xcode 16.2 availability on macos-latest imagePinned versions can disappear from the runner image’s catalog; if unavailable, the job fails. Consider making this configurable or confirm availability.
…hance ESLint configuration
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
example/App.tsx (1)
385-408: Remove unused style rules (optionRow, optionLabel, warningText)They’re not referenced; trim to reduce noise.
warningText: { - fontSize: 13, - color: '#ff6b6b', - fontStyle: 'italic', - marginTop: 8, + // removed unused style },Alternatively, delete optionRow, optionLabel, and warningText blocks entirely.
🧹 Nitpick comments (9)
example/App.tsx (4)
42-85: Consolidate pickers into a single helper to remove duplication and centralize permission UXBoth image-picking functions duplicate logic. Combine them to cut maintenance and keep messages consistent.
- const pickImageFromCamera = async () => { - const { status } = await ImagePicker.requestCameraPermissionsAsync(); - if (status !== 'granted') { - Alert.alert( - 'Permission Denied', - 'Camera permission is required to take photos' - ); - return; - } - - const result = await ImagePicker.launchCameraAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.Images, - allowsEditing: false, - quality: 1, - }); - - if (!result.canceled && result.assets[0]) { - setSelectedImage(result.assets[0].uri); - setScanResult(null); - } - }; - - const pickImageFromGallery = async () => { - const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); - if (status !== 'granted') { - Alert.alert( - 'Permission Denied', - 'Gallery permission is required to select photos' - ); - return; - } - - const result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.Images, - allowsEditing: false, - quality: 1, - }); - - if (!result.canceled && result.assets[0]) { - setSelectedImage(result.assets[0].uri); - setScanResult(null); - } - }; + const handleImagePicker = async (type: 'camera' | 'gallery') => { + const perm = + type === 'camera' + ? await ImagePicker.requestCameraPermissionsAsync() + : await ImagePicker.requestMediaLibraryPermissionsAsync(); + if (perm.status !== 'granted') { + Alert.alert( + 'Permission Denied', + `${type === 'camera' ? 'Camera' : 'Gallery'} permission is required` + ); + return; + } + const result = + type === 'camera' + ? await ImagePicker.launchCameraAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.Images, + allowsEditing: false, + quality: 1, + }) + : await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.Images, + allowsEditing: false, + quality: 1, + }); + if (!result.canceled && result.assets[0]) { + setSelectedImage(result.assets[0].uri); + setScanResult(null); + } + };
157-168: Wire buttons to the unified picker helper- onPress={pickImageFromCamera} + onPress={() => handleImagePicker('camera')} ... - onPress={pickImageFromGallery} + onPress={() => handleImagePicker('gallery')}
111-116: Avoid duplicate UX: drop the alert; the UI already shows a no-results panelPrevents double messaging and keeps the flow quieter.
- if (results.length === 0) { - Alert.alert( - 'No Codes Found', - 'No barcodes were detected in the image. Try using a clearer image or different barcode formats.' - ); - }
327-364: The 'gap' style requires newer RN; add a fallback or adjust to margins to match stated RN >=0.70 supportRN’s flex gap landed relatively recently. Either keep the example’s minimum RN aligned with gap support or replace with margins between children.
CHANGELOG.md (1)
46-47: Fix inconsistency: example app doesn’t expose a disable switchChange “optional disable switch” to reflect the current implementation (info only).
-- Automatic preprocessing info with optional disable switch +- Automatic preprocessing info (always on in example)ios/ImageCodeScanner.swift (3)
191-194: Limit UPC_A mapping to EAN-13 to avoid unrelated UPC-E detectionsIncluding .upce widens results beyond the requested symbology.
- case "UPC_A": - symbologies.append(contentsOf: [.ean13, .upce]) // UPC-A via EAN-13 + UPC-E + case "UPC_A": + symbologies.append(.ean13) // UPC-A is represented as EAN-13 with leading 0
109-115: Unused parameter: optionsThe native signature exposes options but they aren’t used; JS docs show only path/formats. Align signatures or implement options-driven toggles to avoid confusion.
Do you want me to draft a follow-up aligning iOS/Android/TS to remove or use this argument?
116-173: Verbose logging: consider DEBUG gatingThe prints are helpful but noisy in production. Wrap with #if DEBUG or behind a module-level flag.
README.md (1)
55-60: Avoid promising support for unreleased RN versions“TBD” is safer than “Fully Supported (when released)”.
-| 0.80.x+ | ✅ 0.1.x | Fully Supported (when released) | +| 0.80.x+ | ✅ 0.1.x | Planned / TBD |
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
CHANGELOG.md(2 hunks)README.md(13 hunks)eslint.config.mjs(1 hunks)example/App.tsx(1 hunks)ios/ImageCodeScanner.swift(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- eslint.config.mjs
🧰 Additional context used
🧬 Code graph analysis (1)
example/App.tsx (1)
example/src/App.tsx (1)
App(36-257)
🪛 LanguageTool
README.md
[grammar] ~35-~35: There might be a mistake here.
Context: ...nality) ## 📋 Supported Barcode Formats | Format | iOS | Android | | ------...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...Formats | Format | iOS | Android | | ----------- | --- | ------- | | QR Cod...
(QB_NEW_EN)
[grammar] ~38-~38: There might be a mistake here.
Context: ...ndroid | | ----------- | --- | ------- | | QR Code | ✅ | ✅ | | Code 128...
(QB_NEW_EN)
[grammar] ~39-~39: There might be a mistake here.
Context: ... ------- | | QR Code | ✅ | ✅ | | Code 128 | ✅ | ✅ | | Code 39 ...
(QB_NEW_EN)
[grammar] ~40-~40: There might be a mistake here.
Context: ...| ✅ | | Code 128 | ✅ | ✅ | | Code 39 | ✅ | ✅ | | Code 93 ...
(QB_NEW_EN)
[grammar] ~41-~41: There might be a mistake here.
Context: ...| ✅ | | Code 39 | ✅ | ✅ | | Code 93 | ✅ | ✅ | | EAN-13 ...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...| ✅ | | Code 93 | ✅ | ✅ | | EAN-13 | ✅ | ✅ | | EAN-8 ...
(QB_NEW_EN)
[grammar] ~43-~43: There might be a mistake here.
Context: ...| ✅ | | EAN-13 | ✅ | ✅ | | EAN-8 | ✅ | ✅ | | UPC-A ...
(QB_NEW_EN)
[grammar] ~44-~44: There might be a mistake here.
Context: ...| ✅ | | EAN-8 | ✅ | ✅ | | UPC-A | ✅ | ✅ | | UPC-E ...
(QB_NEW_EN)
[grammar] ~45-~45: There might be a mistake here.
Context: ...| ✅ | | UPC-A | ✅ | ✅ | | UPC-E | ✅ | ✅ | | PDF417 ...
(QB_NEW_EN)
[grammar] ~46-~46: There might be a mistake here.
Context: ...| ✅ | | UPC-E | ✅ | ✅ | | PDF417 | ✅ | ✅ | | Data Mat...
(QB_NEW_EN)
[grammar] ~47-~47: There might be a mistake here.
Context: ...| ✅ | | PDF417 | ✅ | ✅ | | Data Matrix | ✅ | ✅ | | Aztec ...
(QB_NEW_EN)
[grammar] ~48-~48: There might be a mistake here.
Context: ...| ✅ | | Data Matrix | ✅ | ✅ | | Aztec | ✅ | ✅ | | ITF ...
(QB_NEW_EN)
[grammar] ~49-~49: There might be a mistake here.
Context: ...| ✅ | | Aztec | ✅ | ✅ | | ITF | ✅ | ✅ | | Codabar ...
(QB_NEW_EN)
[grammar] ~50-~50: There might be a mistake here.
Context: ...| ✅ | | ITF | ✅ | ✅ | | Codabar | ✅ | ✅ | ## Compat...
(QB_NEW_EN)
[grammar] ~55-~55: There might be a mistake here.
Context: ... | | -------------------- | ---------------...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...-------------------------------------- | | 0.70.x - 0.74.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~57-~57: There might be a mistake here.
Context: ...Supported | | 0.75.x - 0.79.x | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~58-~58: There might be a mistake here.
Context: ...Supported (including New Architecture) | | 0.80.x+ | ✅ 0.1.x ...
(QB_NEW_EN)
[grammar] ~63-~63: There might be a mistake here.
Context: ...quirements - React Native: >=0.70.0 - React: >=17.0.0 - iOS: 13.4+ - **A...
(QB_NEW_EN)
[grammar] ~64-~64: There might be a mistake here.
Context: ...Native**: >=0.70.0 - React: >=17.0.0 - iOS: 13.4+ - Android: minSdkVersio...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a mistake here.
Context: ...0 - React: >=17.0.0 - iOS: 13.4+ - Android: minSdkVersion 21+ - Node:...
(QB_NEW_EN)
[grammar] ~66-~66: There might be a mistake here.
Context: ...: 13.4+ - Android: minSdkVersion 21+ - Node: >=18 ## Installation ```bash n...
(QB_NEW_EN)
[grammar] ~177-~177: There might be a mistake here.
Context: .... Original Image: First scan attempt 2. Grayscale Conversion: Improves detecti...
(QB_NEW_EN)
[grammar] ~178-~178: There might be a mistake here.
Context: ...mproves detection in colored backgrounds 3. Contrast Enhancement: Better recogniti...
(QB_NEW_EN)
[grammar] ~179-~179: There might be a mistake here.
Context: ...etter recognition in low-contrast images 4. Rotation Attempts: Tries 0°, 90°, 180°...
(QB_NEW_EN)
[grammar] ~274-~274: There might be a mistake here.
Context: ... | Required | Description | | --------- | ------------- | -------- |...
(QB_NEW_EN)
[grammar] ~275-~275: There might be a mistake here.
Context: ...-- | -------- | ---------------------- | | options | ScanOptions | Yes |...
(QB_NEW_EN)
[grammar] ~320-~320: There might be a mistake here.
Context: ... automatically - Smart Retry Logic: If initial scan fails, automatically tries...
(QB_NEW_EN)
[grammar] ~381-~381: There might be a mistake here.
Context: ...mera and gallery using Expo Image Picker - Automatic preprocessing (always on; no m...
(QB_NEW_EN)
[grammar] ~382-~382: There might be a mistake here.
Context: ... (always on; no manual toggles required) - Multiple barcode format selection - Perf...
(QB_NEW_EN)
[grammar] ~383-~383: There might be a mistake here.
Context: ...red) - Multiple barcode format selection - Performance timing measurements - Beauti...
(QB_NEW_EN)
[grammar] ~384-~384: There might be a mistake here.
Context: ...ection - Performance timing measurements - Beautiful, responsive UI - Cross-platfor...
(QB_NEW_EN)
[grammar] ~385-~385: There might be a mistake here.
Context: ... measurements - Beautiful, responsive UI - Cross-platform support (iOS, Android, We...
(QB_NEW_EN)
[grammar] ~390-~390: There might be a mistake here.
Context: ...testing, but barcode scanning won't work - ⚡ Prebuild Mode: Full functionality ...
(QB_NEW_EN)
[grammar] ~391-~391: There might be a mistake here.
Context: ...scanning (requires Xcode/Android Studio) - 📖 **See [QUICK_START.md](./example/QUIC...
(QB_NEW_EN)
[grammar] ~392-~392: There might be a mistake here.
Context: ...RT.md)** for detailed setup instructions Platform Support: - 📱 iOS: Full ...
(QB_NEW_EN)
[grammar] ~396-~396: There might be a mistake here.
Context: ... iOS: Full camera and gallery access - 🤖 Android: Full camera and gallery ...
(QB_NEW_EN)
[grammar] ~397-~397: There might be a mistake here.
Context: ...ndroid**: Full camera and gallery access - 🌐 Web: Photo library access (camera...
(QB_NEW_EN)
CHANGELOG.md
[grammar] ~18-~18: There might be a mistake here.
Context: ...preprocessing** for optimal recognition: - Contrast enhancement - Grayscale conve...
(QB_NEW_EN)
[grammar] ~19-~19: There might be a mistake here.
Context: ...al recognition: - Contrast enhancement - Grayscale conversion - Multiple rotati...
(QB_NEW_EN)
[grammar] ~20-~20: There might be a mistake here.
Context: ...ast enhancement - Grayscale conversion - Multiple rotation attempts (0°, 90°, 180...
(QB_NEW_EN)
[grammar] ~21-~21: There might be a mistake here.
Context: ... rotation attempts (0°, 90°, 180°, 270°) - Ultra-simple API - just pass image pat...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: ...ght and performant native implementation - Automatic preprocessing enabled by def...
(QB_NEW_EN)
[grammar] ~33-~33: There might be a mistake here.
Context: ...ng** enabled by default for best results - Smart retry logic with multiple image en...
(QB_NEW_EN)
[grammar] ~34-~34: There might be a mistake here.
Context: ...th multiple image enhancement techniques - No additional setup required for Android...
(QB_NEW_EN)
[grammar] ~35-~35: There might be a mistake here.
Context: ...No additional setup required for Android - Minimal iOS setup with just pod install ...
(QB_NEW_EN)
[grammar] ~36-~36: There might be a mistake here.
Context: ... Minimal iOS setup with just pod install - Expo integration with proper prebuild ...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...egration** with proper prebuild workflow - Modern example app using Expo Image Pi...
(QB_NEW_EN)
[grammar] ~38-~38: There might be a mistake here.
Context: ...** using Expo Image Picker and StatusBar - Simplified API - just pass image path ...
(QB_NEW_EN)
[grammar] ~39-~39: There might be a mistake here.
Context: ...API** - just pass image path and formats - Performance metrics and timing measure...
(QB_NEW_EN)
[grammar] ~44-~44: There might be a mistake here.
Context: ... - Modern Expo-based example application - Barcode format selection UI with real-ti...
(QB_NEW_EN)
[grammar] ~45-~45: There might be a mistake here.
Context: ...rmat selection UI with real-time toggles - Automatic preprocessing info with option...
(QB_NEW_EN)
[grammar] ~46-~46: There might be a mistake here.
Context: ...essing info with optional disable switch - Improved error handling and user feedbac...
(QB_NEW_EN)
…refactor image decoding logic
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt (1)
206-213: Recycle bitmaps to prevent leaks; also clean up pending variants after success.Bitmaps are precomputed and kept in memory; recycle each after use and recycle remaining ones when a result is found.
fun tryNextImage() { if (currentIndex >= imagesToTry.size) { // No more images to try, return empty result val arr = Arguments.fromList(emptyList<String>()) promise.resolve(arr) return } @@ - val image = InputImage.fromBitmap(currentBitmap, 0) - val scanner = BarcodeScanning.getClient(scannerOptions) + val image = InputImage.fromBitmap(currentBitmap, 0) + val scanner = BarcodeScanning.getClient(scannerOptions) @@ .addOnSuccessListener { barcodes -> try { if (barcodes.isNotEmpty()) { // Found barcodes, process and return val codes = barcodes .mapNotNull { barcode -> val value = barcode.displayValue ?: barcode.rawValue value } .filter { it.isNotEmpty() } - val arr = Arguments.fromList(codes) - promise.resolve(arr) + val arr = Arguments.fromList(codes) + // Recycle remaining, unprocessed bitmaps + imagesToTry.drop(currentIndex).forEach { (_, bmp) -> + if (!bmp.isRecycled) bmp.recycle() + } + promise.resolve(arr) } else { // No barcodes found, try next preprocessing tryNextImage() } } catch (e: Exception) { android.util.Log.e("ImageCodeScanner", "Error processing results for $description", e) tryNextImage() } finally { scanner.close() + if (!currentBitmap.isRecycled) { + currentBitmap.recycle() + } } } .addOnFailureListener { exception -> android.util.Log.e("ImageCodeScanner", "Scan failed for $description: ${exception.message}") scanner.close() + if (!currentBitmap.isRecycled) { + currentBitmap.recycle() + } tryNextImage() }Also applies to: 221-249
🧹 Nitpick comments (6)
package.json (1)
105-106: Tighten peer dependency ranges to reflect tested support.
"react: >=17" and "react-native: >=0.70" are very broad and may accidentally accept React 19 or older RN where Turbo Modules/Codegen differ. Suggest narrowing to your validated band and documenting it in COMPATIBILITY.md.Apply if accurate for your tests:
"peerDependencies": { - "react": ">=17.0.0", - "react-native": ">=0.70.0" + "react": ">=18 <19", + "react-native": ">=0.72 <0.80" }android/build.gradle (2)
62-63: Java 17 upgrade: good; consider Gradle toolchains for portability.Compile/target 17 and jvmTarget=17 are fine. Optionally add Gradle toolchains to avoid local JDK drift in consumer apps.
Apply:
android { + java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } + } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" }Also applies to: 67-67
73-75: Duplicate source directory entry for codegen; keep one to avoid redundant scanning.Both paths resolve to the same location. Drop the duplicate.
sourceSets { main { java.srcDirs += [ - "${buildDir}/generated/source/codegen/java", - "build/generated/source/codegen/java" + "${buildDir}/generated/source/codegen/java" ] } }android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt (3)
175-202: Respect options parameter; avoid always doing all preprocess steps.Current code ignores options and forces all transforms, which costs CPU/memory. Gate by options with sensible defaults (true to preserve behavior).
- val imagesToTry = mutableListOf<Pair<String, Bitmap>>() - imagesToTry.add("Original" to bitmap) + val imagesToTry = mutableListOf<Pair<String, Bitmap>>() + imagesToTry.add("Original" to bitmap) + + val grayscaleEnabled = if (options.hasKey("convertToGrayscale")) options.getBoolean("convertToGrayscale") else true + val enhanceContrastEnabled = if (options.hasKey("enhanceContrast")) options.getBoolean("enhanceContrast") else true + val tryRotationsEnabled = if (options.hasKey("tryRotations")) options.getBoolean("tryRotations") else true @@ - // Always add grayscale version - try { - imagesToTry.add("Grayscale" to convertToGrayscale(bitmap)) - android.util.Log.d("ImageCodeScanner", "Added grayscale version") - } catch (e: Exception) { - android.util.Log.w("ImageCodeScanner", "Failed to create grayscale: ${e.message}") - } + if (grayscaleEnabled) { + try { + imagesToTry.add("Grayscale" to convertToGrayscale(bitmap)) + android.util.Log.d("ImageCodeScanner", "Added grayscale version") + } catch (e: Exception) { + android.util.Log.w("ImageCodeScanner", "Failed to create grayscale: ${e.message}") + } + } @@ - // Always add enhanced contrast version - try { - imagesToTry.add("Enhanced contrast" to enhanceContrast(bitmap)) - android.util.Log.d("ImageCodeScanner", "Added contrast enhanced version") - } catch (e: Exception) { - android.util.Log.w("ImageCodeScanner", "Failed to enhance contrast: ${e.message}") - } + if (enhanceContrastEnabled) { + try { + imagesToTry.add("Enhanced contrast" to enhanceContrast(bitmap)) + android.util.Log.d("ImageCodeScanner", "Added contrast enhanced version") + } catch (e: Exception) { + android.util.Log.w("ImageCodeScanner", "Failed to enhance contrast: ${e.message}") + } + } @@ - // Always add rotated versions - try { - imagesToTry.add("Rotated 90°" to rotateBitmap(bitmap, 90f)) - imagesToTry.add("Rotated 180°" to rotateBitmap(bitmap, 180f)) - imagesToTry.add("Rotated 270°" to rotateBitmap(bitmap, 270f)) - android.util.Log.d("ImageCodeScanner", "Added rotated versions") - } catch (e: Exception) { - android.util.Log.w("ImageCodeScanner", "Failed to rotate: ${e.message}") - } + if (tryRotationsEnabled) { + try { + imagesToTry.add("Rotated 90°" to rotateBitmap(bitmap, 90f)) + imagesToTry.add("Rotated 180°" to rotateBitmap(bitmap, 180f)) + imagesToTry.add("Rotated 270°" to rotateBitmap(bitmap, 270f)) + android.util.Log.d("ImageCodeScanner", "Added rotated versions") + } catch (e: Exception) { + android.util.Log.w("ImageCodeScanner", "Failed to rotate: ${e.message}") + } + }If your TS API intentionally removed user-tunable preprocessing, ignore this and keep all-true defaults.
217-219: Performance: reuse a single BarcodeScanner instance across attempts.Creating/closing a scanner per attempt adds overhead. Hoist
val scanner = BarcodeScanning.getClient(scannerOptions)outsidetryNextImage()and close it once when done.
217-219: Orientation handling: prefer EXIF-aware rotation for the original image.Using
InputImage.fromBitmap(..., 0)ignores EXIF. Consider reading EXIF viaExifInterfaceand rotating the original once instead of trying fixed 90° steps.Also applies to: 95-99
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
RNImageCodeScanner.podspec(1 hunks)android/build.gradle(1 hunks)android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt(2 hunks)package.json(2 hunks)react-native.config.js(1 hunks)
🔇 Additional comments (4)
package.json (2)
4-4: Description change LGTM; keep tagline consistent across docs.
Matches the simplified API direction. Ensure README, npm page, and repo description use the same phrasing.
84-102: DevDeps Alignment with RN 0.79/React 18 VerifiedAll of the updated development dependencies are compatible and no changes are required:
- ESLint 9.22.0 and eslint-config-prettier 9.1.0 are intended to be used together (v9 of the Prettier config supports ESLint v9).
- TypeScript ^5.3.0 is within the supported range for React 18 and React Native 0.79.x (the RN codegen tooling and tsconfig presets are fully compatible).
No further action needed.
react-native.config.js (1)
1-13: Confirm Autolinking Configuration
Thereact-native.config.jsat lines 1–13 looks correct for both iOS (podspecPath) and Android (sourceDir/manifestPath). To ensure the React Native CLI actually picks it up:• Add the CLI if missing
• In your package.json, under devDependencies, include:
json "@react-native-community/cli": "latest"
• Re-run config and inspect the specific entrynpx react-native config \ | jq '.dependencies["react-native-image-code-scanner"]'You should see an object containing your
podspecPathandsourceDirsettings.If that key is absent or empty, please verify your module’s name in its podspec/package.json and adjust accordingly.
android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt (1)
10-11: Base class switch to generated spec: LGTM.Aligns with codegen-based modules and keeps the JS name via ReactModule annotation.
| val bitmapOptions = BitmapFactory.Options() | ||
| bitmapOptions.inJustDecodeBounds = true | ||
| BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions) | ||
|
|
||
| // Calculate sample size if image is too large | ||
| var sampleSize = 1 | ||
| val maxDimension = 2048 | ||
| while (options.outWidth / sampleSize > maxDimension || options.outHeight / sampleSize > maxDimension) { | ||
| while (bitmapOptions.outWidth / sampleSize > maxDimension || bitmapOptions.outHeight / sampleSize > maxDimension) { | ||
| sampleSize *= 2 | ||
| } | ||
|
|
||
| options.inJustDecodeBounds = false | ||
| options.inSampleSize = sampleSize | ||
| bitmapOptions.inJustDecodeBounds = false | ||
| bitmapOptions.inSampleSize = sampleSize | ||
|
|
||
| val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, options) | ||
| val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions) | ||
| if (originalBitmap == null) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Bitmap sampling: add safe defaults and guard decode-bounds edge cases.
Set preferred config and recycle the original when a scaled copy is used to cut peak memory.
- val bitmapOptions = BitmapFactory.Options()
- bitmapOptions.inJustDecodeBounds = true
+ val bitmapOptions = BitmapFactory.Options().apply {
+ inJustDecodeBounds = true
+ inPreferredConfig = Bitmap.Config.ARGB_8888
+ }
BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions)
@@
- bitmapOptions.inJustDecodeBounds = false
- bitmapOptions.inSampleSize = sampleSize
+ bitmapOptions.inJustDecodeBounds = false
+ bitmapOptions.inSampleSize = sampleSize.coerceAtLeast(1)
@@
- val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions)
+ val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions)
if (originalBitmap == null) {
promise.reject("INVALID_IMAGE", "Cannot decode image file: $path", null)
return
}
@@
- val bitmap = scaleBitmapIfNeeded(originalBitmap)
+ val bitmap = scaleBitmapIfNeeded(originalBitmap)
+ if (bitmap !== originalBitmap && !originalBitmap.isRecycled) {
+ originalBitmap.recycle()
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val bitmapOptions = BitmapFactory.Options() | |
| bitmapOptions.inJustDecodeBounds = true | |
| BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions) | |
| // Calculate sample size if image is too large | |
| var sampleSize = 1 | |
| val maxDimension = 2048 | |
| while (options.outWidth / sampleSize > maxDimension || options.outHeight / sampleSize > maxDimension) { | |
| while (bitmapOptions.outWidth / sampleSize > maxDimension || bitmapOptions.outHeight / sampleSize > maxDimension) { | |
| sampleSize *= 2 | |
| } | |
| options.inJustDecodeBounds = false | |
| options.inSampleSize = sampleSize | |
| bitmapOptions.inJustDecodeBounds = false | |
| bitmapOptions.inSampleSize = sampleSize | |
| val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, options) | |
| val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions) | |
| if (originalBitmap == null) { | |
| val bitmapOptions = BitmapFactory.Options().apply { | |
| inJustDecodeBounds = true | |
| inPreferredConfig = Bitmap.Config.ARGB_8888 | |
| } | |
| BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions) | |
| // Calculate sample size if image is too large | |
| var sampleSize = 1 | |
| val maxDimension = 2048 | |
| while (bitmapOptions.outWidth / sampleSize > maxDimension || bitmapOptions.outHeight / sampleSize > maxDimension) { | |
| sampleSize *= 2 | |
| } | |
| bitmapOptions.inJustDecodeBounds = false | |
| bitmapOptions.inSampleSize = sampleSize.coerceAtLeast(1) | |
| val originalBitmap = BitmapFactory.decodeFile(imgFile.absolutePath, bitmapOptions) | |
| if (originalBitmap == null) { | |
| promise.reject("INVALID_IMAGE", "Cannot decode image file: $path", null) | |
| return | |
| } | |
| val bitmap = scaleBitmapIfNeeded(originalBitmap) | |
| if (bitmap !== originalBitmap && !originalBitmap.isRecycled) { | |
| originalBitmap.recycle() | |
| } |
🤖 Prompt for AI Agents
In android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt around
lines 115 to 130, the Bitmap decoding lacks safe defaults and edge-case guards:
set bitmapOptions.inPreferredConfig to Bitmap.Config.RGB_565 (or ARGB_8888 if
alpha needed) before decoding, protect against decodeFile returning 0 for
outWidth/outHeight by treating them as unknown (skip sampling loop or clamp
sampleSize to 1 if bounds are invalid), and after creating a scaled/copy bitmap
ensure the originalBitmap is recycled if it is not the same instance to free
memory; also set bitmapOptions.inMutable as needed for further operations.
Ensure sampleSize is at least 1 and cap it to avoid integer overflow.
|
|
||
| Pod::Spec.new do |s| | ||
| s.name = "ImageCodeScanner" | ||
| s.name = "RNImageCodeScanner" |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Pod rename aligns with autolinking; verify tags exist for CocoaPods fetch.
Rename to RNImageCodeScanner looks correct and matches react-native.config.js. Ensure a matching git tag exists for each version so pod install can resolve the source.
Run:
🏁 Script executed:
#!/bin/bash
# Confirm the config points to the new podspec name and the version tag exists
rg -n "podspecPath: './RNImageCodeScanner.podspec'"
git tag -l | rg -n "$(jq -r .version package.json)"Length of output: 195
🏁 Script executed:
#!/bin/bash
# Verify if any git tags exist matching the version from package.json
version=$(jq -r .version package.json)
echo "Checking for git tags matching version '${version}'..."
git tag -l "*${version}*"Length of output: 184
Action Required: Add Git tag for version 0.1.0
- The
RNImageCodeScanner.podspecrename aligns correctly with the entry inreact-native.config.jsat line 5. - No Git tags matching the current package version (
0.1.0) were found. A matching tag is required so that CocoaPods can resolve the source when runningpod install. - Please create and push a tag for this version (e.g.
v0.1.0) in the repository.
🤖 Prompt for AI Agents
In RNImageCodeScanner.podspec around line 6, the podspec version (0.1.0) has no
matching Git tag so CocoaPods cannot resolve the source; create and push a Git
tag that exactly matches the package version (for example v0.1.0) on the
repository, ensure the tag is pushed to the remote (origin) and points to the
commit that contains this podspec, and then verify by running a local pod
install or fetching tags so CocoaPods can resolve the source.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (4)
ios/ImageCodeScanner.swift (4)
14-16: Good reuse of CIContext to cut per-call overhead.
Re-using a shared CIContext avoids repeated GPU state setup. Nice.
30-33: Preserving scale and orientation on processed images is correct.
This keeps Vision orientation mapping accurate across preprocessing steps.Also applies to: 47-50
146-173: Good: preprocessing operates on the scaled base image.
Prevents full‑res processing spikes and keeps the pipeline consistent.
177-208: UPC_A format mapping is too broad; drop UPC‑E from UPC_A.
Users asking for UPC_A shouldn’t receive UPC‑E by default.- case "UPC_A": - symbologies.append(contentsOf: [.ean13, .upce]) // UPC-A via EAN-13 + UPC-E + case "UPC_A": + symbologies.append(.ean13) // UPC-A is encoded within EAN-13
🧹 Nitpick comments (11)
ios/ImageCodeScanner.swift (6)
23-26: Prefer typed Core Image APIs or keyed constants over string keys.
Reduces key-typo risk and improves readability.Example using CIFilter builtins (iOS 13+):
- let filter = CIFilter(name: "CIColorControls") - filter?.setValue(currentCIImage, forKey: "inputImage") - filter?.setValue(2.0, forKey: "inputContrast") - filter?.setValue(-0.2, forKey: "inputBrightness") - filter?.setValue(1.0, forKey: "inputSaturation") + let filter = CIFilter.colorControls() + filter.inputImage = currentCIImage + filter.contrast = 2.0 + filter.brightness = -0.2 + filter.saturation = 1.0If you can’t adopt builtins, at least use kCI* keyed constants:
- filter?.setValue(currentCIImage, forKey: "inputImage") + filter?.setValue(currentCIImage, forKey: kCIInputImageKey)Also applies to: 39-44
52-78: Rotate using UIGraphicsImageRenderer for consistency and clarity.
Aligns with the renderer used elsewhere and keeps scale handling uniform.- UIGraphicsBeginImageContextWithOptions(newSize, false, image.scale) - defer { UIGraphicsEndImageContext() } - guard let context = UIGraphicsGetCurrentContext() else { return nil } + let format = UIGraphicsImageRendererFormat.default() + format.scale = image.scale + let renderer = UIGraphicsImageRenderer(size: newSize, format: format) - context.translateBy(x: newSize.width / 2, y: newSize.height / 2) - context.rotate(by: radians) - image.draw(in: CGRect( - x: -image.size.width / 2, - y: -image.size.height / 2, - width: image.size.width, - height: image.size.height - )) - return UIGraphicsGetImageFromCurrentImageContext() + return renderer.image { ctx in + let c = ctx.cgContext + c.translateBy(x: newSize.width / 2, y: newSize.height / 2) + c.rotate(by: radians) + image.draw(in: CGRect(x: -image.size.width/2, y: -image.size.height/2, + width: image.size.width, height: image.size.height)) + }
80-93: Minor: consider point-sized renderer with image.scale to avoid “size” mismatches.
Current code renders in pixel coords (format.scale=1) then assigns the original scale, which can make UIImage.size (in points) less intuitive. Optional tweak below keeps 1:1 between size and scale.- let newSizePx = CGSize(width: newW, height: newH) - let format = UIGraphicsImageRendererFormat.default() - format.scale = 1 // render size is in pixels - let rendered = UIGraphicsImageRenderer(size: newSizePx, format: format).image { _ in - image.draw(in: CGRect(origin: .zero, size: newSizePx)) - } - return UIImage(cgImage: rendered.cgImage!, scale: image.scale, orientation: image.imageOrientation) + let newSizePt = CGSize(width: newW / image.scale, height: newH / image.scale) + let format = UIGraphicsImageRendererFormat.default() + format.scale = image.scale + let rendered = UIGraphicsImageRenderer(size: newSizePt, format: format).image { _ in + image.draw(in: CGRect(origin: .zero, size: newSizePt)) + } + return UIImage(cgImage: rendered.cgImage!, scale: image.scale, orientation: image.imageOrientation)
162-173: Generate rotated/derived images lazily to cut peak memory.
Prebuilding 6–7 large variants can exceed 100MB transiently. Build on demand via closures.- var imagesToTry: [(String, UIImage)] = [("Original", baseImage)] - if let grayscaleImage = convertToGrayscale(baseImage) { - imagesToTry.append(("Grayscale", grayscaleImage)) - } - if let contrastImage = enhanceContrast(baseImage) { - imagesToTry.append(("Enhanced contrast", contrastImage)) - } - if let rotated90 = rotateImage(baseImage, degrees: 90) { imagesToTry.append(("Rotated 90°", rotated90)) } - if let rotated180 = rotateImage(baseImage, degrees: 180) { imagesToTry.append(("Rotated 180°", rotated180)) } - if let rotated270 = rotateImage(baseImage, degrees: 270) { imagesToTry.append(("Rotated 270°", rotated270)) } + var imagesToTry: [(String, () -> UIImage?)] = [] + imagesToTry.append(("Original", { baseImage })) + imagesToTry.append(("Grayscale", { self.convertToGrayscale(baseImage) })) + imagesToTry.append(("Enhanced contrast", { self.enhanceContrast(baseImage) })) + imagesToTry.append(("Rotated 90°", { self.rotateImage(baseImage, degrees: 90) })) + imagesToTry.append(("Rotated 180°", { self.rotateImage(baseImage, degrees: 180) })) + imagesToTry.append(("Rotated 270°", { self.rotateImage(baseImage, degrees: 270) }))And adapt tryScanning to invoke closures:
- func tryScanning(images: [(String, UIImage)], index: Int) { + func tryScanning(images: [(String, () -> UIImage?)], index: Int) { @@ - let (description, currentImage) = images[index] + let (description, makeImage) = images[index] + guard let currentImage = makeImage() else { + tryScanning(images: images, index: index + 1) + return + }Also applies to: 215-233
174-213: Deduplicate symbologies before assigning to the request.
Prevents redundant work and simplifies debugging.// If no formats specified, default to QR if symbologies.isEmpty { symbologies.append(.qr) } + // Deduplicate + symbologies = Array(Set(symbologies))
116-173: Gate debug logs or switch to OSLog.
Reduces console noise in production apps.Example:
- print("ImageCodeScanner iOS - Starting scan with all preprocessing options enabled") + #if DEBUG + print("ImageCodeScanner iOS - Starting scan with all preprocessing options enabled") + #endifAlso applies to: 225-261, 284-286
.github/actions/setup/action.yml (2)
20-24: Trim cache scope to Yarn cache + install-state; avoid node_modules cachingCaching
**/node_modulesis large and brittle across runners; Yarn’s cache + install-state is sufficient and faster.path: | - **/node_modules .yarn/cache .yarn/install-state.gzpath: | - **/node_modules .yarn/cache .yarn/install-state.gzAlso applies to: 42-45
29-31: Consider always running yarn install even on cache hitsEven with a restored install state,
yarn install --immutableis cheap and verifies integrity/lifecycle scripts. Optional, but improves safety.- - name: Install dependencies - if: steps.yarn-cache.outputs.cache-hit != 'true' + - name: Install dependencies + # Run even on cache hits to verify state; Yarn no-ops when up-to-date.github/workflows/ci.yml (3)
109-114: Android build memory: prefer GRADLE_OPTS over JAVA_OPTSGradle honors
GRADLE_OPTS/org.gradle.jvmargs. AddGRADLE_OPTSfor clearer effect.- name: Build example for Android env: - JAVA_OPTS: '-XX:MaxHeapSize=6g' + JAVA_OPTS: '-XX:MaxHeapSize=6g' + GRADLE_OPTS: '-Xmx6g -XX:MaxMetaspaceSize=1g' run: | yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}"
160-167: Streamline Pods install; avoid unconditional repo updateUse
--repo-updatewithpod installand set Bundler path for cache affinity.run: | cd example - bundle install - bundle exec pod repo update --verbose - bundle exec pod install --project-directory=ios + bundle config set path 'vendor/bundle' + bundle install --jobs 4 --retry 3 + bundle exec pod install --project-directory=ios --repo-update
149-159: CI cache cleanup: remove unused Bundler path or configure Bundler
We’ve confirmed there is noGemfile/Gemfile.locknor any Bundler config underexample/, soexample/vendor/bundleis never populated and ends up as an empty cache entry. To keep the cache step accurate, either remove the Bundler path entirely or, if you intend to use Bundler, add aGemfile/Gemfile.lock, configurebundle install --path vendor/bundle, and include the lockfile in your cache key.• File:
.github/workflows/ci.yml(lines 149–159)
• Action: adjust the cachepath(and optionally thekeyif Bundler is added)Suggested optional diff:
with: path: | - example/ios/Pods - example/vendor/bundle + example/ios/Pods key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
.github/actions/setup/action.yml(1 hunks).github/workflows/ci.yml(3 hunks)ios/ImageCodeScanner.swift(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ios/ImageCodeScanner.swift (1)
android/src/main/java/com/imagecodescanner/ImageCodeScannerModule.kt (4)
convertToGrayscale(77-93)name(19-263)enhanceContrast(48-75)scanFromPath(101-258)
🔇 Additional comments (3)
ios/ImageCodeScanner.swift (2)
118-136: Promise resolution guard is solid.
Simple, thread-safe single-resolve pattern. LGTM.
265-267: Confirm necessity of forcing Revision1 on Simulator.
May reduce accuracy; use only if newer revisions crash on sim.Would you like me to check Apple’s latest Vision revision behavior on the simulator and propose a conditional based on iOS version?
.github/workflows/ci.yml (1)
13-17: Good: global immutable Yarn + increased Node memoryTop-level env aligns with deterministic installs and prevents OOMs.
| - name: Enable Corepack | ||
| run: corepack enable | ||
| shell: bash | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Corepack version pin: verify packageManager is set
Ensure package.json (and example/package.json if applicable) has a packageManager: "yarn@<exact>" entry so corepack enable activates the intended Yarn version.
🏁 Script executed:
#!/bin/bash
# Inspect packageManager fields
jq -r '.packageManager // "MISSING"' package.json 2>/dev/null || true
jq -r '.packageManager // "MISSING"' example/package.json 2>/dev/null || trueLength of output: 130
Add missing packageManager field to example/package.json
The root package.json already specifies "packageManager": "yarn@3.6.1", but example/package.json is missing this field. Without it, corepack enable may not pick up the intended Yarn version when running the example workflow.
• In example/package.json, add:
"packageManager": "yarn@3.6.1"to match the root configuration and ensure Corepack correctly activates Yarn v3.6.1.
🤖 Prompt for AI Agents
In .github/actions/setup/action.yml around lines 12 to 15: update the example
project's package.json to include the missing packageManager field so Corepack
uses the intended Yarn version; open example/package.json and add
"packageManager": "yarn@3.6.1" at the top-level of the JSON (alongside
name/version/etc.) to match the root package.json and ensure corepack enable
picks Yarn v3.6.1.
…uild process for iOS and Android
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (2)
.github/actions/setup/action.yml(1 hunks)example/package.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/actions/setup/action.yml
🔇 Additional comments (1)
example/package.json (1)
20-21: Confirm example package dependency updates; please verify SDK 52 in root and run Expo DoctorWe’ve confirmed that example/package.json has been updated as intended. Please take the following steps to ensure full Expo SDK 52 alignment:
- Verified in example/package.json (lines 20–21):
"expo-image-picker": "~16.0.3", "expo-status-bar": "~2.0.1",- Ensure your root package.json specifies Expo SDK 52 (e.g.
"expo": "~52.0.0").- Run
npx expo doctorin your local environment to validate compatibility and catch any mismatch warnings.
| "react": "18.3.1", | ||
| "react-native": "0.76.3", | ||
| "react-native-image-code-scanner": "file:../" | ||
| "react-native-image-code-scanner": "workspace:*" |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
workspace: is correct; ensure workspace wiring and CI install strategy.*
Confirm the lib is part of the root workspaces and that CI runs yarn install at the repo root (not in example/) to use the single lockfile.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Root lockfile present
test -f yarn.lock && echo "OK: root yarn.lock present"
# 2) Example has no nested lockfile
test ! -f example/yarn.lock && echo "OK: no example/yarn.lock"
# 3) Root workspaces declare example and the library
echo "Root workspaces:"
jq -r 'if (.workspaces|type)=="array" then .workspaces[] else .workspaces.packages[] end' package.json
# 4) The example depends on the local workspace
rg -nP '"react-native-image-code-scanner"\s*:\s*"workspace:\*"' example/package.json || { echo "Missing workspace:* dep"; exit 1; }
# 5) The library package exists in the repo
rg -nP '"name"\s*:\s*"react-native-image-code-scanner"' -g '!**/node_modules/**'
echo "If 3–5 look good, CI should install from root with --immutable using the single lockfile."Length of output: 824
Add the library to your root workspaces and verify CI installs from repo root
It looks like your root package.json’s workspaces only lists example, so the react-native-image-code-scanner package won’t be linked as a workspace. You’ll need to:
• In the repo-root package.json, update the workspaces field to include the library’s directory alongside example (e.g.
{
"workspaces": [
"example",
"path/to/react-native-image-code-scanner"
]
})
• Confirm that the CI pipeline runs yarn install (ideally with --immutable) from the repository root—not within example/—so both workspaces share the single lockfile.
• After updating, you should see both entries when running:
jq -r '.workspaces[]' package.jsonand the library will resolve via the workspace protocol.
🤖 Prompt for AI Agents
In example/package.json around line 23, the dependency uses the workspace
protocol but the repo-root package.json workspaces only list "example", so the
library won't be linked as a workspace; update the repo-root package.json
"workspaces" array to include the react-native-image-code-scanner package
directory alongside "example" (e.g. add its relative path), ensure CI runs yarn
install from the repository root (preferably yarn install --immutable) so the
single lockfile is used, and verify by running jq -r '.workspaces[]'
package.json at the repo root to confirm both entries are present and the
package resolves via the workspace protocol.
…uild commands for Android and iOS
- Add react-native@0.76.9 as explicit dependency (required for Expo SDK 52) - Remove unsupported --non-interactive flag from build scripts - Rely on CI=1 environment variable set in GitHub Actions workflow - This fixes the Input is required error during CI builds
…uild - Move pod install into the build:ios script after expo prebuild - Remove separate CocoaPods installation step from workflow - This ensures the ios directory exists before trying to install pods - Fixes the "is not a valid directory" error in CI
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.github/workflows/ci.yml (2)
85-91: Quote bug breaks Node expression; switch to jq or fix quoting.The outer double quotes conflict with the inner ones, risking a syntax error in
node -p. Prefer jq for robustness.Option A (recommended, jq):
- TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status") + TURBO_CACHE_STATUS=$(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json \ + | jq -r '.tasks[] | select(.task=="build:android") | .cache.status')Option B (fix quoting with single-quoted outer string):
- TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status") + TURBO_CACHE_STATUS=$(node -p '($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === "build:android").cache.status')
149-154: Repeat the Android quote issue for iOS cache check.Apply the same jq (or quoting) fix to avoid breaking
node -p.- TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status") + TURBO_CACHE_STATUS=$(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json \ + | jq -r '.tasks[] | select(.task=="build:ios") | .cache.status')
♻️ Duplicate comments (1)
example/package.json (1)
24-24: workspace: is correct; ensure workspace wiring and CI install strategy.*Root package.json must include both the example and the library in “workspaces”, and CI should run yarn install from the repo root using the single lockfile.
Run:
#!/bin/bash set -euo pipefail echo "1) Root lockfile:" test -f yarn.lock && echo "OK: root yarn.lock present" || { echo "Missing root yarn.lock"; exit 1; } echo "2) No nested lockfile in example/:" test ! -f example/yarn.lock && echo "OK: no example/yarn.lock" || { echo "Found example/yarn.lock"; exit 1; } echo "3) Root workspaces list:" jq -r 'if (.workspaces|type)=="array" then .workspaces[] else .workspaces.packages[] end' package.json echo "4) Example depends on the library via workspace protocol:" rg -nP '"react-native-image-code-scanner"\\s*:\\s*"workspace:\\*"' example/package.json || { echo "Missing workspace:* dep"; exit 1; } echo "5) Library package detected in repo:" rg -nP '"name"\\s*:\\s*"react-native-image-code-scanner"' -g '!**/node_modules/**'
🧹 Nitpick comments (7)
example/package.json (1)
15-16: Harden CI build scripts: add Gradle flags and disable iOS code signing.Add --no-daemon/--stacktrace for Gradle reliability and CODE_SIGNING_ALLOWED=NO to avoid CI signing prompts.
Apply this diff:
-"build:android": "expo prebuild --platform android && cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug", +"build:android": "expo prebuild --platform android && cd android && ./gradlew --no-daemon --stacktrace assembleDebug assembleAndroidTest -DtestBuildType=debug", -"build:ios": "expo prebuild --platform ios && cd ios && xcodebuild -workspace ImageCodeScannerExample.xcworkspace -scheme ImageCodeScannerExample -configuration Debug -sdk iphonesimulator -derivedDataPath build" +"build:ios": "expo prebuild --platform ios && cd ios && xcodebuild -workspace ImageCodeScannerExample.xcworkspace -scheme ImageCodeScannerExample -configuration Debug -sdk iphonesimulator -derivedDataPath build CODE_SIGNING_ALLOWED=NO"Also verify the workspace/scheme name “ImageCodeScannerExample” matches the generated Xcode project after prebuild.
.github/workflows/ci.yml (6)
71-75: Redundant NODE_OPTIONS override; rely on the top-level env.Since Lines 13–17 already set NODE_OPTIONS, you can drop this per-step override to reduce noise.
- - name: Install example dependencies - run: cd example && yarn install --immutable - env: - NODE_OPTIONS: --max-old-space-size=4096 + - name: Install example dependencies + run: cd example && yarn install --immutable
117-119: Prefer GRADLE_OPTS/org.gradle.jvmargs over JAVA_OPTS for reliable Gradle heap tuning.Gradle may not honor JAVA_OPTS in all launch contexts. Set GRADLE_OPTS or pass org.gradle.jvmargs.
- name: Build example for Android env: - JAVA_OPTS: '-XX:MaxHeapSize=6g' + JAVA_OPTS: '-XX:MaxHeapSize=6g' + GRADLE_OPTS: '-Xmx6g -Dorg.gradle.jvmargs=-Xmx6g' CI: 1
135-139: Same redundancy here; drop per-step NODE_OPTIONS.Top-level env already covers this.
- - name: Install example dependencies - run: cd example && yarn install --immutable - env: - NODE_OPTIONS: --max-old-space-size=4096 + - name: Install example dependencies + run: cd example && yarn install --immutable
163-163: Gating CocoaPods on turbo cache hit is clever; add a safety check.If a cache is mistakenly HIT on a cold workspace, Pods might be missing. Consider also ensuring
Pods/Manifest.lockexists before skipping.- - name: Install cocoapods - if: env.turbo_cache_hit != 1 + - name: Install cocoapods + if: env.turbo_cache_hit != 1 run: | cd example + if [ ! -f "ios/Pods/Manifest.lock" ]; then export FORCE_POD_INSTALL=1; fi if [ -f "Gemfile" ]; then bundle install - bundle exec pod repo update --verbose - bundle exec pod install --project-directory=ios + bundle exec pod install --project-directory=ios ${FORCE_POD_INSTALL:+--repo-update} else - pod install --project-directory=ios + pod install --project-directory=ios ${FORCE_POD_INSTALL:+--repo-update} fi
166-172: Speed up CocoaPods: avoid unconditional repo updates and cache Bundler.Use
--repo-updateonly when needed (as above) and add Bundler caching viaruby/setup-rubyfor faster builds.I can draft a small step using
ruby/setup-ruby@v1withbundler-cache: trueright before this step if you want it included here.
175-176: Redundant CI env at step-level.Already set at the job level; safe to remove.
- - name: Build example for iOS - env: - CI: 1 + - name: Build example for iOS run: | yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (3)
.github/workflows/ci.yml(5 hunks)example/package.json(1 hunks)package.json(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-android
🔇 Additional comments (6)
example/package.json (3)
8-9: Switch to expo run for platform builds looks right.These scripts align with the native build flow introduced by Expo SDK 52.
20-21: Expo SDK 52 patch bumps look good.expo-image-picker ~16.0.3 and expo-status-bar ~2.0.1 match the SDK 52 range.
23-23: Double-check React Native version alignment with Expo 52.Ensure 0.76.9 matches what Expo 52 expects in this repo configuration; if uncertain, run “expo install react-native” to sync.
.github/workflows/ci.yml (3)
63-63: Setting CI=1 at the job level is fine.Many tools key off this flag; having it explicit per job is OK.
127-127: CI=1 on iOS job is fine.Consistent with Android.
13-17: CI Setup Verified – Corepack Enablement and Yarn Pinning PresentThe composite action at .github/actions/setup/action.yml includes a dedicated Enable Corepack step running
corepack enable, and the root package.json has"packageManager": "yarn@3.6.1", ensuring the Yarn version is pinned and preventing classic-vs-Berry drift. No additional changes are required here.
Description
This PR addresses multiple critical issues preventing successful CI builds and Android compilation:
🐛 Problems Fixed
CI Workflow Failures
yarn.lockfile causingYN0028error with--immutableflagAndroid Build Failures
Changes
CI/GitHub Actions
yarn.lockto version control for deterministic buildsNODE_OPTIONS: --max-old-space-size=4096).yarn/cacheto dependency caching strategyenv.yml)Android
com.imagecodescanner.NativeImageCodeScannerSpec)options→bitmapOptions)scanCompletedvariableDocumentation & Other
Testing
Breaking Changes
None - These are internal build fixes that don't affect the API.
Type of Change
Checklist
Summary by CodeRabbit
New Features
Example App
Documentation