expo-screen-orientation 6.0.1 → 6.0.3

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.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,18 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 6.0.3 — 2023-07-12
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [iOS] When config plugin is not configured the initial orientation is now based on values in `Info.plist` instead of being set to portrait. ([#23456](https://github.com/expo/expo/pull/23456) by [@behenate](https://github.com/behenate))
18
+
19
+ ## 6.0.2 — 2023-07-04
20
+
21
+ ### 💡 Others
22
+
23
+ - [iOS] Refactor the singleton class to work properly in versioned code in Expo Go. ([#23228](https://github.com/expo/expo/pull/23228) by [@tsapeta](https://github.com/tsapeta))
24
+
13
25
  ## 6.0.1 — 2023-06-23
14
26
 
15
27
  ### 🐛 Bug fixes
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '6.0.1'
6
+ version = '6.0.3'
7
7
 
8
8
  buildscript {
9
9
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -67,7 +67,7 @@ android {
67
67
  minSdkVersion safeExtGet("minSdkVersion", 21)
68
68
  targetSdkVersion safeExtGet("targetSdkVersion", 33)
69
69
  versionCode 7
70
- versionName '6.0.1'
70
+ versionName '6.0.3'
71
71
  }
72
72
  lintOptions {
73
73
  abortOnError false
@@ -2,6 +2,7 @@
2
2
 
3
3
  import ExpoModulesCore
4
4
 
5
+ @objc(EXScreenOrientationAppDelegate)
5
6
  public class ScreenOrientationAppDelegate: ExpoAppDelegateSubscriber {
6
7
  public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
7
8
  ScreenOrientationRegistry.shared.updateCurrentScreenOrientation()
@@ -1,6 +1,6 @@
1
1
  import ExpoModulesCore
2
2
 
3
- public class ScreenOrientationModule: Module, OrientationListener, Hashable {
3
+ public class ScreenOrientationModule: Module, ScreenOrientationController {
4
4
  static let didUpdateDimensionsEvent = "expoDidUpdateDimensions"
5
5
 
6
6
  let screenOrientationRegistry = ScreenOrientationRegistry.shared
@@ -22,7 +22,7 @@ public class ScreenOrientationModule: Module, OrientationListener, Hashable {
22
22
  throw UnsupportedOrientationLockException(orientationLock)
23
23
  }
24
24
 
25
- screenOrientationRegistry.setMask(orientationMask, forModule: self)
25
+ screenOrientationRegistry.setMask(orientationMask, forController: self)
26
26
  }
27
27
 
28
28
  AsyncFunction("lockPlatformAsync") { (allowedOrientations: [ModuleOrientation]) in
@@ -43,7 +43,7 @@ public class ScreenOrientationModule: Module, OrientationListener, Hashable {
43
43
  throw UnsupportedOrientationLockException(nil)
44
44
  }
45
45
 
46
- screenOrientationRegistry.setMask(allowedOrientationsMask, forModule: self)
46
+ screenOrientationRegistry.setMask(allowedOrientationsMask, forController: self)
47
47
  }
48
48
 
49
49
  AsyncFunction("getOrientationLockAsync") {
@@ -75,23 +75,18 @@ public class ScreenOrientationModule: Module, OrientationListener, Hashable {
75
75
  return ModuleOrientation.from(orientation: screenOrientationRegistry.currentScreenOrientation).rawValue
76
76
  }
77
77
 
78
- OnStartObserving {
79
- screenOrientationRegistry.registerModuleToReceiveNotification(self)
80
- }
81
-
82
- OnStopObserving {
83
- screenOrientationRegistry.unregisterModuleFromReceivingNotification(self)
78
+ OnCreate {
79
+ screenOrientationRegistry.registerController(self)
84
80
  }
85
81
 
86
82
  OnDestroy {
87
- screenOrientationRegistry.unregisterModuleFromReceivingNotification(self)
88
- screenOrientationRegistry.moduleWillDeallocate(self)
83
+ screenOrientationRegistry.unregisterController(self)
89
84
  }
90
85
  }
91
86
 
92
- // MARK: - ScreenOrientationListener
87
+ // MARK: - ScreenOrientationController
93
88
 
94
- func screenOrientationDidChange(_ orientation: UIInterfaceOrientation) {
89
+ public func screenOrientationDidChange(_ orientation: UIInterfaceOrientation) {
95
90
  guard let currentTraitCollection = screenOrientationRegistry.currentTraitCollection else {
96
91
  return
97
92
  }
@@ -105,14 +100,4 @@ public class ScreenOrientationModule: Module, OrientationListener, Hashable {
105
100
  ] as [String: Any]
106
101
  ])
107
102
  }
108
-
109
- // MARK: - Hashable
110
-
111
- public func hash(into hasher: inout Hasher) {
112
- hasher.combine(ObjectIdentifier(self))
113
- }
114
-
115
- public static func == (lhs: ScreenOrientationModule, rhs: ScreenOrientationModule) -> Bool {
116
- return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
117
- }
118
103
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import ExpoModulesCore
4
4
 
5
+ @objc(EXScreenOrientationReactDelegateHandler)
5
6
  public class ScreenOrientationReactDelegateHandler: ExpoReactDelegateHandler {
6
7
  public override func createRootViewController(reactDelegate: ExpoReactDelegate) -> UIViewController? {
7
8
  return ScreenOrientationViewController(defaultScreenOrientationFromPlist: ())
@@ -1,7 +1,7 @@
1
1
  import Foundation
2
2
  import ExpoModulesCore
3
3
 
4
- protocol OrientationListener {
4
+ public protocol ScreenOrientationController: AnyObject {
5
5
  func screenOrientationDidChange(_ orientation: UIInterfaceOrientation)
6
6
  }
7
7
 
@@ -14,10 +14,10 @@ public class ScreenOrientationRegistry: NSObject, UIApplicationDelegate {
14
14
  @objc
15
15
  public static let shared = ScreenOrientationRegistry()
16
16
 
17
- var currentScreenOrientation: UIInterfaceOrientation
18
- var orientationListeners: [ScreenOrientationModule?] = []
19
- var moduleInterfaceMasks: [ScreenOrientationModule: UIInterfaceOrientationMask] = [:]
20
- weak var currentTraitCollection: UITraitCollection?
17
+ public var currentScreenOrientation: UIInterfaceOrientation
18
+ var orientationControllers: [ScreenOrientationController] = []
19
+ var controllerInterfaceMasks: [ObjectIdentifier: UIInterfaceOrientationMask] = [:]
20
+ public weak var currentTraitCollection: UITraitCollection?
21
21
  var lastOrientationMask: UIInterfaceOrientationMask
22
22
  var rootViewController: UIViewController? {
23
23
  let keyWindow = UIApplication
@@ -29,7 +29,7 @@ public class ScreenOrientationRegistry: NSObject, UIApplicationDelegate {
29
29
  return keyWindow?.rootViewController
30
30
  }
31
31
 
32
- var currentOrientationMask: UIInterfaceOrientationMask {
32
+ public var currentOrientationMask: UIInterfaceOrientationMask {
33
33
  var currentOrientationMask: UIInterfaceOrientationMask = []
34
34
 
35
35
  EXUtilities.performSynchronously {
@@ -61,7 +61,7 @@ public class ScreenOrientationRegistry: NSObject, UIApplicationDelegate {
61
61
  /**
62
62
  Called by ScreenOrientationAppDelegate in order to set initial interface orientation.
63
63
  */
64
- func updateCurrentScreenOrientation() {
64
+ public func updateCurrentScreenOrientation() {
65
65
  let windows = UIApplication.shared.windows
66
66
  if !windows.isEmpty {
67
67
  self.currentScreenOrientation = windows[0].windowScene?.interfaceOrientation ?? .unknown
@@ -112,8 +112,10 @@ public class ScreenOrientationRegistry: NSObject, UIApplicationDelegate {
112
112
  }
113
113
  }
114
114
 
115
- func setMask(_ mask: UIInterfaceOrientationMask, forModule module: ScreenOrientationModule) {
116
- moduleInterfaceMasks[module] = mask
115
+ public func setMask(_ mask: UIInterfaceOrientationMask, forController controller: any ScreenOrientationController) {
116
+ let controllerIdentifier = ObjectIdentifier(controller)
117
+
118
+ controllerInterfaceMasks[controllerIdentifier] = mask
117
119
  enforceDesiredDeviceOrientation(withOrientationMask: mask)
118
120
  }
119
121
 
@@ -124,14 +126,14 @@ public class ScreenOrientationRegistry: NSObject, UIApplicationDelegate {
124
126
  */
125
127
  @objc
126
128
  public func requiredOrientationMask() -> UIInterfaceOrientationMask {
127
- if moduleInterfaceMasks.isEmpty {
129
+ if controllerInterfaceMasks.isEmpty {
128
130
  return []
129
131
  }
130
132
 
131
133
  // We want to apply an orientation mask which is an intersection of locks applied by the modules.
132
134
  var mask = doesDeviceHaveNotch ? UIInterfaceOrientationMask.allButUpsideDown : UIInterfaceOrientationMask.all
133
135
 
134
- for moduleMask in moduleInterfaceMasks {
136
+ for moduleMask in controllerInterfaceMasks {
135
137
  mask = mask.intersection(moduleMask.value)
136
138
  }
137
139
 
@@ -231,28 +233,24 @@ public class ScreenOrientationRegistry: NSObject, UIApplicationDelegate {
231
233
  }
232
234
 
233
235
  /**
234
- Called at the end of the screen orientation change. Notifies modules about the orientation change.
236
+ Called at the end of the screen orientation change. Notifies the controllers about the orientation change.
235
237
  */
236
238
  func screenOrientationDidChange(_ newScreenOrientation: UIInterfaceOrientation) {
237
239
  currentScreenOrientation = newScreenOrientation
238
- for module in orientationListeners {
239
- module?.screenOrientationDidChange(newScreenOrientation)
240
+
241
+ for controller in orientationControllers {
242
+ controller.screenOrientationDidChange(newScreenOrientation)
240
243
  }
241
244
  }
242
245
 
243
- func moduleWillDeallocate(_ module: ScreenOrientationModule) {
244
- moduleInterfaceMasks.removeValue(forKey: module)
246
+ public func registerController(_ controller: ScreenOrientationController) {
247
+ orientationControllers.append(controller)
245
248
  }
246
249
 
247
- func registerModuleToReceiveNotification(_ module: ScreenOrientationModule) {
248
- orientationListeners.append(module)
249
- }
250
+ public func unregisterController(_ controller: ScreenOrientationController) {
251
+ let controllerIdentifier = ObjectIdentifier(controller)
250
252
 
251
- func unregisterModuleFromReceivingNotification(_ module: ScreenOrientationModule) {
252
- for i in (0..<orientationListeners.count).reversed() {
253
- if orientationListeners[i] === module || orientationListeners[i] == nil {
254
- orientationListeners.remove(at: i)
255
- }
256
- }
253
+ controllerInterfaceMasks.removeValue(forKey: controllerIdentifier)
254
+ orientationControllers.removeAll(where: { $0 === controller })
257
255
  }
258
256
  }
@@ -73,6 +73,21 @@ internal func plistStringToInterfaceOrientationMask(_ maskName: String) -> UIInt
73
73
  }
74
74
  }
75
75
 
76
+ internal func orientationStringToInterfaceOrientationMask(_ orientationString: String) -> UIInterfaceOrientationMask? {
77
+ switch orientationString {
78
+ case "UIInterfaceOrientationPortrait":
79
+ return .portrait
80
+ case "UIInterfaceOrientationPortraitUpsideDown":
81
+ return .portraitUpsideDown
82
+ case "UIInterfaceOrientationLandscapeRight":
83
+ return .landscapeRight
84
+ case "UIInterfaceOrientationLandscapeLeft":
85
+ return .landscapeLeft
86
+ default:
87
+ return nil
88
+ }
89
+ }
90
+
76
91
  extension UIInterfaceOrientation {
77
92
  internal func toInterfaceOrientationMask() -> UIInterfaceOrientationMask {
78
93
  return UIInterfaceOrientationMask(rawValue: 1 << self.rawValue)
@@ -1,34 +1,44 @@
1
1
  import ExpoModulesCore
2
2
 
3
- let defaultScreenOrientationMask = "EXDefaultScreenOrientationMask"
3
+ let defaultScreenOrientationMaskKey = "EXDefaultScreenOrientationMask"
4
+ let supportedOrientationsKey = "UISupportedInterfaceOrientations"
5
+ let ipadSupportedOrientationsKey = "UISupportedInterfaceOrientations~ipad"
4
6
 
5
7
  class ScreenOrientationViewController: UIViewController {
6
8
  let screenOrientationRegistry = ScreenOrientationRegistry.shared
7
9
  private var defaultOrientationMask: UIInterfaceOrientationMask
8
10
 
9
- init(defaultOrientationMask: UIInterfaceOrientationMask = .portrait) {
11
+ init(defaultOrientationMask: UIInterfaceOrientationMask = doesDeviceHaveNotch ? .allButUpsideDown : .all) {
10
12
  self.defaultOrientationMask = defaultOrientationMask
11
13
  super.init(nibName: nil, bundle: nil)
12
14
  }
13
15
 
14
16
  convenience init(defaultScreenOrientationFromPlist: Void) {
15
- guard let orientationString = Bundle.main.object(forInfoDictionaryKey: defaultScreenOrientationMask) as? String else {
16
- self.init(defaultOrientationMask: .portrait)
17
+ let supportedInterfaceOrientations = ScreenOrientationViewController.getSupportedInterfaceOrientations()
18
+
19
+ guard let orientationString = Bundle.main.object(forInfoDictionaryKey: defaultScreenOrientationMaskKey) as? String else {
20
+ // If user hasn't defined a default interface orientation using the config plugin use the allowed values from Info.plist as the
21
+ // default orientation. Values in Info.plist are set with the "orientation" key in app.json
22
+ self.init(defaultOrientationMask: supportedInterfaceOrientations)
17
23
  return
18
24
  }
19
25
 
20
26
  guard let mask = plistStringToInterfaceOrientationMask(orientationString) else {
21
- log.warn("Orientation lock string '\(orientationString)' provided in Info.plist does not correspond to a valid orientation mask. Application will default to portrait orientation lock.")
22
- self.init(defaultOrientationMask: .portrait)
27
+ log.warn("Orientation lock string '\(orientationString)' provided in Info.plist does not correspond to a valid orientation mask. Application will default to orientation mask set in \(supportedOrientationsKey).")
28
+ self.init(defaultOrientationMask: supportedInterfaceOrientations)
23
29
  return
24
30
  }
25
31
 
26
32
  guard mask.isSupportedByDevice() else {
27
- log.warn("Orientation lock string '\(orientationString)' provided in Info.plist is not supported by the device. Application will default to portrait orientation lock.")
28
- self.init(defaultOrientationMask: .portrait)
33
+ log.warn("Orientation lock string '\(orientationString)' provided in Info.plist is not supported by the device. Application will default to orientation lock set in \(supportedOrientationsKey).")
34
+ self.init(defaultOrientationMask: supportedInterfaceOrientations)
29
35
  return
30
36
  }
31
37
 
38
+ if mask != mask.intersection(supportedInterfaceOrientations) {
39
+ log.warn("Info.plist: Orientations allowed in `\(supportedOrientationsKey)` are in conflict with the values allowed in `\(defaultScreenOrientationMaskKey)`. Values from `\(defaultScreenOrientationMaskKey)` will be used. When setting the initial orientation using the config plugin delete the `\"orientation\"` key from `app.json`")
40
+ }
41
+
32
42
  self.init(defaultOrientationMask: mask)
33
43
  }
34
44
 
@@ -61,4 +71,27 @@ class ScreenOrientationViewController: UIViewController {
61
71
  }
62
72
  return screenWindowTraitsClass.shouldAskScreensForScreenOrientation?(in: self) ?? false
63
73
  }
74
+
75
+ /**
76
+ * Parses the lists under the key 'UISupportedInterfaceOrientations' in Info.plist into a UIInterfaceOrientation mask. Also checks for ipad specific settings.
77
+ * If no orientation is found all possible orientations will be returned.
78
+ */
79
+ private static func getSupportedInterfaceOrientations() -> UIInterfaceOrientationMask {
80
+ let allPossibleOrientations: UIInterfaceOrientationMask = doesDeviceHaveNotch ? .allButUpsideDown : .all
81
+ let ipadSupportedOrientationStrings = Bundle.main.object(forInfoDictionaryKey: ipadSupportedOrientationsKey) as? [String] ?? []
82
+ let commonSupportedOrientationStrings = Bundle.main.object(forInfoDictionaryKey: supportedOrientationsKey) as? [String] ?? []
83
+ let supportedOrientationStrings = (isPad() && !ipadSupportedOrientationStrings.isEmpty) ?
84
+ ipadSupportedOrientationStrings : commonSupportedOrientationStrings
85
+ var orientationMask: UIInterfaceOrientationMask = []
86
+
87
+ for orientationString in supportedOrientationStrings {
88
+ guard let orientation = orientationStringToInterfaceOrientationMask(orientationString) else {
89
+ log.warn("Info.plist: \(orientationString) is not a valid value for the \(supportedOrientationsKey) key")
90
+ continue
91
+ }
92
+ orientationMask.insert(orientation)
93
+ }
94
+
95
+ return orientationMask.isEmpty ? allPossibleOrientations : orientationMask
96
+ }
64
97
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-screen-orientation",
3
- "version": "6.0.1",
3
+ "version": "6.0.3",
4
4
  "description": "Expo universal module for managing device's screen orientation",
5
5
  "main": "build/ScreenOrientation.js",
6
6
  "types": "build/ScreenOrientation.d.ts",
@@ -41,5 +41,5 @@
41
41
  "peerDependencies": {
42
42
  "expo": "*"
43
43
  },
44
- "gitHead": "a72ae33519fe54eaf195dc3e61a49db8345103db"
44
+ "gitHead": "8fdc53c90c52242a80ea511ee3073d9ab950bc68"
45
45
  }