@neoskola/auto-play 0.3.17 → 0.3.18

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.
@@ -7,6 +7,11 @@
7
7
 
8
8
  import CarPlay
9
9
 
10
+ private struct NowPlayingPushResult {
11
+ let success: Bool
12
+ let errorDescription: String?
13
+ }
14
+
10
15
  @MainActor
11
16
  class AutoPlayInterfaceController: NSObject, CPInterfaceControllerDelegate {
12
17
  let interfaceController: CPInterfaceController
@@ -61,11 +66,28 @@ class AutoPlayInterfaceController: NSObject, CPInterfaceControllerDelegate {
61
66
  return true
62
67
  }
63
68
 
64
- let success = await pushNowPlayingTemplateSafely(animated: animated)
65
- if !success {
66
- throw AutoPlayError.pushFailed("CPNowPlayingTemplate push failed")
69
+ let firstAttempt = await pushNowPlayingTemplateSafely(animated: animated)
70
+ if firstAttempt.success || interfaceController.topTemplate is CPNowPlayingTemplate {
71
+ return true
67
72
  }
68
- return true
73
+
74
+ // CarPlay can reject pushes while handling list selection transitions.
75
+ // Retry once after a short delay to avoid transient failures.
76
+ try? await Task.sleep(nanoseconds: 250_000_000)
77
+ let secondAttempt = await pushNowPlayingTemplateSafely(animated: animated)
78
+ if secondAttempt.success || interfaceController.topTemplate is CPNowPlayingTemplate {
79
+ return true
80
+ }
81
+
82
+ let reason = secondAttempt.errorDescription
83
+ ?? firstAttempt.errorDescription
84
+ ?? "unknown reason"
85
+ let topTemplateDescription = interfaceController.topTemplate.map {
86
+ String(describing: type(of: $0))
87
+ } ?? "nil"
88
+ throw AutoPlayError.pushFailed(
89
+ "CPNowPlayingTemplate push failed (\(reason)). top=\(topTemplateDescription) stackCount=\(interfaceController.templates.count)"
90
+ )
69
91
  }
70
92
 
71
93
  return try await interfaceController.pushTemplate(
@@ -76,7 +98,7 @@ class AutoPlayInterfaceController: NSObject, CPInterfaceControllerDelegate {
76
98
 
77
99
  /// Pushes CPNowPlayingTemplate using ObjC @try/@catch to prevent crash from NSException.
78
100
  /// Uses a completion handler to confirm the push actually succeeded.
79
- private func pushNowPlayingTemplateSafely(animated: Bool) async -> Bool {
101
+ private func pushNowPlayingTemplateSafely(animated: Bool) async -> NowPlayingPushResult {
80
102
  return await withCheckedContinuation { continuation in
81
103
  do {
82
104
  try ObjCExceptionCatcher.push(
@@ -88,12 +110,22 @@ class AutoPlayInterfaceController: NSObject, CPInterfaceControllerDelegate {
88
110
  print("[AutoPlay] CPNowPlayingTemplate push completion error: \(error.localizedDescription)")
89
111
  }
90
112
  print("[AutoPlay] CPNowPlayingTemplate push completion: success=\(success)")
91
- continuation.resume(returning: success)
113
+ continuation.resume(
114
+ returning: NowPlayingPushResult(
115
+ success: success,
116
+ errorDescription: error?.localizedDescription
117
+ )
118
+ )
92
119
  }
93
120
  )
94
121
  } catch {
95
122
  print("[AutoPlay] CPNowPlayingTemplate push threw ObjC exception: \(error.localizedDescription)")
96
- continuation.resume(returning: false)
123
+ continuation.resume(
124
+ returning: NowPlayingPushResult(
125
+ success: false,
126
+ errorDescription: error.localizedDescription
127
+ )
128
+ )
97
129
  }
98
130
  }
99
131
  }
@@ -307,10 +307,13 @@ class NowPlayingTemplate: NSObject, AutoPlayTemplate {
307
307
  nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
308
308
  }
309
309
 
310
+ // Keep playback metadata populated even before duration is known.
311
+ // This helps CarPlay recognize an active now-playing session.
312
+ nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentElapsedTime
313
+ nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = config.isPlaying ? 1.0 : 0.0
314
+
310
315
  if currentDuration > 0 {
311
316
  nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = currentDuration
312
- nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentElapsedTime
313
- nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = config.isPlaying ? 1.0 : 0.0
314
317
  }
315
318
 
316
319
  MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neoskola/auto-play",
3
- "version": "0.3.17",
3
+ "version": "0.3.18",
4
4
  "description": "Android Auto and Apple CarPlay for react-native",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",