Skip to content

fix: rotate the scanner to the forced scanOrientation in UIScene apps - #49

Open
andredestro wants to merge 2 commits into
mainfrom
fix/RMET-5550/forced-scan-orientation
Open

andredestro wants to merge 2 commits into
mainfrom
fix/RMET-5550/forced-scan-orientation

Conversation

@andredestro

Copy link
Copy Markdown
Contributor

Description

Makes a forced scanOrientation (portrait or landscape) work in apps that use the UIScene lifecycle:

  • Rotate on present and dismiss. When the scanner is presented with a forced orientation, it now requests the rotation explicitly (requestGeometryUpdate on iOS 16+, the UIDevice orientation fallback on iOS 15). On dismiss, it rotates to the device's current orientation if the app supports it, or back to the orientation in place before scanning.
  • Keep the camera preview in sync with the view. The preview is resized and re-oriented in viewDidLayoutSubviews, after each transition completes (a 180° rotation changes no size, so no layout runs), and whenever the window scene's effectiveGeometry changes. That last one covers the forced rotation, where the first layout still sees the old orientation.
  • Decode in the orientation that is on screen. The session manager passes the preview's orientation to the decoder, which uses it for Vision instead of the physical device orientation, and recomputes the region of interest when it changes. The region of interest is now normalized with the window bounds: the screen bounds still reported the old orientation right after the forced rotation, which produced an invalid region (width > 1) and no decoding.
  • Reads the interface orientation from effectiveGeometry on iOS 16+, since interfaceOrientation is deprecated as of iOS 26.

Context

With the UIScene lifecycle (mandatory when building with the iOS 27 SDK), presenting the scanner with a narrower supportedInterfaceOrientations no longer rotates the interface. With scanOrientation set to landscape and the device held in portrait (or the other way around), the layout broke and no code was decoded. adaptive was not affected.

Tracked in RMET-5550. Related, same area: ionic-team/capacitor-barcode-scanner#58

Type of changes

  • Fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Refactor (cosmetic changes)
  • Breaking change (change that would cause existing functionality to not work as expected)

Tests

  • Unit tests for the new orientation mappings: all 7 tests pass.
  • On an iPhone 16 Pro Max with iOS 27.0.1, using the capacitor-barcode-scanner SwiftPM example app (Capacitor 9, UIScene) pointed at this branch:
    • Forced landscape or portrait, opened with the device in either orientation: the interface rotates, the preview fills the screen and matches what the camera sees, and codes are decoded.
    • Rotating 180° with the scanner open: the preview stays upright.
    • After dismissing: the app follows the device's current orientation.
    • adaptive: unchanged.

Screenshots (if appropriate)

Checklist

  • Code follows code style of this project
  • Changes require an update to the documentation
    • Documentation has been updated accordingly

@andredestro
andredestro marked this pull request as ready for review October 27, 2026 10:51
@andredestro
andredestro requested a review from a team as a code owner October 27, 2026 10:51
@alexgerardojacinto alexgerardojacinto self-assigned this Oct 30, 2026
The fallback always picked the first orientation in the mask, so a forced
landscape scanner opened with the interface in landscapeLeft was flipped
180 degrees to landscapeRight. Skip the rotation when the current
orientation is already in the mask, and otherwise prefer how the device
is held.
/// The scene's current interface orientation, read from `effectiveGeometry` on iOS 16+
/// (`interfaceOrientation` is deprecated as of iOS 26).
var currentInterfaceOrientation: UIInterfaceOrientation {
if #available(iOS 16.0, *) { return self.effectiveGeometry.interfaceOrientation }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't iOS 16 the lowest we support these days?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Capacitor 9, yes. But this lib is also used by the Capacitor 8 barcode plugin and the Cordova plugin on MABS 12, which are both still on iOS 15, so I kept the pre-16 path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants