@neoskola/auto-play 0.3.15 → 0.3.17

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/ios/Types.swift CHANGED
@@ -20,4 +20,5 @@ enum AutoPlayError: Error {
20
20
  case invalidTemplateType(String)
21
21
  case noUiWindow(String)
22
22
  case initReactRootViewFailed(String)
23
+ case pushFailed(String)
23
24
  }
@@ -61,7 +61,11 @@ class AutoPlayInterfaceController: NSObject, CPInterfaceControllerDelegate {
61
61
  return true
62
62
  }
63
63
 
64
- return pushNowPlayingTemplateSafely(animated: animated)
64
+ let success = await pushNowPlayingTemplateSafely(animated: animated)
65
+ if !success {
66
+ throw AutoPlayError.pushFailed("CPNowPlayingTemplate push failed")
67
+ }
68
+ return true
65
69
  }
66
70
 
67
71
  return try await interfaceController.pushTemplate(
@@ -71,19 +75,26 @@ class AutoPlayInterfaceController: NSObject, CPInterfaceControllerDelegate {
71
75
  }
72
76
 
73
77
  /// Pushes CPNowPlayingTemplate using ObjC @try/@catch to prevent crash from NSException.
74
- /// The push call is made entirely in Objective-C so NSExceptions never propagate through Swift frames.
75
- private func pushNowPlayingTemplateSafely(animated: Bool) -> Bool {
76
- do {
77
- try ObjCExceptionCatcher.push(
78
- CPNowPlayingTemplate.shared,
79
- on: self.interfaceController,
80
- animated: animated
81
- )
82
- print("[AutoPlay] CPNowPlayingTemplate pushed successfully")
83
- return true
84
- } catch {
85
- print("[AutoPlay] CPNowPlayingTemplate push threw ObjC exception: \(error.localizedDescription)")
86
- return false
78
+ /// Uses a completion handler to confirm the push actually succeeded.
79
+ private func pushNowPlayingTemplateSafely(animated: Bool) async -> Bool {
80
+ return await withCheckedContinuation { continuation in
81
+ do {
82
+ try ObjCExceptionCatcher.push(
83
+ CPNowPlayingTemplate.shared,
84
+ on: self.interfaceController,
85
+ animated: animated,
86
+ completion: { success, error in
87
+ if let error = error {
88
+ print("[AutoPlay] CPNowPlayingTemplate push completion error: \(error.localizedDescription)")
89
+ }
90
+ print("[AutoPlay] CPNowPlayingTemplate push completion: success=\(success)")
91
+ continuation.resume(returning: success)
92
+ }
93
+ )
94
+ } catch {
95
+ print("[AutoPlay] CPNowPlayingTemplate push threw ObjC exception: \(error.localizedDescription)")
96
+ continuation.resume(returning: false)
97
+ }
87
98
  }
88
99
  }
89
100
 
@@ -38,16 +38,21 @@ class NowPlayingTemplate: NSObject, AutoPlayTemplate {
38
38
  // Set the config ID on the shared singleton so TemplateStore can find it
39
39
  initTemplate(template: CPNowPlayingTemplate.shared, id: config.id)
40
40
 
41
- DispatchQueue.main.async { [weak self] in
42
- guard let self = self else { return }
43
- NowPlayingSessionManager.shared.ensureSessionActive()
44
- self.setupRemoteCommandCenter()
45
- self.updateNowPlayingInfo()
46
- self.isSetupComplete = true
41
+ // Setup remote commands and now playing info synchronously
42
+ // so they're ready before CPNowPlayingTemplate.shared is pushed
43
+ NowPlayingSessionManager.shared.ensureSessionActive()
44
+ setupRemoteCommandCenter()
45
+ updateNowPlayingInfo()
47
46
 
48
- if let image = config.image {
49
- self.loadImageAsync(image: image)
50
- }
47
+ // Set playbackState before push so CarPlay sees an active now-playing session
48
+ if config.isPlaying {
49
+ MPNowPlayingInfoCenter.default().playbackState = .playing
50
+ }
51
+
52
+ isSetupComplete = true
53
+
54
+ if let image = config.image {
55
+ loadImageAsync(image: image)
51
56
  }
52
57
  }
53
58
 
@@ -13,4 +13,10 @@ onInterfaceController:(CPInterfaceController * _Nonnull)interfaceController
13
13
  animated:(BOOL)animated
14
14
  error:(NSError * _Nullable * _Nullable)error;
15
15
 
16
+ + (BOOL)pushTemplate:(CPTemplate * _Nonnull)templateToPush
17
+ onInterfaceController:(CPInterfaceController * _Nonnull)interfaceController
18
+ animated:(BOOL)animated
19
+ completion:(void (^ _Nullable)(BOOL success, NSError * _Nullable error))completion
20
+ error:(NSError * _Nullable * _Nullable)error;
21
+
16
22
  @end
@@ -23,4 +23,26 @@ onInterfaceController:(CPInterfaceController *)interfaceController
23
23
  }
24
24
  }
25
25
 
26
+ + (BOOL)pushTemplate:(CPTemplate *)templateToPush
27
+ onInterfaceController:(CPInterfaceController *)interfaceController
28
+ animated:(BOOL)animated
29
+ completion:(void (^)(BOOL, NSError *))completion
30
+ error:(NSError **)error {
31
+ @try {
32
+ [interfaceController pushTemplate:templateToPush animated:animated completion:completion];
33
+ return YES;
34
+ } @catch (NSException *exception) {
35
+ NSLog(@"[ObjCExceptionCatcher] Caught exception during pushTemplate: %@ — %@", exception.name, exception.reason);
36
+ if (error) {
37
+ *error = [NSError errorWithDomain:@"ObjCExceptionCatcher"
38
+ code:0
39
+ userInfo:@{
40
+ NSLocalizedDescriptionKey: exception.reason ?: @"Unknown Objective-C exception",
41
+ @"ExceptionName": exception.name ?: @"Unknown"
42
+ }];
43
+ }
44
+ return NO;
45
+ }
46
+ }
47
+
26
48
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neoskola/auto-play",
3
- "version": "0.3.15",
3
+ "version": "0.3.17",
4
4
  "description": "Android Auto and Apple CarPlay for react-native",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",