expo-camera 55.0.15 → 55.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/android/build.gradle +2 -2
  3. package/expo-module.config.json +3 -2
  4. package/ios/CameraViewModule.swift +3 -6
  5. package/ios/Current/BarcodeScanner.swift +37 -17
  6. package/ios/Current/BarcodeScannerUtils.swift +0 -36
  7. package/ios/Current/ExpoBarcodeScannerProvider.swift +13 -0
  8. package/ios/Current/MetaDataDelegate.swift +22 -44
  9. package/ios/ExpoCamera.podspec +2 -13
  10. package/ios/ExpoCameraBarcodeScanning.podspec +29 -0
  11. package/ios/barcode-scanning/ExpoCameraZXingProvider.swift +44 -0
  12. package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.module → 55.0.16/expo.modules.camera-55.0.16.module} +7 -7
  13. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.module.md5 +1 -0
  14. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.module.sha1 +1 -0
  15. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.module.sha256 +1 -0
  16. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.module.sha512 +1 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.pom → 55.0.16/expo.modules.camera-55.0.16.pom} +1 -1
  18. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.pom.md5 +1 -0
  19. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.pom.sha1 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.pom.sha256 +1 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.16/expo.modules.camera-55.0.16.pom.sha512 +1 -0
  22. package/local-maven-repo/host/exp/exponent/expo.modules.camera/maven-metadata.xml +4 -4
  23. package/local-maven-repo/host/exp/exponent/expo.modules.camera/maven-metadata.xml.md5 +1 -1
  24. package/local-maven-repo/host/exp/exponent/expo.modules.camera/maven-metadata.xml.sha1 +1 -1
  25. package/local-maven-repo/host/exp/exponent/expo.modules.camera/maven-metadata.xml.sha256 +1 -1
  26. package/local-maven-repo/host/exp/exponent/expo.modules.camera/maven-metadata.xml.sha512 +1 -1
  27. package/package.json +2 -2
  28. package/prebuilds/output/debug/xcframeworks/ExpoCamera.tar.gz +0 -0
  29. package/prebuilds/output/debug/xcframeworks/ExpoCameraBarcodeScanning.tar.gz +0 -0
  30. package/prebuilds/output/release/xcframeworks/ExpoCamera.tar.gz +0 -0
  31. package/prebuilds/output/release/xcframeworks/ExpoCameraBarcodeScanning.tar.gz +0 -0
  32. package/spm.config.json +35 -11
  33. package/ios/Current/BarcodeScannerUnavailable.swift +0 -40
  34. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.module.md5 +0 -1
  35. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.module.sha1 +0 -1
  36. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.module.sha256 +0 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.module.sha512 +0 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.pom.md5 +0 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.pom.sha1 +0 -1
  40. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.pom.sha256 +0 -1
  41. package/local-maven-repo/host/exp/exponent/expo.modules.camera/55.0.15/expo.modules.camera-55.0.15.pom.sha512 +0 -1
  42. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15-sources.jar → 55.0.16/expo.modules.camera-55.0.16-sources.jar} +0 -0
  43. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15-sources.jar.md5 → 55.0.16/expo.modules.camera-55.0.16-sources.jar.md5} +0 -0
  44. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15-sources.jar.sha1 → 55.0.16/expo.modules.camera-55.0.16-sources.jar.sha1} +0 -0
  45. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15-sources.jar.sha256 → 55.0.16/expo.modules.camera-55.0.16-sources.jar.sha256} +0 -0
  46. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15-sources.jar.sha512 → 55.0.16/expo.modules.camera-55.0.16-sources.jar.sha512} +0 -0
  47. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.aar → 55.0.16/expo.modules.camera-55.0.16.aar} +0 -0
  48. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.aar.md5 → 55.0.16/expo.modules.camera-55.0.16.aar.md5} +0 -0
  49. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.aar.sha1 → 55.0.16/expo.modules.camera-55.0.16.aar.sha1} +0 -0
  50. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.aar.sha256 → 55.0.16/expo.modules.camera-55.0.16.aar.sha256} +0 -0
  51. /package/local-maven-repo/host/exp/exponent/expo.modules.camera/{55.0.15/expo.modules.camera-55.0.15.aar.sha512 → 55.0.16/expo.modules.camera-55.0.16.aar.sha512} +0 -0
