expo-modules-core 1.11.4 → 1.11.6

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 (39) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/ExpoModulesCore.podspec +5 -1
  3. package/android/build.gradle +3 -4
  4. package/android/proguard-rules.pro +1 -1
  5. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +1 -1
  6. package/android/src/main/java/expo/modules/kotlin/types/DateTypeConverter.kt +45 -0
  7. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +3 -1
  8. package/expo-module.config.json +1 -1
  9. package/ios/AppContext.swift +21 -4
  10. package/ios/AppDelegates/EXAppDelegateWrapper.h +2 -1
  11. package/ios/AppDelegates/EXAppDelegateWrapper.mm +6 -2
  12. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +4 -1
  13. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.m +8 -1
  14. package/ios/AppDelegates/ExpoAppDelegate.swift +6 -3
  15. package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +10 -3
  16. package/ios/Arguments/Convertibles.swift +18 -1
  17. package/ios/EXDefines.h +7 -1
  18. package/ios/Interfaces/BarcodeScanner/EXBarcodeScannerInterface.h +0 -1
  19. package/ios/Interfaces/FaceDetector/EXFaceDetectorManagerInterface.h +0 -1
  20. package/ios/Interfaces/Font/EXFontProcessorInterface.h +1 -1
  21. package/ios/Interfaces/Font/EXFontScalerInterface.h +1 -1
  22. package/ios/Interfaces/ImageLoader/EXImageLoaderInterface.h +1 -1
  23. package/ios/Legacy/EXUtilities.h +1 -1
  24. package/ios/Legacy/EXUtilities.m +11 -2
  25. package/ios/Legacy/Protocols/EXUIManager.h +2 -1
  26. package/ios/Legacy/Protocols/EXUtilitiesInterface.h +1 -1
  27. package/ios/Legacy/Services/EXReactNativeAdapter.mm +20 -2
  28. package/ios/Modules/ModuleDefinitionComponents.swift +0 -2
  29. package/ios/Platform.h +23 -0
  30. package/ios/Platform.swift +12 -0
  31. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +1 -2
  32. package/ios/ReactDelegates/EXReactDelegateWrapper.h +1 -1
  33. package/ios/Tests/ConvertiblesSpec.swift +16 -0
  34. package/ios/Views/AnyViewProp.swift +0 -2
  35. package/ios/Views/ConcreteViewProp.swift +0 -2
  36. package/ios/Views/ViewFactory.swift +0 -2
  37. package/ios/Views/ViewManagerDefinition.swift +0 -2
  38. package/ios/Views/ViewModuleWrapper.swift +0 -1
  39. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -10,6 +10,25 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 1.11.6 — 2024-01-12
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 1.11.5 — 2024-01-10
18
+
19
+ ### 🎉 New features
20
+
21
+ - Added support for macOS platform. ([#26186](https://github.com/expo/expo/pull/26186) by [@tsapeta](https://github.com/tsapeta))
22
+ - Add `Date` type converter. ([#26148](https://github.com/expo/expo/pull/26148) by [@alanjhughes](https://github.com/alanjhughes))
23
+
24
+ ### 🐛 Bug fixes
25
+
26
+ - Adjust proguard rules to prevent issues with types implementing `Enumerable`. ([#26108](https://github.com/expo/expo/pull/26108) by [@alanjhughes](https://github.com/alanjhughes))
27
+
28
+ ### 💡 Others
29
+
30
+ - Replace deprecated `com.facebook.react:react-native:+` Android dependency with `com.facebook.react:react-android`. ([#26237](https://github.com/expo/expo/pull/26237) by [@kudo](https://github.com/kudo))
31
+
13
32
  ## 1.11.4 — 2023-12-21
14
33
 
15
34
  _This version does not introduce any user-facing changes._
@@ -24,7 +24,11 @@ Pod::Spec.new do |s|
24
24
  s.license = package['license']
25
25
  s.author = package['author']
26
26
  s.homepage = package['homepage']
27
- s.platforms = { :ios => '13.4', :tvos => '13.4'}
27
+ s.platforms = {
28
+ :ios => '13.4',
29
+ :osx => '10.15',
30
+ :tvos => '13.4'
31
+ }
28
32
  s.swift_version = '5.4'
29
33
  s.source = { git: 'https://github.com/expo/expo.git' }
30
34
  s.static_framework = true
@@ -5,7 +5,7 @@ apply plugin: 'kotlin-android'
5
5
  apply plugin: 'maven-publish'
6
6
 
7
7
  group = 'host.exp.exponent'
8
- version = '1.11.4'
8
+ version = '1.11.6'
9
9
 
10
10
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
11
11
  if (expoModulesCorePlugin.exists()) {
@@ -143,7 +143,7 @@ android {
143
143
  defaultConfig {
144
144
  consumerProguardFiles 'proguard-rules.pro'
145
145
  versionCode 1
146
- versionName "1.11.4"
146
+ versionName "1.11.6"
147
147
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
148
148
 
149
149
  testInstrumentationRunner "expo.modules.TestRunner"
@@ -235,8 +235,7 @@ dependencies {
235
235
 
236
236
  implementation("androidx.tracing:tracing-ktx:1.2.0")
237
237
 
238
- //noinspection GradleDynamicVersion
239
- implementation 'com.facebook.react:react-native:+'
238
+ implementation 'com.facebook.react:react-android'
240
239
 
241
240
  compileOnly 'com.facebook.fbjni:fbjni:0.5.1'
242
241
 
@@ -14,7 +14,7 @@
14
14
  -keep class * implements expo.modules.kotlin.records.Record {
15
15
  *;
16
16
  }
17
- -keepclassmembers enum * implements expo.modules.kotlin.types.Enumerable {
17
+ -keep enum * implements expo.modules.kotlin.types.Enumerable {
18
18
  *;
19
19
  }
20
20
 
@@ -46,7 +46,7 @@ class ModuleRegistry(
46
46
 
47
47
  fun register(provider: ModulesProvider) = apply {
48
48
  provider.getModulesList().forEach { type ->
49
- val module = type.newInstance()
49
+ val module = type.getDeclaredConstructor().newInstance()
50
50
  register(module)
51
51
  }
52
52
  }
@@ -0,0 +1,45 @@
1
+ package expo.modules.kotlin.types
2
+
3
+ import android.os.Build
4
+ import androidx.annotation.RequiresApi
5
+ import com.facebook.react.bridge.Dynamic
6
+ import com.facebook.react.bridge.ReadableType
7
+ import expo.modules.kotlin.exception.UnexpectedException
8
+ import expo.modules.kotlin.jni.CppType
9
+ import expo.modules.kotlin.jni.ExpectedType
10
+ import expo.modules.kotlin.jni.SingleType
11
+ import java.time.Instant
12
+ import java.time.LocalDate
13
+ import java.time.ZoneId
14
+ import java.time.format.DateTimeFormatter
15
+
16
+ @RequiresApi(Build.VERSION_CODES.O)
17
+ class DateTypeConverter(isOptional: Boolean) : DynamicAwareTypeConverters<LocalDate>(isOptional) {
18
+ override fun convertFromDynamic(value: Dynamic): LocalDate {
19
+ return when (value.type) {
20
+ ReadableType.String -> LocalDate.parse(value.asString(), DateTimeFormatter.ISO_DATE_TIME)
21
+ ReadableType.Number -> convertFromLong(value.asDouble().toLong())
22
+ else -> throw UnexpectedException("Unknown argument type: ${value.type}")
23
+ }
24
+ }
25
+
26
+ override fun convertFromAny(value: Any): LocalDate {
27
+ return when (value) {
28
+ is String -> LocalDate.parse(value, DateTimeFormatter.ISO_DATE_TIME)
29
+ is Long -> convertFromLong(value)
30
+ else -> throw UnexpectedException("Unknown argument type: ${value::class}")
31
+ }
32
+ }
33
+
34
+ private fun convertFromLong(value: Long): LocalDate {
35
+ val instant = Instant.ofEpochMilli(value)
36
+ return instant.atZone(ZoneId.systemDefault()).toLocalDate()
37
+ }
38
+
39
+ override fun getCppRequiredTypes() = ExpectedType(
40
+ SingleType(CppType.INT),
41
+ SingleType(CppType.STRING)
42
+ )
43
+
44
+ override fun isTrivial() = false
45
+ }
@@ -41,6 +41,7 @@ import java.io.File
41
41
  import java.net.URI
42
42
  import java.net.URL
43
43
  import java.nio.file.Path
44
+ import java.time.LocalDate
44
45
  import kotlin.reflect.KClass
45
46
  import kotlin.reflect.KType
46
47
  import kotlin.reflect.typeOf
@@ -302,7 +303,8 @@ object TypeConverterProviderImpl : TypeConverterProvider {
302
303
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
303
304
  return converters + mapOf(
304
305
  Path::class to PathTypeConverter(isOptional),
305
- Color::class to ColorTypeConverter(isOptional)
306
+ Color::class to ColorTypeConverter(isOptional),
307
+ LocalDate::class to DateTypeConverter(isOptional)
306
308
  )
307
309
  }
308
310
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "platforms": ["ios", "android"],
2
+ "platforms": ["ios", "android", "macos", "tvos"],
3
3
  "ios": {
4
4
  "podspecPath": "./ExpoModulesCore.podspec"
5
5
  }
@@ -1,5 +1,3 @@
1
- import UIKit
2
-
3
1
  /**
4
2
  The app context is an interface to a single Expo app.
5
3
  */
@@ -213,11 +211,21 @@ public final class AppContext: NSObject {
213
211
  Starts listening to `UIApplication` notifications.
214
212
  */
215
213
  private func listenToClientAppNotifications() {
216
- [
214
+ #if os(iOS) || os(tvOS)
215
+ let notifications = [
217
216
  UIApplication.willEnterForegroundNotification,
218
217
  UIApplication.didBecomeActiveNotification,
219
218
  UIApplication.didEnterBackgroundNotification
220
- ].forEach { name in
219
+ ]
220
+ #elseif os(macOS)
221
+ let notifications = [
222
+ NSApplication.willUnhideNotification,
223
+ NSApplication.didBecomeActiveNotification,
224
+ NSApplication.didHideNotification
225
+ ]
226
+ #endif
227
+
228
+ notifications.forEach { name in
221
229
  NotificationCenter.default.addObserver(self, selector: #selector(handleClientAppNotification(_:)), name: name, object: nil)
222
230
  }
223
231
  }
@@ -228,12 +236,21 @@ public final class AppContext: NSObject {
228
236
  @objc
229
237
  private func handleClientAppNotification(_ notification: Notification) {
230
238
  switch notification.name {
239
+ #if os(iOS) || os(tvOS)
231
240
  case UIApplication.willEnterForegroundNotification:
232
241
  moduleRegistry.post(event: .appEntersForeground)
233
242
  case UIApplication.didBecomeActiveNotification:
234
243
  moduleRegistry.post(event: .appBecomesActive)
235
244
  case UIApplication.didEnterBackgroundNotification:
236
245
  moduleRegistry.post(event: .appEntersBackground)
246
+ #elseif os(macOS)
247
+ case NSApplication.willUnhideNotification:
248
+ moduleRegistry.post(event: .appEntersForeground)
249
+ case NSApplication.didBecomeActiveNotification:
250
+ moduleRegistry.post(event: .appBecomesActive)
251
+ case NSApplication.didHideNotification:
252
+ moduleRegistry.post(event: .appEntersBackground)
253
+ #endif
237
254
  default:
238
255
  return
239
256
  }
@@ -1,8 +1,9 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
+ #import <ExpoModulesCore/Platform.h>
4
+
3
5
  #if __cplusplus
4
6
 
5
- #import <UIKit/UIKit.h>
6
7
  #import <ExpoModulesCore/EXReactDelegateWrapper.h>
7
8
 
8
9
  #if __has_include(<React-RCTAppDelegate/RCTAppDelegate.h>)
@@ -4,7 +4,6 @@
4
4
  #import <ExpoModulesCore/EXReactDelegateWrapper+Private.h>
5
5
  #import <ExpoModulesCore/Swift.h>
6
6
 
7
-
8
7
  @interface EXAppDelegateWrapper()
9
8
 
10
9
  @property (nonatomic, strong) EXReactDelegateWrapper *reactDelegate;
@@ -44,12 +43,14 @@
44
43
 
45
44
  #if __has_include(<React-RCTAppDelegate/RCTAppDelegate.h>) || __has_include(<React_RCTAppDelegate/RCTAppDelegate.h>)
46
45
 
46
+ #if !TARGET_OS_OSX
47
47
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
48
48
  {
49
49
  [super application:application didFinishLaunchingWithOptions:launchOptions];
50
50
  [_expoAppDelegate application:application didFinishLaunchingWithOptions:launchOptions];
51
51
  return YES;
52
52
  }
53
+ #endif // !TARGET_OS_OSX
53
54
 
54
55
  - (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
55
56
  {
@@ -69,8 +70,11 @@
69
70
  moduleName:moduleName
70
71
  initialProperties:initProps
71
72
  fabricEnabled:enableFabric];
72
- #if !TARGET_OS_TV
73
+ #if TARGET_OS_IOS
73
74
  rootView.backgroundColor = UIColor.systemBackgroundColor;
75
+ #elif TARGET_OS_OSX
76
+ rootView.wantsLayer = YES;
77
+ rootView.layer.backgroundColor = NSColor.windowBackgroundColor.CGColor;
74
78
  #endif
75
79
  return rootView;
76
80
  }
@@ -1,7 +1,6 @@
1
1
  // Copyright © 2018 650 Industries. All rights reserved.
2
2
 
3
3
  #import <Foundation/Foundation.h>
4
- #import <UIKit/UIKit.h>
5
4
 
6
5
  NS_ASSUME_NONNULL_BEGIN
7
6
 
@@ -9,7 +8,11 @@ NS_ASSUME_NONNULL_BEGIN
9
8
  The legacy wrapper is still used to forward app delegate calls to singleton modules.
10
9
  See `EXAppDelegatesLoader.m` which registers this class as a subscriber of `ExpoAppDelegate`.
11
10
  */
11
+ #if TARGET_OS_OSX
12
+ @interface EXLegacyAppDelegateWrapper : NSResponder <NSApplicationDelegate>
13
+ #else
12
14
  @interface EXLegacyAppDelegateWrapper : UIResponder <UIApplicationDelegate>
15
+ #endif
13
16
 
14
17
  @end
15
18
 
@@ -3,15 +3,21 @@
3
3
  #import <Foundation/FoundationErrors.h>
4
4
 
5
5
  #import <ExpoModulesCore/EXSingletonModule.h>
6
+ #import <ExpoModulesCore/Platform.h>
6
7
  #import <ExpoModulesCore/EXModuleRegistryProvider.h>
7
8
  #import <ExpoModulesCore/EXLegacyAppDelegateWrapper.h>
8
9
 
10
+ #if !TARGET_OS_OSX
9
11
  static NSMutableArray<id<UIApplicationDelegate>> *subcontractors;
10
12
  static NSMutableDictionary<NSString *,NSArray<id<UIApplicationDelegate>> *> *subcontractorsForSelector;
11
13
  static dispatch_once_t onceToken;
14
+ #endif
12
15
 
13
16
  @implementation EXLegacyAppDelegateWrapper
14
17
 
18
+ // The legacy app delegate wrapper is not supported on macOS, but we keep it no-op for convenience.
19
+ #if !TARGET_OS_OSX
20
+
15
21
  @synthesize window = _window;
16
22
 
17
23
  - (void)forwardInvocation:(NSInvocation *)invocation {
@@ -216,7 +222,6 @@ static dispatch_once_t onceToken;
216
222
  }
217
223
  }
218
224
 
219
-
220
225
  #pragma mark - Subcontractors
221
226
 
222
227
  - (void)ensureSubcontractorsAreInitializedAndSorted {
@@ -261,4 +266,6 @@ static dispatch_once_t onceToken;
261
266
  return result;
262
267
  }
263
268
 
269
+ #endif // !TARGET_OS_OSX
270
+
264
271
  @end
@@ -1,4 +1,3 @@
1
- import UIKit
2
1
  import Dispatch
3
2
  import Foundation
4
3
 
@@ -18,6 +17,7 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
18
17
  @objc
19
18
  public let reactDelegate = ExpoReactDelegate(handlers: reactDelegateHandlers)
20
19
 
20
+ #if os(iOS) || os(tvOS)
21
21
  // MARK: - Initializing the App
22
22
 
23
23
  open func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
@@ -317,6 +317,8 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
317
317
  }
318
318
  #endif
319
319
 
320
+ #endif // os(iOS)
321
+
320
322
  // MARK: - Statics
321
323
 
322
324
  @objc
@@ -354,7 +356,8 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
354
356
  }
355
357
  }
356
358
  }
357
- #if !os(tvOS)
359
+
360
+ #if os(iOS)
358
361
  private func allowedOrientations(for userInterfaceIdiom: UIUserInterfaceIdiom) -> UIInterfaceOrientationMask {
359
362
  // For now only iPad-specific orientations are supported
360
363
  let deviceString = userInterfaceIdiom == .pad ? "~pad" : ""
@@ -379,4 +382,4 @@ private func allowedOrientations(for userInterfaceIdiom: UIUserInterfaceIdiom) -
379
382
  }
380
383
  return mask
381
384
  }
382
- #endif
385
+ #endif // os(iOS)
@@ -1,14 +1,21 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- import UIKit
4
-
5
3
  /**
6
4
  Base class for app delegate subscribers. Ensures the class
7
5
  inherits from `UIResponder` and has `required init()` initializer.
8
6
  */
9
7
  @objc(EXBaseAppDelegateSubscriber)
10
8
  open class BaseExpoAppDelegateSubscriber: UIResponder {
11
- public override required init() {}
9
+ public override required init() {
10
+ super.init()
11
+ }
12
+
13
+ #if os(macOS)
14
+ @available(*, unavailable)
15
+ public required init?(coder: NSCoder) {
16
+ fatalError("init(coder:) has not been implemented")
17
+ }
18
+ #endif // os(macOS)
12
19
  }
13
20
 
14
21
  /**
@@ -1,6 +1,5 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- import UIKit
4
3
  import CoreGraphics
5
4
 
6
5
  // Here we extend some common iOS types to implement `Convertible` protocol and
@@ -96,3 +95,21 @@ extension CGRect: Convertible {
96
95
  throw Conversions.ConvertingException<CGRect>(value)
97
96
  }
98
97
  }
98
+
99
+ extension Date: Convertible {
100
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Date {
101
+ if let value = value as? String {
102
+ let formatter = ISO8601DateFormatter()
103
+ formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
104
+ guard let date = formatter.date(from: value) else {
105
+ throw Conversions.ConvertingException<Date>(value)
106
+ }
107
+ return date
108
+ }
109
+ // For converting the value from `Date.now()`
110
+ if let value = value as? Int {
111
+ return Date(timeIntervalSince1970: Double(value) / 1000.0)
112
+ }
113
+ throw Conversions.ConvertingException<Date>(value)
114
+ }
115
+ }
package/ios/EXDefines.h CHANGED
@@ -78,7 +78,8 @@ if (var == nil) { return; }
78
78
  // Converts nil -> [NSNull null]
79
79
  #define EXNullIfNil(value) (value ?: [NSNull null])
80
80
 
81
- #import <UIKit/UIKit.h>
81
+ #import <ExpoModulesCore/Platform.h>
82
+
82
83
  #import <Foundation/Foundation.h>
83
84
 
84
85
  typedef struct EXMethodInfo {
@@ -103,6 +104,11 @@ EX_EXTERN void EXLogWarn(NSString *format, ...);
103
104
  EX_EXTERN void EXLogError(NSString *format, ...);
104
105
  EX_EXTERN void EXFatal(NSError *);
105
106
  EX_EXTERN NSError * EXErrorWithMessage(NSString *);
107
+
108
+ #if TARGET_OS_OSX
109
+ EX_EXTERN NSApplication *EXSharedApplication(void);
110
+ #else
106
111
  EX_EXTERN UIApplication *EXSharedApplication(void);
112
+ #endif
107
113
 
108
114
  EX_EXTERN_C_END
@@ -2,7 +2,6 @@
2
2
 
3
3
  #import <Foundation/Foundation.h>
4
4
  #import <AVFoundation/AVFoundation.h>
5
- #import <UIKit/UIKit.h>
6
5
 
7
6
  @protocol EXBarCodeScannerInterface
8
7
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  #import <Foundation/Foundation.h>
4
4
  #import <AVFoundation/AVFoundation.h>
5
- #import <UIKit/UIKit.h>
6
5
 
7
6
  @protocol EXFaceDetectorManagerInterface
8
7
  #if !TARGET_OS_TV
@@ -1,6 +1,6 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <UIKit/UIKit.h>
3
+ #import <ExpoModulesCore/Platform.h>
4
4
 
5
5
  @protocol EXFontProcessorInterface
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <UIKit/UIKit.h>
3
+ #import <ExpoModulesCore/Platform.h>
4
4
 
5
5
  @protocol EXFontScalerInterface
6
6
 
@@ -1,6 +1,6 @@
1
1
  // Copyright © 2018 650 Industries. All rights reserved.
2
2
 
3
- #import <UIKit/UIKit.h>
3
+ #import <ExpoModulesCore/Platform.h>
4
4
 
5
5
  typedef void (^EXImageLoaderCompletionBlock)(NSError *error, UIImage *image);
6
6
 
@@ -1,8 +1,8 @@
1
1
  // Copyright © 2018 650 Industries. All rights reserved.
2
2
 
3
3
  #import <Foundation/Foundation.h>
4
- #import <UIKit/UIKit.h>
5
4
 
5
+ #import <ExpoModulesCore/Platform.h>
6
6
  #import <ExpoModulesCore/EXInternalModule.h>
7
7
  #import <ExpoModulesCore/EXUtilitiesInterface.h>
8
8
  #import <ExpoModulesCore/EXModuleRegistryConsumer.h>
@@ -39,6 +39,7 @@ EX_REGISTER_MODULE();
39
39
 
40
40
  - (UIViewController *)currentViewController
41
41
  {
42
+ #if TARGET_OS_IOS || TARGET_OS_TV
42
43
  id<EXUtilService> utilService = [_moduleRegistry getSingletonModuleForName:@"Util"];
43
44
 
44
45
  if (utilService != nil) {
@@ -47,12 +48,16 @@ EX_REGISTER_MODULE();
47
48
 
48
49
  UIViewController *controller = [[[UIApplication sharedApplication] keyWindow] rootViewController];
49
50
  UIViewController *presentedController = controller.presentedViewController;
50
-
51
+
51
52
  while (presentedController && ![presentedController isBeingDismissed]) {
52
53
  controller = presentedController;
53
54
  presentedController = controller.presentedViewController;
54
55
  }
55
56
  return controller;
57
+ #elif TARGET_OS_OSX
58
+ // Even though the function's return type is `UIViewController`, react-native-macos will alias `NSViewController` to `UIViewController`.
59
+ return [[[NSApplication sharedApplication] keyWindow] contentViewController];
60
+ #endif
56
61
  }
57
62
 
58
63
  + (void)performSynchronouslyOnMainThread:(void (^)(void))block
@@ -102,7 +107,11 @@ EX_REGISTER_MODULE();
102
107
  static CGFloat scale;
103
108
 
104
109
  [self unsafeExecuteOnMainQueueOnceSync:&onceToken block:^{
105
- scale = [UIScreen mainScreen].scale;
110
+ #if TARGET_OS_IOS || TARGET_OS_TV
111
+ scale = [UIScreen mainScreen].scale;
112
+ #elif TARGET_OS_OSX
113
+ scale = [NSScreen mainScreen].backingScaleFactor;
114
+ #endif
106
115
  }];
107
116
 
108
117
  return scale;
@@ -1,7 +1,8 @@
1
1
  // Copyright © 2018 650 Industries. All rights reserved.
2
2
 
3
3
  #import <Foundation/Foundation.h>
4
- #import <UIKit/UIKit.h>
4
+
5
+ #import <ExpoModulesCore/Platform.h>
5
6
 
6
7
  @protocol EXUIManager <NSObject>
7
8
 
@@ -1,6 +1,6 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
- #import <UIKit/UIKit.h>
3
+ #import <ExpoModulesCore/Platform.h>
4
4
 
5
5
  @protocol EXUtilitiesInterface
6
6
 
@@ -226,11 +226,11 @@ EX_REGISTER_MODULE();
226
226
  _isForegrounded && (
227
227
  [notification.name isEqualToString:UIApplicationWillResignActiveNotification] ||
228
228
  [notification.name isEqualToString:UIApplicationDidEnterBackgroundNotification] ||
229
- RCTSharedApplication().applicationState == UIApplicationStateBackground
229
+ [self isApplicationStateBackground]
230
230
  )
231
231
  ) {
232
232
  [self setAppStateToBackground];
233
- } else if (!_isForegrounded && RCTSharedApplication().applicationState == UIApplicationStateActive) {
233
+ } else if (!_isForegrounded && [self isApplicationStateActive]) {
234
234
  [self setAppStateToForeground];
235
235
  }
236
236
  }
@@ -315,4 +315,22 @@ EX_REGISTER_MODULE();
315
315
  });
316
316
  }
317
317
 
318
+ - (BOOL)isApplicationStateBackground
319
+ {
320
+ #if TARGET_OS_IOS || TARGET_OS_TV
321
+ return RCTSharedApplication().applicationState == UIApplicationStateBackground;
322
+ #elif TARGET_OS_OSX
323
+ return RCTSharedApplication().isHidden;
324
+ #endif
325
+ }
326
+
327
+ - (BOOL)isApplicationStateActive
328
+ {
329
+ #if TARGET_OS_IOS || TARGET_OS_TV
330
+ return RCTSharedApplication().applicationState == UIApplicationStateActive;
331
+ #elif TARGET_OS_OSX
332
+ return RCTSharedApplication().isActive;
333
+ #endif
334
+ }
335
+
318
336
  @end
@@ -1,5 +1,3 @@
1
- import UIKit
2
-
3
1
  // MARK: - Module name
4
2
 
5
3
  /**
package/ios/Platform.h ADDED
@@ -0,0 +1,23 @@
1
+ // Copyright 2024-present 650 Industries. All rights reserved.
2
+
3
+ #if TARGET_OS_IOS || TARGET_OS_TV
4
+
5
+ #import <UIKit/UIKit.h>
6
+
7
+ #elif TARGET_OS_OSX
8
+
9
+ #import <AppKit/AppKit.h>
10
+ #import <React/RCTUIKit.h>
11
+
12
+ @compatibility_alias UIView NSView;
13
+ @compatibility_alias UIResponder NSResponder;
14
+ @compatibility_alias UIColor NSColor;
15
+ @compatibility_alias UIWindow NSWindow;
16
+
17
+ #ifndef UIApplication
18
+ @compatibility_alias UIApplication NSApplication;
19
+ #endif
20
+
21
+ @protocol UIApplicationDelegate <NSApplicationDelegate> @end
22
+
23
+ #endif // TARGET_OS_OSX
@@ -0,0 +1,12 @@
1
+ #if os(macOS)
2
+
3
+ import AppKit
4
+
5
+ public typealias UIApplication = NSApplication
6
+ public typealias UIView = NSView
7
+ public typealias UIViewController = NSViewController
8
+ public typealias UIResponder = NSResponder
9
+ public typealias UIApplicationDelegate = NSApplicationDelegate
10
+ public typealias UIWindow = NSWindow
11
+
12
+ #endif // os(macOS)
@@ -1,7 +1,6 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <UIKit/UIKit.h>
4
-
3
+ #import <ExpoModulesCore/Platform.h>
5
4
  #import <ExpoModulesCore/EXDefines.h>
6
5
  #import <React/RCTBridge.h>
7
6
 
@@ -1,8 +1,8 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <UIKit/UIKit.h>
4
3
  #import <React/RCTBridge.h>
5
4
  #import <React/RCTRootView.h>
5
+ #import <ExpoModulesCore/Platform.h>
6
6
 
7
7
  NS_ASSUME_NONNULL_BEGIN
8
8
 
@@ -381,5 +381,21 @@ class ConvertiblesSpec: ExpoSpec {
381
381
  })
382
382
  }
383
383
  }
384
+
385
+ describe("Date") {
386
+ it("converts from `ISO 8601` String to Date") {
387
+ let date = try Date.convert(from: "2023-12-27T10:58:20.654Z", appContext: appContext)
388
+ let components = Calendar.current.dateComponents([.day, .month], from: date)
389
+ expect(components.month) == 12
390
+ expect(components.day) == 27
391
+ }
392
+
393
+ it("converts from `Date.now()` to Date") {
394
+ let date = try Date.convert(from: 1703718341639, appContext: appContext)
395
+ let components = Calendar.current.dateComponents([.day, .month], from: date)
396
+ expect(components.month) == 12
397
+ expect(components.day) == 27
398
+ }
399
+ }
384
400
  }
385
401
  }
@@ -1,5 +1,3 @@
1
- import UIKit
2
-
3
1
  /**
4
2
  Type-erased protocol for view props classes.
5
3
  */
@@ -1,7 +1,5 @@
1
1
  // Copyright 2021-present 650 Industries. All rights reserved.
2
2
 
3
- import UIKit
4
-
5
3
  /**
6
4
  Specialized class for the view prop. Specifies the prop name and its setter.
7
5
  */
@@ -1,5 +1,3 @@
1
- import UIKit
2
-
3
1
  /**
4
2
  A definition of the view factory that creates views.
5
3
  */
@@ -1,5 +1,3 @@
1
- import UIKit
2
-
3
1
  /**
4
2
  The definition of the view manager. It's part of the module definition to scope only view-related definitions.
5
3
  */
@@ -1,4 +1,3 @@
1
- import UIKit
2
1
  import ObjectiveC
3
2
 
4
3
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-core",
3
- "version": "1.11.4",
3
+ "version": "1.11.6",
4
4
  "description": "The core of Expo Modules architecture",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -44,5 +44,5 @@
44
44
  "@testing-library/react-hooks": "^7.0.1",
45
45
  "expo-module-scripts": "^3.0.0"
46
46
  },
47
- "gitHead": "36402c8b2bc9b63f003c04642d97bf091b35fe16"
47
+ "gitHead": "f9100f83a5d971dbdef83336a8f055046566fa83"
48
48
  }