@imgly/camera-react-native 1.81.1-rc.0 → 1.82.0-rc.0

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.
@@ -14,6 +14,9 @@ Pod::Spec.new do |s|
14
14
  s.source = { path: './ios' }
15
15
 
16
16
  s.source_files = 'ios/**/*.{h,m,mm,swift}'
17
+ # ios/Package.swift is the manifest for React Native's experimental Swift
18
+ # Package Manager mode, not a source file.
19
+ s.exclude_files = 'ios/Package.swift'
17
20
 
18
21
  s.dependency 'IMGLYCamera', s.version.to_s
19
22
 
package/README.md CHANGED
@@ -24,3 +24,20 @@ const result = await IMGLYCamera.openCamera({
24
24
  ## Changelog
25
25
 
26
26
  To keep up-to-date with the latest changes, visit [CHANGELOG](https://img.ly/docs/cesdk/changelog/).
27
+
28
+ ## Swift Package Manager (experimental)
29
+
30
+ React Native 0.87 introduced an experimental Swift Package Manager mode (`npx react-native spm`) — see the [React Native 0.87 announcement](https://reactnative.dev/blog/2026/08/11/react-native-0.87) and the [0.87.0 release notes](https://github.com/react/react-native/releases/tag/v0.87.0). This module dual-ships a SwiftPM manifest (`ios/Package.swift`) next to its podspec, so React Native's SPM autolinking resolves it out of the box. CocoaPods currently remains the default integration path; the React Native team does not recommend the SPM mode for production yet.
31
+
32
+ The notes below describe React Native **0.87.0**. That is the version this
33
+ support was built and verified against. We have not verified newer React Native
34
+ versions, so we do not know whether these workarounds still apply there. React
35
+ Native calls this mode experimental and can change its commands, flags, and
36
+ generated layout in any release. Check the release notes of the React Native
37
+ version you use.
38
+
39
+ Note: React Native 0.87 pins its generated autolinking package to iOS 15 while this module requires iOS 16. Until the floor is derived from the linked libraries upstream, raise the `platforms:` entries in `react-native/scripts/spm/generate-spm-autolinking.js` to `.iOS(.v16)` (for example with `patch-package`).
40
+
41
+ Note: The app target itself must also build with an iOS 16 deployment target. The React Native template scaffolds a lower one, which works until your app code imports this module directly — for example for native customization — and then fails with a minimum-deployment-target error. Raise the **iOS Deployment Target** of the app target in Xcode to 16.0.
42
+
43
+ Note: React Native 0.87.0 ships `hermes-compiler` for bytecode version 98 while its prebuilt SwiftPM Hermes runtime expects 99, so any build with an embedded JS bundle crashes at startup. Install `hermes-compiler@^260318099` until a React Native release aligns the two.
@@ -141,6 +141,6 @@ repositories {
141
141
  }
142
142
 
143
143
  dependencies {
144
- api "ly.img:camera:1.81.1-rc.0"
144
+ api "ly.img:camera:1.82.0-rc.0"
145
145
  implementation "com.facebook.react:react-native"
146
146
  }
@@ -0,0 +1,47 @@
1
+ import Foundation
2
+ #if canImport(IMGLYCameraModuleObjC)
3
+ // Swift Package Manager builds the Objective-C++ bridge as a separate target.
4
+ // Under CocoaPods both languages share one module, so no import is needed.
5
+ import IMGLYCameraModuleObjC
6
+ #endif
7
+
8
+ /// The Swift implementation behind the Objective-C++ React Native bridge.
9
+ ///
10
+ /// The bridge resolves this class at runtime by its stable Objective-C name
11
+ /// (see `IMGLYCameraModuleImplementationProvider`), so no static
12
+ /// Objective-C → Swift reference exists. This is what allows building the
13
+ /// module with Swift Package Manager, which cannot compile mixed
14
+ /// Swift/Objective-C++ targets (SE-0403).
15
+ @objc(IMGLYCameraModuleDefaultImplementation)
16
+ final class IMGLYCameraModuleDefaultImplementation: NSObject, IMGLYCameraModuleImplementation {
17
+ func openCamera(
18
+ withSettings settings: [AnyHashable: Any],
19
+ video: String?,
20
+ metadata: [AnyHashable: Any]?,
21
+ resolve: @escaping IMGLYCameraResolveBlock,
22
+ reject: @escaping IMGLYCameraRejectBlock,
23
+ ) {
24
+ guard let settings = settings as? [String: Any],
25
+ let cameraSettings = CameraSettings.fromDictionary(settings) else {
26
+ reject("E_PARSING", "Unable to parse the argument(s): ", nil)
27
+ return
28
+ }
29
+ let metadata = metadata as? [String: Any]
30
+
31
+ DispatchQueue.main.async {
32
+ IMGLYCameraModuleSwiftAdapter.shared.openCamera(
33
+ settings: cameraSettings,
34
+ video: video,
35
+ metadata: metadata,
36
+ ) { result, error in
37
+ if let result {
38
+ resolve(result.toDictionary())
39
+ } else if let error {
40
+ reject("E_RECORDING_FAILED", "The recording failed due to: ", error)
41
+ } else {
42
+ resolve(NSNull())
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
@@ -1,3 +1,5 @@
1
+ import CoreGraphics
2
+ import Foundation
1
3
  import IMGLYCamera
2
4
 
3
5
  /// The result type for a camera reaction session.
@@ -0,0 +1,95 @@
1
+ // swift-tools-version: 6.1
2
+ // 6.1 is the parse floor for the trailing-comma syntax SwiftFormat enforces (SE-0439). The
3
+ // toolchain floor comes from the IMGLYUI-swift dependency (tools 6.3.1) — do not lower this.
4
+
5
+ // Hand-authored manifest for React Native's experimental Swift Package Manager
6
+ // mode (React Native >= 0.87, `npx react-native spm`). CocoaPods
7
+ // (IMGLYCameraModule.podspec) remains the supported default integration.
8
+ //
9
+ // React Native's SPM autolinking consumes this manifest through a symlink at
10
+ // <app>/ios/build/generated/autolinking/libs/CameraReactNative -> this
11
+ // directory, so the relative package references below resolve against that
12
+ // location. This is React Native's documented contract for libraries that ship
13
+ // their own manifest (react-native/scripts/spm/__doc__/spm-header-paths-contract.md);
14
+ // the package and product must be named after the npm package
15
+ // (@imgly/camera-react-native -> CameraReactNative).
16
+ //
17
+ // The Objective-C++ bridge and the Swift implementation are separate targets
18
+ // because SwiftPM cannot compile mixed-language targets (SE-0403). The bridge
19
+ // resolves the Swift implementation at runtime (IMGLYCameraModuleSupport.h),
20
+ // so no Objective-C -> Swift compile-time dependency exists.
21
+
22
+ import Foundation
23
+ import PackageDescription
24
+
25
+ // Single-source the version from package.json, like the podspec does, so
26
+ // release automation bumps the IMG.LY dependency pin together with the
27
+ // package version. React Native's autolinking references this manifest
28
+ // through a symlink, so resolve it before walking up to the package root.
29
+ let version: Version = {
30
+ let packageJSON = URL(fileURLWithPath: #filePath)
31
+ .resolvingSymlinksInPath()
32
+ .deletingLastPathComponent()
33
+ .deletingLastPathComponent()
34
+ .appendingPathComponent("package.json")
35
+ guard let data = try? Data(contentsOf: packageJSON),
36
+ let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
37
+ let versionString = json["version"] as? String,
38
+ let version = Version(versionString) else {
39
+ fatalError("Unable to read the package version from \(packageJSON.path).")
40
+ }
41
+ return version
42
+ }()
43
+
44
+ let package = Package(
45
+ name: "CameraReactNative",
46
+ platforms: [
47
+ .iOS(.v16),
48
+ ],
49
+ products: [
50
+ .library(name: "CameraReactNative", targets: ["IMGLYCameraModule", "IMGLYCameraModuleObjC"]),
51
+ ],
52
+ dependencies: [
53
+ .package(name: "ReactNative", path: "../../../../xcframeworks"),
54
+ .package(name: "React-GeneratedCode", path: "../../../ios"),
55
+ // Pinned exactly: the module and IMGLYUI are versioned in lockstep, matching the podspec.
56
+ .package(url: "https://github.com/imgly/IMGLYUI-swift.git", exact: version),
57
+ ],
58
+ targets: [
59
+ .target(
60
+ name: "IMGLYCameraModuleObjC",
61
+ dependencies: [
62
+ .product(name: "ReactHeaders", package: "ReactNative"),
63
+ .product(name: "ReactNativeHeaders", package: "ReactNative"),
64
+ .product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"),
65
+ .product(name: "ReactAppHeaders", package: "React-GeneratedCode"),
66
+ ],
67
+ path: "bridge",
68
+ publicHeadersPath: "include",
69
+ cxxSettings: [
70
+ // React Native's SwiftPM autolinking defines this for no target, while
71
+ // CocoaPods defines it for every one. Without it this module would
72
+ // compile its legacy bridge branch and run behind the TurboModule
73
+ // interop layer, so the integration path would decide the dispatch
74
+ // mechanism. The codegen'd spec headers the branch needs come from the
75
+ // ReactAppHeaders product above.
76
+ .define("RCT_NEW_ARCH_ENABLED", to: "1"),
77
+ .define("DEBUG", .when(configuration: .debug)),
78
+ .define("NDEBUG", .when(configuration: .release)),
79
+ ],
80
+ linkerSettings: [.linkedFramework("Foundation")],
81
+ ),
82
+ .target(
83
+ name: "IMGLYCameraModule",
84
+ dependencies: [
85
+ "IMGLYCameraModuleObjC",
86
+ .product(name: "IMGLYCamera", package: "IMGLYUI-swift"),
87
+ ],
88
+ path: ".",
89
+ exclude: ["bridge"],
90
+ ),
91
+ ],
92
+ // The module sources are written for the Swift 5 language mode.
93
+ swiftLanguageModes: [.v5],
94
+ cxxLanguageStandard: .cxx20,
95
+ )
@@ -1,5 +1,5 @@
1
1
  #import "IMGLYCameraModule.h"
2
- #import "IMGLYCameraModule/IMGLYCameraModule-Swift.h"
2
+ #import "IMGLYCameraModuleSupport.h"
3
3
 
4
4
  @implementation IMGLYCameraModule
5
5
 
@@ -52,21 +52,12 @@ RCT_EXPORT_METHOD(openCamera : (nonnull NSDictionary*)settings video : (nullable
52
52
  metadata:(NSDictionary*)metadata
53
53
  resolve:(RCTPromiseResolveBlock)resolve
54
54
  reject:(RCTPromiseRejectBlock)reject {
55
- CameraSettings* cameraSettings = [CameraSettings fromDictionary:settings];
56
- dispatch_async(dispatch_get_main_queue(), ^{
57
- [[IMGLYCameraModuleSwiftAdapter shared]
58
- openCameraWithSettings:cameraSettings
59
- video:video
60
- metadata:metadata
61
- completion:^(CameraResult* _Nullable result, NSError* _Nullable error) {
62
- if (result != nil) {
63
- resolve([result toDictionary]);
64
- } else if (error != nil) {
65
- reject(@"E_RECORDING_FAILED", @"The recording failed due to: ", error);
66
- } else {
67
- resolve([NSNull null]);
68
- }
69
- }];
70
- });
55
+ id<IMGLYCameraModuleImplementation> implementation = IMGLYCameraModuleImplementationProvider.implementation;
56
+ if (implementation == nil) {
57
+ reject(@"E_IMPLEMENTATION_MISSING",
58
+ @"The Swift implementation of the IMGLYCamera module was not linked into the app.", nil);
59
+ return;
60
+ }
61
+ [implementation openCameraWithSettings:settings video:video metadata:metadata resolve:resolve reject:reject];
71
62
  }
72
63
  @end
@@ -0,0 +1,23 @@
1
+ #import "IMGLYCameraModuleSupport.h"
2
+
3
+ @implementation IMGLYCameraModuleImplementationProvider
4
+
5
+ + (nullable id<IMGLYCameraModuleImplementation>)implementation {
6
+ static id<IMGLYCameraModuleImplementation> implementation;
7
+ static dispatch_once_t onceToken;
8
+ dispatch_once(&onceToken, ^{
9
+ // The Swift class is looked up by its stable Objective-C runtime name
10
+ // (`IMGLYCameraModuleImplementation.swift`) because this target must not
11
+ // reference Swift at compile time. React Native apps link with `-ObjC` on
12
+ // both the CocoaPods and the Swift Package Manager path, which keeps the
13
+ // class alive in Release and Archive builds despite the missing static
14
+ // reference.
15
+ Class implementationClass = NSClassFromString(@"IMGLYCameraModuleDefaultImplementation");
16
+ if ([implementationClass conformsToProtocol:@protocol(IMGLYCameraModuleImplementation)]) {
17
+ implementation = [[implementationClass alloc] init];
18
+ }
19
+ });
20
+ return implementation;
21
+ }
22
+
23
+ @end
@@ -0,0 +1,46 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ /// Resolves a fulfilled result. Mirrors React Native's `RCTPromiseResolveBlock`
6
+ /// without importing React, so the Swift implementation stays React-free.
7
+ typedef void (^IMGLYCameraResolveBlock)(id _Nullable result);
8
+
9
+ /// Rejects with an error. Mirrors React Native's `RCTPromiseRejectBlock`.
10
+ typedef void (^IMGLYCameraRejectBlock)(NSString* code, NSString* message, NSError* _Nullable error);
11
+
12
+ /// The seam between the Objective-C++ React Native bridge and the Swift
13
+ /// implementation of the camera module.
14
+ ///
15
+ /// The bridge resolves the implementation at runtime through
16
+ /// `IMGLYCameraModuleImplementationProvider` instead of importing the generated
17
+ /// `-Swift.h` header. Swift Package Manager cannot compile mixed
18
+ /// Swift/Objective-C++ targets (SE-0403) and never emits that header, so the
19
+ /// Objective-C target must not depend on Swift at compile time.
20
+ @protocol IMGLYCameraModuleImplementation <NSObject>
21
+
22
+ /// Opens the camera.
23
+ /// - Parameters:
24
+ /// - settings: The raw camera settings as received from JavaScript.
25
+ /// - video: The source of the video to react to as received from JavaScript.
26
+ /// - metadata: Any custom metadata as received from JavaScript.
27
+ /// - resolve: The block to invoke with the recording result, or `NSNull` on cancellation.
28
+ /// - reject: The block to invoke when parsing or the recording fails.
29
+ - (void)openCameraWithSettings:(NSDictionary*)settings
30
+ video:(nullable NSString*)video
31
+ metadata:(nullable NSDictionary*)metadata
32
+ resolve:(IMGLYCameraResolveBlock)resolve
33
+ reject:(IMGLYCameraRejectBlock)reject;
34
+
35
+ @end
36
+
37
+ /// Resolves the Swift implementation of the camera module at runtime.
38
+ @interface IMGLYCameraModuleImplementationProvider : NSObject
39
+
40
+ /// The resolved implementation, or `nil` when the Swift part of this module
41
+ /// was not linked into the app.
42
+ + (nullable id<IMGLYCameraModuleImplementation>)implementation;
43
+
44
+ @end
45
+
46
+ NS_ASSUME_NONNULL_END
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imgly/camera-react-native",
3
- "version": "1.81.1-rc.0",
3
+ "version": "1.82.0-rc.0",
4
4
  "description": "Camera SDK for React Native - provide a versatile video camera to your users on iOS and Android.",
5
5
  "react-native": "index.js",
6
6
  "source": "index.js",