package/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 55.0.16 — 2026-04-21
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [iOS] Fix inconsistent barcode `type` value returned by ZXing fallback scanner (code39, pdf417, codabar) — it now returns the same format as the AVFoundation scanner (e.g. `"code39"` instead of `"org.iso.Code39"`). ([#44726](https://github.com/expo/expo/pull/44726) by [@jensdev](https://github.com/jensdev))
18
+
13
19
  ## 55.0.15 — 2026-04-09
14
20
 
15
21
  _This version does not introduce any user-facing changes._
@@ -38,6 +44,7 @@ _This version does not introduce any user-facing changes._
38
44
 
39
45
  - [Web] Fix `isAvailableAsync` returning `true` on devices without a camera. ([#43932](https://github.com/expo/expo/pull/43932) by [@alanjhughes](https://github.com/alanjhughes))
40
46
  - [iOS] Added explicit `import React` for xcframework compatibility. ([#44248](https://github.com/expo/expo/pull/44248) by [@chrfalch](https://github.com/chrfalch))
47
+ - [iOS] Extract barcode scanning (ZXingObjC) into a separate `ExpoCameraBarcodeScanning` companion pod. Disabling barcode scanning via config plugin now correctly excludes ZXingObjC from precompiled builds, reducing binary size. (by [@chrfalch](https://github.com/chrfalch)) ([#44766](https://github.com/expo/expo/pull/44766) by [@chrfalch](https://github.com/chrfalch))
41
48
 
42
49
  ## 55.0.9 — 2026-02-25
43
50
 
@@ -4,7 +4,7 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '55.0.15'
7
+ version = '55.0.16'
8
8
 
9
9
  def barcodeScannerEnabled = findProperty('expo.camera.barcode-scanner-enabled')
10
10
  def isBarcodeScannerEnabled = (barcodeScannerEnabled ?: "true").toString() != "false"
@@ -13,7 +13,7 @@ android {
13
13
  namespace "expo.modules.camera"
14
14
  defaultConfig {
15
15
  versionCode 32
16
- versionName "55.0.15"
16
+ versionName "55.0.16"
17
17
  }
18
18
  }
19
19
 
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "platforms": ["apple", "android", "web"],
3
3
  "apple": {
4
- "modules": ["CameraViewModule"]
4
+ "modules": ["CameraViewModule"],
5
+ "podspecPath": ["ios/ExpoCamera.podspec"]
5
6
  },
6
7
  "android": {
7
8
  "modules": ["expo.modules.camera.CameraViewModule"],
8
9
  "publication": {
9
10
  "groupId": "host.exp.exponent",
10
11
  "artifactId": "expo.modules.camera",
11
- "version": "55.0.15",
12
+ "version": "55.0.16",
12
13
  "repository": "local-maven-repo"
13
14
  }
14
15
  }
@@ -148,7 +148,6 @@ public final class CameraViewModule: Module, ScannerResultHandler {
148
148
  }
149
149
 
150
150
  Prop("barcodeScannerEnabled") { (view, scanBarcodes: Bool?) in
151
- #if canImport(ZXingObjC)
152
151
  if let scanBarcodes, view.isScanningBarcodes != scanBarcodes {
153
152
  view.isScanningBarcodes = scanBarcodes
154
153
  return
@@ -156,17 +155,15 @@ public final class CameraViewModule: Module, ScannerResultHandler {
156
155
  if scanBarcodes == nil && view.isScanningBarcodes != false {
157
156
  view.isScanningBarcodes = false
158
157
  }
159
- #endif
160
158
  }
161
159
 
162
160
  Prop("barcodeScannerSettings") { (view, settings: BarcodeSettings?) in
163
- #if canImport(ZXingObjC)
164
161
  if let settings {
162
+ if view.barcodeScanner?.isAvailable == false {
163
+ self.appContext?.jsLogger.warn("Barcode scanning has been disabled")
164
+ }
165
165
  view.setBarcodeScannerSettings(settings: settings)
166
166
  }
167
- #else
168
- self.appContext?.jsLogger.warn("Barcode scanning has been disabled")
169
- #endif
170
167
  }
171
168
 
172
169
  Prop("mute") { (view, muted: Bool?) in
@@ -2,9 +2,6 @@ import AVFoundation
2
2
 
3
3
  let BARCODE_TYPES_KEY = "barcodeTypes"
4
4
 
5
- #if canImport(ZXingObjC)
6
- import ZXingObjC
7
-
8
5
  class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
9
6
  private var onBarcodeScanned: (([String: Any]?) -> Void)?
10
7
  var isScanningBarcodes = false
@@ -13,26 +10,37 @@ class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
13
10
 
14
11
  private let session: AVCaptureSession
15
12
  private let sessionQueue: DispatchQueue
16
- private let zxingCaptureQueue = DispatchQueue(label: "com.zxing.captureQueue")
13
+ private let captureQueue = DispatchQueue(label: "com.expo.barcodeScannerCaptureQueue")
17
14
 
18
15
  private var metadataOutput: AVCaptureMetadataOutput?
19
16
  private var videoDataOutput: AVCaptureVideoDataOutput?
20
17
  private var settings = BarcodeScannerUtils.getDefaultSettings()
21
- private var zxingBarcodeReaders: [AVMetadataObject.ObjectType: ZXReader] = [
22
- AVMetadataObject.ObjectType.pdf417: ZXPDF417Reader(),
23
- AVMetadataObject.ObjectType.code39: ZXCode39Reader()
24
- ]
25
18
  private var previewLayer: AVCaptureVideoPreviewLayer?
26
- private var zxingEnabled = true
19
+ private var barcodeProviderEnabled = true
27
20
  private var delegate: MetaDataDelegate?
28
21
 
22
+ private let barcodeProvider: ExpoBarcodeScannerProvider?
23
+
29
24
  init(session: AVCaptureSession, sessionQueue: DispatchQueue) {
30
25
  self.session = session
31
26
  self.sessionQueue = sessionQueue
27
+ self.barcodeProvider = BarcodeScanner.discoverProvider()
28
+ }
32
29
 
33
- if #available(iOS 15.4, *) {
34
- zxingBarcodeReaders[AVMetadataObject.ObjectType.codabar] = ZXCodaBarReader()
30
+ /// True when a barcode scanner provider is available (the companion pod is linked).
31
+ var isAvailable: Bool {
32
+ return barcodeProvider != nil
33
+ }
34
+
35
+ /// Discovers the optional barcode scanner provider at runtime.
36
+ /// The provider module registers by exposing a class named "ExpoCameraZXingProvider"
37
+ /// that conforms to ExpoBarcodeScannerProvider. Returns nil if the provider pod isn't linked.
38
+ static func discoverProvider() -> ExpoBarcodeScannerProvider? {
39
+ guard let cls = NSClassFromString("ExpoCameraZXingProvider") as? NSObject.Type,
40
+ let instance = cls.init() as? ExpoBarcodeScannerProvider else {
41
+ return nil
35
42
  }
43
+ return instance
36
44
  }
37
45
 
38
46
  func setSettings(_ newSettings: [String: [AVMetadataObject.ObjectType]]) {
@@ -41,8 +49,13 @@ class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
41
49
  let newTypes = Set(value)
42
50
  if previousTypes != newTypes {
43
51
  settings[BARCODE_TYPES_KEY] = value
44
- let zxingCoveredTypes = Set(zxingBarcodeReaders.keys)
45
- zxingEnabled = !zxingCoveredTypes.isDisjoint(with: newTypes)
52
+ if let barcodeProvider {
53
+ let supportedTypeSet = Set(barcodeProvider.supportedTypes)
54
+ let requestedRawValues = Set(newTypes.map { $0.rawValue })
55
+ barcodeProviderEnabled = !supportedTypeSet.isDisjoint(with: requestedRawValues)
56
+ } else {
57
+ barcodeProviderEnabled = false
58
+ }
46
59
  maybeStartBarcodeScanning()
47
60
  }
48
61
  }
@@ -85,6 +98,10 @@ class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
85
98
  return
86
99
  }
87
100
 
101
+ guard barcodeProvider != nil else {
102
+ return
103
+ }
104
+
88
105
  if metadataOutput == nil || videoDataOutput == nil {
89
106
  addOutputs()
90
107
  if metadataOutput == nil {
@@ -108,11 +125,15 @@ class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
108
125
  }
109
126
 
110
127
  private func addOutputs() {
128
+ guard let barcodeProvider else {
129
+ return
130
+ }
131
+
111
132
  delegate = MetaDataDelegate(
112
133
  settings: settings,
113
134
  previewLayer: previewLayer,
114
- zxingBarcodeReaders: zxingBarcodeReaders,
115
- zxingEnabled: zxingEnabled,
135
+ barcodeProvider: barcodeProvider,
136
+ barcodeProviderEnabled: barcodeProviderEnabled,
116
137
  metadataResultHandler: self)
117
138
 
118
139
  session.beginConfiguration()
@@ -129,7 +150,7 @@ class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
129
150
  let output = AVCaptureVideoDataOutput()
130
151
  output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
131
152
  output.alwaysDiscardsLateVideoFrames = true
132
- output.setSampleBufferDelegate(delegate, queue: zxingCaptureQueue)
153
+ output.setSampleBufferDelegate(delegate, queue: captureQueue)
133
154
  if session.canAddOutput(output) {
134
155
  session.addOutput(output)
135
156
  videoDataOutput = output
@@ -161,4 +182,3 @@ class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
161
182
  self.onBarcodeScanned?(result)
162
183
  }
163
184
  }
164
- #endif
@@ -1,7 +1,4 @@
1
1
  import AVFoundation
2
- #if canImport(ZXingObjC)
3
- import ZXingObjC
4
- #endif
5
2
  import VisionKit
6
3
  import Vision
7
4
 
@@ -105,37 +102,4 @@ class BarcodeScannerUtils {
105
102
  ]
106
103
  }
107
104
 
108
- #if canImport(ZXingObjC)
109
- static func zxResultToDictionary(_ barcodeScannerResult: ZXResult) -> [String: Any] {
110
- var result = [String: Any]()
111
- result["type"] = BarcodeScannerUtils.zxingFormatToString(barcodeScannerResult.barcodeFormat)
112
-
113
- var data = ""
114
- for i in 0..<barcodeScannerResult.text.count {
115
- let character = barcodeScannerResult.text[barcodeScannerResult.text.index(barcodeScannerResult.text.startIndex, offsetBy: i)]
116
- if character != "\0" {
117
- data.append(character)
118
- }
119
- }
120
- result["data"] = data
121
-
122
- return result
123
- }
124
-
125
- static func zxingFormatToString(_ format: ZXBarcodeFormat) -> String {
126
- switch format {
127
- case kBarcodeFormatPDF417:
128
- return AVMetadataObject.ObjectType.pdf417.rawValue
129
- case kBarcodeFormatCode39:
130
- return AVMetadataObject.ObjectType.code39.rawValue
131
- case kBarcodeFormatCodabar:
132
- if #available(iOS 15.4, *) {
133
- return AVMetadataObject.ObjectType.codabar.rawValue
134
- }
135
- return "unknown"
136
- default:
137
- return "unknown"
138
- }
139
- }
140
- #endif
141
105
  }
@@ -0,0 +1,13 @@
1
+ import AVFoundation
2
+
3
+ /// Protocol for barcode scanner providers.
4
+ /// Implement this in a separate module and expose via @objc(ExpoCameraZXingProvider) for runtime discovery.
5
+ ///
6
+ /// Returned dictionaries should have `"type"` and `"data"` keys matching the shape expected by the JS event.
7
+ @objc public protocol ExpoBarcodeScannerProvider {
8
+ /// The AVMetadataObject.ObjectType raw values this provider handles.
9
+ @objc var supportedTypes: [String] { get }
10
+
11
+ /// Scan a video frame for barcodes. Returns result dictionaries or an empty array.
12
+ @objc func scanBarcodes(from image: CGImage) -> [[String: Any]]
13
+ }
@@ -1,28 +1,29 @@
1
- #if canImport(ZXingObjC)
2
1
  import AVFoundation
3
- import ZXingObjC
2
+ import CoreImage
4
3
 
5
4
  class MetaDataDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate, AVCaptureVideoDataOutputSampleBufferDelegate {
6
5
  private var settings: [String: [AVMetadataObject.ObjectType]]
7
6
  private var previewLayer: AVCaptureVideoPreviewLayer?
8
- private var zxingBarcodeReaders: [AVMetadataObject.ObjectType: ZXReader]
9
- private var zxingEnabled = true
10
- private var zxingFPSProcessed = 6.0
7
+ private let barcodeProvider: ExpoBarcodeScannerProvider
8
+ private var barcodeProviderEnabled = true
9
+ private var barcodeProviderFPSProcessed = 6.0
11
10
  private var lastFrameTimeStamp = 0.0
12
11
  private let responseHandler: BarcodeScanningResponseHandler
13
12
 
13
+ private let ciContext = CIContext()
14
+
14
15
  init(
15
16
  settings: [String: [AVMetadataObject.ObjectType]],
16
17
  previewLayer: AVCaptureVideoPreviewLayer?,
17
- zxingBarcodeReaders: [AVMetadataObject.ObjectType: ZXReader],
18
- zxingEnabled: Bool,
18
+ barcodeProvider: ExpoBarcodeScannerProvider,
19
+ barcodeProviderEnabled: Bool,
19
20
  metadataResultHandler: BarcodeScanningResponseHandler
20
21
  ) {
21
22
  self.settings = settings
22
23
  self.previewLayer = previewLayer
23
- self.zxingEnabled = zxingEnabled
24
+ self.barcodeProviderEnabled = barcodeProviderEnabled
24
25
  self.responseHandler = metadataResultHandler
25
- self.zxingBarcodeReaders = zxingBarcodeReaders
26
+ self.barcodeProvider = barcodeProvider
26
27
  }
27
28
 
28
29
  func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
@@ -30,6 +31,8 @@ class MetaDataDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate, AVCapt
30
31
  return
31
32
  }
32
33
 
34
+ let barcodeProviderTypes = Set(barcodeProvider.supportedTypes)
35
+
33
36
  for metadata in metadataObjects {
34
37
  var codeMetadata = metadata as? AVMetadataMachineReadableCodeObject
35
38
  if let previewLayer {
@@ -37,7 +40,8 @@ class MetaDataDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate, AVCapt
37
40
  }
38
41
 
39
42
  for barcodeType in settings {
40
- if zxingBarcodeReaders[barcodeType] != nil {
43
+ // Skip types handled by the barcode provider — those come through captureOutput instead
44
+ if barcodeProviderTypes.contains(barcodeType.rawValue) {
41
45
  continue
42
46
  }
43
47
 
@@ -51,11 +55,11 @@ class MetaDataDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate, AVCapt
51
55
  }
52
56
 
53
57
  func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
54
- guard zxingEnabled else {
58
+ guard barcodeProviderEnabled else {
55
59
  return
56
60
  }
57
61
 
58
- let kMinMargin = 1.0 / zxingFPSProcessed
62
+ let kMinMargin = 1.0 / barcodeProviderFPSProcessed
59
63
  let presentTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
60
64
  let curFrameTimeStamp = Double(presentTimeStamp.value) / Double(presentTimeStamp.timescale)
61
65
 
@@ -63,42 +67,16 @@ class MetaDataDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate, AVCapt
63
67
  lastFrameTimeStamp = curFrameTimeStamp
64
68
 
65
69
  if let videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer),
66
- let videoFrameImage = ZXCGImageLuminanceSource.createImage(from: videoFrame) {
67
- self.scanBarcodes(from: videoFrameImage) { barcodeScannerResult in
68
- self.responseHandler.onScanningResult(BarcodeScannerUtils.zxResultToDictionary(barcodeScannerResult))
70
+ let image = createImage(from: videoFrame) {
71
+ for result in barcodeProvider.scanBarcodes(from: image) {
72
+ self.responseHandler.onScanningResult(result)
69
73
  }
70
74
  }
71
75
  }
72
76
  }
73
77
 
74
- func scanBarcodes(from image: CGImage, completion: @escaping (ZXResult) -> Void) {
75
- let source = ZXCGImageLuminanceSource(cgImage: image)
76
- let binarizer = ZXHybridBinarizer(source: source)
77
- let bitmap = ZXBinaryBitmap(binarizer: binarizer)
78
-
79
- var result: ZXResult?
80
-
81
- for reader in zxingBarcodeReaders.values {
82
- result = try? reader.decode(bitmap, hints: nil)
83
- if result != nil {
84
- break
85
- }
86
- }
87
-
88
- if result == nil && bitmap?.rotateSupported == true {
89
- if let rotatedBitmap = bitmap?.rotateCounterClockwise() {
90
- for reader in zxingBarcodeReaders.values {
91
- result = try? reader.decode(rotatedBitmap, hints: nil)
92
- if result != nil {
93
- break
94
- }
95
- }
96
- }
97
- }
98
-
99
- if let result {
100
- completion(result)
101
- }
78
+ private func createImage(from buffer: CVImageBuffer) -> CGImage? {
79
+ let ciImage = CIImage(cvImageBuffer: buffer)
80
+ return ciContext.createCGImage(ciImage, from: ciImage.extent)
102
81
  }
103
82
  }
104
- #endif
@@ -1,9 +1,6 @@
1
1
  require 'json'
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
- podfile_properties = JSON.parse(File.read("#{Pod::Config.instance.installation_root}/Podfile.properties.json")) rescue {}
5
-
6
- barcode_scanner_enabled = podfile_properties.fetch('expo-camera.barcode-scanner-enabled', 'true') != 'false'
7
4
 
8
5
  Pod::Spec.new do |s|
9
6
  s.name = 'ExpoCamera'
@@ -20,22 +17,14 @@ Pod::Spec.new do |s|
20
17
  s.static_framework = true
21
18
 
22
19
  s.dependency 'ExpoModulesCore'
23
- if barcode_scanner_enabled
24
- s.dependency 'ZXingObjC/PDF417'
25
- s.dependency 'ZXingObjC/OneD'
26
- end
27
20
 
28
21
  # Swift/Objective-C compatibility
29
- xcconfig = {
22
+ s.pod_target_xcconfig = {
30
23
  'DEFINES_MODULE' => 'YES',
31
24
  'SWIFT_COMPILATION_MODE' => 'wholemodule'
32
25
  }
33
26
 
34
- if barcode_scanner_enabled
35
- xcconfig['GCC_PREPROCESSOR_DEFINITIONS'] = 'ZXINGOBJC_USE_SUBSPECS ZXINGOBJC_PDF417 ZXINGOBJC_ONED'
36
- end
37
-
38
- s.pod_target_xcconfig = xcconfig
27
+ s.exclude_files = "barcode-scanning/**"
39
28
 
40
29
  if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
41
30
  s.source_files = "**/*.h"
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ExpoCameraBarcodeScanning'
7
+ s.version = package['version']
8
+ s.summary = 'ZXing-based barcode scanning provider for expo-camera'
9
+ s.description = 'Provides PDF417, Code39, and Codabar barcode scanning via ZXingObjC for expo-camera'
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platforms = { :ios => '15.1' }
14
+ s.swift_version = '5.9'
15
+ s.source = { :git => 'https://github.com/expo/expo.git' }
16
+ s.static_framework = true
17
+
18
+ s.dependency 'ExpoCamera'
19
+ s.dependency 'ZXingObjC/PDF417'
20
+ s.dependency 'ZXingObjC/OneD'
21
+
22
+ s.source_files = 'barcode-scanning/**/*.swift'
23
+
24
+ s.pod_target_xcconfig = {
25
+ 'DEFINES_MODULE' => 'YES',
26
+ 'GCC_PREPROCESSOR_DEFINITIONS' => 'ZXINGOBJC_USE_SUBSPECS ZXINGOBJC_PDF417 ZXINGOBJC_ONED',
27
+ 'SWIFT_COMPILATION_MODE' => 'wholemodule'
28
+ }
29
+ end
@@ -0,0 +1,44 @@
1
+ import AVFoundation
2
+ internal import ZXingObjC
3
+ import ExpoCamera
4
+
5
+ @objc(ExpoCameraZXingProvider)
6
+ class ExpoCameraZXingProvider: NSObject, ExpoBarcodeScannerProvider {
7
+ private var readers: [String: ZXReader] = [:]
8
+
9
+ override init() {
10
+ super.init()
11
+ readers[AVMetadataObject.ObjectType.pdf417.rawValue] = ZXPDF417Reader()
12
+ readers[AVMetadataObject.ObjectType.code39.rawValue] = ZXCode39Reader()
13
+ if #available(iOS 15.4, *) {
14
+ readers[AVMetadataObject.ObjectType.codabar.rawValue] = ZXCodaBarReader()
15
+ }
16
+ }
17
+
18
+ var supportedTypes: [String] {
19
+ Array(readers.keys)
20
+ }
21
+
22
+ func scanBarcodes(from image: CGImage) -> [[String: Any]] {
23
+ let source = ZXCGImageLuminanceSource(cgImage: image)
24
+ let binarizer = ZXHybridBinarizer(source: source)
25
+ let bitmap = ZXBinaryBitmap(binarizer: binarizer)
26
+
27
+ for (type, reader) in readers {
28
+ if let result = try? reader.decode(bitmap, hints: nil) {
29
+ return [["type": type, "data": result.text.filter { $0 != "\0" }]]
30
+ }
31
+ }
32
+
33
+ // Retry with rotated image for barcodes at non-standard orientations
34
+ if bitmap?.rotateSupported == true, let rotated = bitmap?.rotateCounterClockwise() {
35
+ for (type, reader) in readers {
36
+ if let result = try? reader.decode(rotated, hints: nil) {
37
+ return [["type": type, "data": result.text.filter { $0 != "\0" }]]
38
+ }
39
+ }
40
+ }
41
+
42
+ return []
43
+ }
44
+ }
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "host.exp.exponent",
5
5
  "module": "expo.modules.camera",
6
- "version": "55.0.15",
6
+ "version": "55.0.16",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -40,8 +40,8 @@
40
40
  ],
41
41
  "files": [
42
42
  {
43
- "name": "expo.modules.camera-55.0.15.aar",
44
- "url": "expo.modules.camera-55.0.15.aar",
43
+ "name": "expo.modules.camera-55.0.16.aar",
44
+ "url": "expo.modules.camera-55.0.16.aar",
45
45
  "size": 247692,
46
46
  "sha512": "ec176be898748075419c264cfd6587d184ae6223dc64d5bec48ec4baeb959eed532faa061ccd62a7efcac779971d5ae5c93c172b6ec042c64c070b3f718953a8",
47
47
  "sha256": "d192b7cd2385ccd27c32b317970562c10c7288b4455532b2676fd9c05860c151",
@@ -146,8 +146,8 @@
146
146
  ],
147
147
  "files": [
148
148
  {
149
- "name": "expo.modules.camera-55.0.15.aar",
150
- "url": "expo.modules.camera-55.0.15.aar",
149
+ "name": "expo.modules.camera-55.0.16.aar",
150
+ "url": "expo.modules.camera-55.0.16.aar",
151
151
  "size": 247692,
152
152
  "sha512": "ec176be898748075419c264cfd6587d184ae6223dc64d5bec48ec4baeb959eed532faa061ccd62a7efcac779971d5ae5c93c172b6ec042c64c070b3f718953a8",
153
153
  "sha256": "d192b7cd2385ccd27c32b317970562c10c7288b4455532b2676fd9c05860c151",
@@ -166,8 +166,8 @@
166
166
  },
167
167
  "files": [
168
168
  {
169
- "name": "expo.modules.camera-55.0.15-sources.jar",
170
- "url": "expo.modules.camera-55.0.15-sources.jar",
169
+ "name": "expo.modules.camera-55.0.16-sources.jar",
170
+ "url": "expo.modules.camera-55.0.16-sources.jar",
171
171
  "size": 29083,
172
172
  "sha512": "026c8ca43c56694a89b33c7a57a7b0ad7b8c4a8552911f5198cf167a1835f1006a32501d17502cc4ffa545b83b2ff73a442090d5de819dbf7ccfa7279ce8f36b",
173
173
  "sha256": "fb6fc10073864be50cdcf3f26efa6904cadbb709bb471a3db65d819110a649c7",
@@ -0,0 +1 @@
1
+ 788cf2746885da58fbcefab4af7d72e2a36e6b4b675a1433cea4190732f087ce
@@ -0,0 +1 @@
1
+ ffaa76537d69f945b44bb521138d723a85aefe17879b37e66d3baf86522db0a478def6121deaa82695108ad41ebd8340a03562273ec46e1ada0ef2432560186e
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>host.exp.exponent</groupId>
11
11
  <artifactId>expo.modules.camera</artifactId>
12
- <version>55.0.15</version>
12
+ <version>55.0.16</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.camera</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -0,0 +1 @@
1
+ f6508f67ecb5e43dc537375ad18928e0cec00d7ecadb8554221e81b8c526532f
@@ -0,0 +1 @@
1
+ a551238243b99d8c1718828cc449434970eec421e77099ec3c4528efc043f0db6b704535ff2e19b4085a59aa8bef508c126ac8feb219cbbf7f66e7da673acc02
@@ -3,11 +3,11 @@
3
3
  <groupId>host.exp.exponent</groupId>
4
4
  <artifactId>expo.modules.camera</artifactId>
5
5
  <versioning>
6
- <latest>55.0.15</latest>
7
- <release>55.0.15</release>
6
+ <latest>55.0.16</latest>
7
+ <release>55.0.16</release>
8
8
  <versions>
9
- <version>55.0.15</version>
9
+ <version>55.0.16</version>
10
10
  </versions>
11
- <lastUpdated>20260409135100</lastUpdated>
11
+ <lastUpdated>20260421111034</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- e9faad40fed14629b5ce97dfccf8185c
1
+ c163d612429f20f84ec5627e270e39a8
@@ -1 +1 @@
1
- d74892eaa65467ea141b275df4b926a832dac940
1
+ d5837e0908e474121d593de88c389b20abba0c6a
@@ -1 +1 @@
1
- 149a621f539e89250fed23d1de1b074d74734c042afc7f19ee53907fad5927f5
1
+ 7608c990e2d4c868a3fc172e53886ca2b4a1b038b96297d03922871db7b4c367
@@ -1 +1 @@
1
- 1bfb5ed3b719a39d74adbb26b10180651e844d3236f5e08c0ace616b2923f6d252ed33d885e836167b05f04e65ff59263787277b5f6fe77cc23f4afd6555395f
1
+ 55cee9f2a5cab2f36d5684a646622161a6283f062d0a9a7c3a6fe856e14193cda88220f40fbc5c8b86e6c01207d16b881c034e323858e3a0ebdb76e7ff8394e7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-camera",
3
- "version": "55.0.15",
3
+ "version": "55.0.16",
4
4
  "description": "A React component that renders a preview for the device's either front or back camera. Camera's parameters like zoom, auto focus, white balance and flash mode are adjustable. With expo-camera, one can also take photos and record videos that are saved to the app's cache. Morever, the component is also capable of detecting faces and bar codes appearing on the preview.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -50,5 +50,5 @@
50
50
  "optional": true
51
51
  }
52
52
  },
53
- "gitHead": "b0ada30fd6a819c5f98a23d99b1b89a2ed68743d"
53
+ "gitHead": "e37e614d97c3ca53f16b91609a787675d044c284"
54
54
  }
package/spm.config.json CHANGED
@@ -13,32 +13,56 @@
13
13
  "Hermes",
14
14
  "expo-modules-core/ExpoModulesCore"
15
15
  ],
16
- "spmPackages": [
17
- {
18
- "url": "https://github.com/zxingify/zxingify-objc.git",
19
- "productName": "ZXingObjC",
20
- "version": {
21
- "exact": "3.6.9"
22
- }
23
- }
24
- ],
25
16
  "targets": [
26
17
  {
27
18
  "type": "swift",
28
19
  "name": "ExpoCamera",
29
20
  "path": "ios",
30
21
  "pattern": "**/*.swift",
22
+ "exclude": ["barcode-scanning/**"],
31
23
  "dependencies": [
32
24
  "ReactNativeDependencies",
33
25
  "React",
34
26
  "Hermes",
35
- "expo-modules-core/ExpoModulesCore",
36
- "ZXingObjC"
27
+ "expo-modules-core/ExpoModulesCore"
37
28
  ],
38
29
  "linkedFrameworks": [
39
30
  "Foundation",
40
31
  "UIKit",
41
32
  "AVFoundation"
33
+ ]
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ "name": "ExpoCameraBarcodeScanning",
39
+ "podName": "ExpoCameraBarcodeScanning",
40
+ "platforms": [
41
+ "iOS(.v15)"
42
+ ],
43
+ "autolinkWhen": {
44
+ "podfileProperty": "expo.camera.barcode-scanner-enabled",
45
+ "disabledValue": "false"
46
+ },
47
+ "externalDependencies": [],
48
+ "spmPackages": [
49
+ {
50
+ "url": "https://github.com/zxingify/zxingify-objc.git",
51
+ "productName": "ZXingObjC",
52
+ "version": {
53
+ "exact": "3.6.9"
54
+ }
55
+ }
56
+ ],
57
+ "targets": [
58
+ {
59
+ "type": "swift",
60
+ "name": "ExpoCameraBarcodeScanning",
61
+ "path": "ios/barcode-scanning",
62
+ "pattern": "**/*.swift",
63
+ "dependencies": [
64
+ "ExpoCamera",
65
+ "ZXingObjC"
42
66
  ],
43
67
  "compilerFlags": {
44
68
  "swift": [
@@ -1,40 +0,0 @@
1
- #if !canImport(ZXingObjC)
2
- import AVFoundation
3
-
4
- class BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
5
- private var onBarcodeScanned: (([String: Any]?) -> Void)?
6
- var isScanningBarcodes = false
7
-
8
- init(session: AVCaptureSession, sessionQueue: DispatchQueue) {}
9
-
10
- func setSettings(_ newSettings: [String: [AVMetadataObject.ObjectType]]) {}
11
-
12
- func setPreviewLayer(layer: AVCaptureVideoPreviewLayer) {}
13
-
14
- func setIsEnabled(_ enabled: Bool) {
15
- isScanningBarcodes = enabled
16
- if enabled {
17
- onBarcodeScanned?(nil)
18
- }
19
- }
20
-
21
- func setConnection(enabled: Bool) {}
22
-
23
- func setOnBarcodeScanned(_ onBarcodeScanned: @escaping ([String: Any]?) -> Void) {
24
- self.onBarcodeScanned = onBarcodeScanned
25
- }
26
-
27
- func maybeStartBarcodeScanning() {}
28
-
29
- func stopBarcodeScanning() {
30
- if isScanningBarcodes {
31
- isScanningBarcodes = false
32
- onBarcodeScanned?(nil)
33
- }
34
- }
35
-
36
- func onScanningResult(_ result: [String: Any]) {
37
- onBarcodeScanned?(result)
38
- }
39
- }
40
- #endif
@@ -1 +0,0 @@
1
- 98ecef2f29437da2479e695c9488bf8de60d4c594e44521b74de663480363e05
@@ -1 +0,0 @@
1
- 07b524c0504680bde71c644af3678feff97a682b6f0f45bed13d2ec7b01faa13b1af8597cd4b2a2bc881d968fff888d912d25c2bdd01be2763997d832ccaf666
@@ -1 +0,0 @@
1
- 5ee450d71dcb402ca3304f3d6be39127fd6aa2375ba28485e50c164626df12d5
@@ -1 +0,0 @@
1
- 8a873b76d4eba416eb86fa4bdfa21e84dba9ed1b8e702f281180e38cacda634ebf6113fbf08020b332305c6b7bdf5c139ecef3253ebbeff11a9869e6c41e11f4