@wwdrew/expo-spotify-sdk 0.4.3 → 0.6.0

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 (81) hide show
  1. package/LICENSE +21 -3
  2. package/README.md +345 -96
  3. package/android/build.gradle +28 -22
  4. package/android/consumer-rules.pro +8 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/java/expo/modules/spotifysdk/ExpoSpotifySDKModule.kt +130 -145
  7. package/android/src/main/java/expo/modules/spotifysdk/SpotifyAuthCoordinator.kt +36 -0
  8. package/android/src/main/java/expo/modules/spotifysdk/SpotifyAuthorizationContract.kt +45 -0
  9. package/android/src/main/java/expo/modules/spotifysdk/SpotifyConfig.kt +80 -0
  10. package/android/src/main/java/expo/modules/spotifysdk/SpotifyErrors.kt +34 -0
  11. package/android/src/main/java/expo/modules/spotifysdk/SpotifyTokenSwapClient.kt +154 -0
  12. package/build/ExpoSpotifySDK.types.d.ts +76 -1
  13. package/build/ExpoSpotifySDK.types.d.ts.map +1 -1
  14. package/build/ExpoSpotifySDK.types.js +12 -1
  15. package/build/ExpoSpotifySDK.types.js.map +1 -1
  16. package/build/ExpoSpotifySDKModule.web.d.ts +7 -3
  17. package/build/ExpoSpotifySDKModule.web.d.ts.map +1 -1
  18. package/build/ExpoSpotifySDKModule.web.js +17 -7
  19. package/build/ExpoSpotifySDKModule.web.js.map +1 -1
  20. package/build/index.d.ts +39 -2
  21. package/build/index.d.ts.map +1 -1
  22. package/build/index.js +117 -4
  23. package/build/index.js.map +1 -1
  24. package/expo-module.config.json +1 -1
  25. package/ios/ExpoSpotifyAppDelegate.swift +14 -0
  26. package/ios/ExpoSpotifyConfiguration.swift +33 -15
  27. package/ios/ExpoSpotifySDK.podspec +2 -4
  28. package/ios/ExpoSpotifySDKModule.swift +96 -26
  29. package/ios/SPTScopeSerializer.swift +40 -39
  30. package/ios/SpotifyAuthCoordinator.swift +133 -0
  31. package/ios/SpotifySDK/SpotifyiOS.xcframework/Info.plist +5 -9
  32. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemote.h +43 -41
  33. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteCommon.h +9 -8
  34. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteConnectivityAPI.h +4 -3
  35. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteContentAPI.h +8 -6
  36. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteContentItem.h +3 -3
  37. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteImageAPI.h +3 -3
  38. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemotePlayerAPI.h +12 -7
  39. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteUserAPI.h +4 -5
  40. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTConfiguration.h +5 -5
  41. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTError.h +7 -9
  42. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTMacros.h +59 -23
  43. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTScope.h +67 -63
  44. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTSession.h +2 -1
  45. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTSessionManager.h +59 -19
  46. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SpotifyAppRemote.h +11 -15
  47. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SpotifyiOS.h +1 -1
  48. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Info.plist +0 -0
  49. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Modules/module.modulemap +0 -1
  50. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/SpotifyiOS +0 -0
  51. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemote.h +43 -41
  52. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteCommon.h +9 -8
  53. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteConnectivityAPI.h +4 -3
  54. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteContentAPI.h +8 -6
  55. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteContentItem.h +3 -3
  56. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteImageAPI.h +3 -3
  57. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemotePlayerAPI.h +12 -7
  58. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteUserAPI.h +4 -5
  59. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTConfiguration.h +5 -5
  60. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTError.h +7 -9
  61. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTMacros.h +59 -23
  62. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTScope.h +67 -63
  63. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTSession.h +2 -1
  64. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTSessionManager.h +59 -19
  65. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SpotifyAppRemote.h +11 -15
  66. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SpotifyiOS.h +1 -1
  67. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Info.plist +0 -0
  68. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Modules/module.modulemap +0 -1
  69. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/SpotifyiOS +0 -0
  70. package/ios/SpotifyTokenRefreshClient.swift +118 -0
  71. package/package.json +12 -11
  72. package/plugin/build/android/withSpotifyAndroidAppBuildGradle.js +15 -10
  73. package/plugin/build/ios/withSpotifyConfigValues.js +12 -7
  74. package/plugin/build/ios/withSpotifyURLScheme.d.ts +1 -1
  75. package/plugin/build/ios/withSpotifyURLScheme.js +9 -8
  76. package/plugin/build/types.d.ts +35 -0
  77. package/plugin/build/types.js +0 -19
  78. package/ios/ExpoSpotifyAuthDelegate.swift +0 -13
  79. package/ios/ExpoSpotifySessionManager+SessionManagerDelegate.swift +0 -16
  80. package/ios/ExpoSpotifySessionManager.swift +0 -90
  81. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/_CodeSignature/CodeResources +0 -454
@@ -1,44 +1,45 @@
1
+ import Foundation
1
2
  import SpotifyiOS
2
3
 
3
- class SPTScopeSerializer {
4
- static let scopeMap: [String: SPTScope] = [
5
- "playlist-read-private": .playlistReadPrivate,
6
- "playlist-read-collaborative": .playlistReadCollaborative,
7
- "playlist-modify-public": .playlistModifyPublic,
8
- "playlist-modify-private": .playlistModifyPrivate,
9
- "user-follow-read": .userFollowRead,
10
- "user-follow-modify": .userFollowModify,
11
- "user-library-read": .userLibraryRead,
12
- "user-library-modify": .userLibraryModify,
13
- "user-read-email": .userReadEmail,
14
- "user-read-private": .userReadPrivate,
15
- "user-top-read": .userTopRead,
16
- "ugc-image-upload": .ugcImageUpload,
17
- "streaming": .streaming,
18
- "app-remote-control": .appRemoteControl,
19
- "user-read-playback-state": .userReadPlaybackState,
20
- "user-modify-playback-state": .userModifyPlaybackState,
21
- "user-read-currently-playing": .userReadCurrentlyPlaying,
22
- "user-read-recently-played": .userReadRecentlyPlayed,
23
- ]
24
-
25
- static func serializeScopes(_ scopes: SPTScope) -> [String] {
26
- var serializedScopes = [String]()
27
- for (scopeString, scopeValue) in scopeMap {
28
- if scopes.contains(scopeValue) {
29
- serializedScopes.append(scopeString)
30
- }
31
- }
32
- return serializedScopes
4
+ enum SPTScopeSerializer {
5
+ /// Single source of truth for the string ↔ SPTScope mapping. Order is
6
+ /// preserved on round-trip via `serialize` (sorted alphabetically) so output
7
+ /// is deterministic.
8
+ static let scopeMap: [(String, SPTScope)] = [
9
+ ("app-remote-control", .appRemoteControl),
10
+ ("playlist-modify-private", .playlistModifyPrivate),
11
+ ("playlist-modify-public", .playlistModifyPublic),
12
+ ("playlist-read-collaborative", .playlistReadCollaborative),
13
+ ("playlist-read-private", .playlistReadPrivate),
14
+ ("streaming", .streaming),
15
+ ("ugc-image-upload", .ugcImageUpload),
16
+ ("user-follow-modify", .userFollowModify),
17
+ ("user-follow-read", .userFollowRead),
18
+ ("user-library-modify", .userLibraryModify),
19
+ ("user-library-read", .userLibraryRead),
20
+ ("user-modify-playback-state", .userModifyPlaybackState),
21
+ ("user-read-currently-playing", .userReadCurrentlyPlaying),
22
+ ("user-read-email", .userReadEmail),
23
+ ("user-read-playback-state", .userReadPlaybackState),
24
+ ("user-read-private", .userReadPrivate),
25
+ ("user-read-recently-played", .userReadRecentlyPlayed),
26
+ ("user-top-read", .userTopRead),
27
+ ]
28
+
29
+ static func serialize(_ scopes: SPTScope) -> [String] {
30
+ scopeMap.compactMap { (string, value) in
31
+ scopes.contains(value) ? string : nil
33
32
  }
34
-
35
- static func deserializeScopes(_ scopes: [String]) -> SPTScope {
36
- var deserializedScopes: SPTScope = []
37
- for scopeString in scopes {
38
- if let scopeValue = scopeMap[scopeString] {
39
- deserializedScopes.insert(scopeValue)
40
- }
41
- }
42
- return deserializedScopes
33
+ }
34
+
35
+ static func deserialize(_ scopes: [String]) -> SPTScope {
36
+ var result: SPTScope = []
37
+ let lookup = Dictionary(uniqueKeysWithValues: scopeMap)
38
+ for string in scopes {
39
+ if let value = lookup[string] {
40
+ result.insert(value)
41
+ }
43
42
  }
43
+ return result
44
+ }
44
45
  }
@@ -0,0 +1,133 @@
1
+ import Foundation
2
+ import SpotifyiOS
3
+
4
+ /// Public, structured errors thrown by the coordinator. Each case carries the
5
+ /// JS-facing error code in `code`, mirroring the Android `CodedException`
6
+ /// taxonomy.
7
+ enum SpotifyError: Error {
8
+ case invalidConfiguration(String)
9
+ case authInProgress
10
+ case userCancelled
11
+ case spotifyNotInstalled
12
+ case underlying(Error)
13
+
14
+ var code: String {
15
+ switch self {
16
+ case .invalidConfiguration: return "INVALID_CONFIG"
17
+ case .authInProgress: return "AUTH_IN_PROGRESS"
18
+ case .userCancelled: return "USER_CANCELLED"
19
+ case .spotifyNotInstalled: return "SPOTIFY_NOT_INSTALLED"
20
+ case .underlying: return "UNKNOWN"
21
+ }
22
+ }
23
+
24
+ var message: String {
25
+ switch self {
26
+ case .invalidConfiguration(let m): return m
27
+ case .authInProgress: return "Another authentication request is already in progress"
28
+ case .userCancelled: return "Authentication was cancelled by the user"
29
+ case .spotifyNotInstalled: return "The Spotify app is not installed on this device"
30
+ case .underlying(let err): return err.localizedDescription
31
+ }
32
+ }
33
+ }
34
+
35
+ /// `actor` ensures `pending` is mutated only on the actor's serial executor;
36
+ /// no manual locks needed.
37
+ actor SpotifyAuthCoordinator {
38
+ static let shared: SpotifyAuthCoordinator? = SpotifyAuthCoordinator.create()
39
+
40
+ private let sptConfiguration: SPTConfiguration
41
+ private let sessionManager: SPTSessionManager
42
+ private let bridge: SpotifySessionDelegateBridge
43
+ private var pending: CheckedContinuation<SPTSession, Error>?
44
+
45
+ private init(sptConfiguration: SPTConfiguration, sessionManager: SPTSessionManager, bridge: SpotifySessionDelegateBridge) {
46
+ self.sptConfiguration = sptConfiguration
47
+ self.sessionManager = sessionManager
48
+ self.bridge = bridge
49
+ bridge.coordinator = self
50
+ }
51
+
52
+ private static func create() -> SpotifyAuthCoordinator? {
53
+ guard
54
+ let configuration = ExpoSpotifyConfiguration.fromInfoPlist(),
55
+ let sptConfig = configuration.sptConfiguration
56
+ else {
57
+ NSLog("[ExpoSpotifySDK] Missing or invalid `ExpoSpotifySDK` Info.plist entry")
58
+ return nil
59
+ }
60
+ let bridge = SpotifySessionDelegateBridge()
61
+ let manager = SPTSessionManager(configuration: sptConfig, delegate: bridge)
62
+ return SpotifyAuthCoordinator(sptConfiguration: sptConfig, sessionManager: manager, bridge: bridge)
63
+ }
64
+
65
+ /// Synchronous getter used by the module's `Function("isAvailable")`. Safe
66
+ /// to call from any thread because the underlying SDK property is read-only
67
+ /// state derived from the installed-apps query.
68
+ nonisolated func isSpotifyAppInstalled() -> Bool {
69
+ sessionManager.isSpotifyAppInstalled
70
+ }
71
+
72
+ /// Synchronous URL-handler dispatcher used by the AppDelegate / SceneDelegate
73
+ /// subscribers to forward redirects to the SPTSessionManager.
74
+ nonisolated func handleOpenURL(_ url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
75
+ sessionManager.application(UIApplication.shared, open: url, options: options)
76
+ }
77
+
78
+ func authenticate(
79
+ scopes: SPTScope,
80
+ tokenSwapURL: URL?,
81
+ tokenRefreshURL: URL?
82
+ ) async throws -> SPTSession {
83
+ guard pending == nil else { throw SpotifyError.authInProgress }
84
+
85
+ // SPTConfiguration is a reference type shared with the session manager, so
86
+ // mutating it here takes effect for the upcoming initiateSession call.
87
+ sptConfiguration.tokenSwapURL = tokenSwapURL
88
+ sptConfiguration.tokenRefreshURL = tokenRefreshURL
89
+
90
+ return try await withCheckedThrowingContinuation { (cont: CheckedContinuation<SPTSession, Error>) in
91
+ self.pending = cont
92
+ Task { @MainActor in
93
+ self.sessionManager.initiateSession(with: scopes, options: .default, campaign: nil)
94
+ }
95
+ }
96
+ }
97
+
98
+ func deliver(_ result: Result<SPTSession, Error>) {
99
+ let cont = pending
100
+ pending = nil
101
+ cont?.resume(with: result)
102
+ }
103
+ }
104
+
105
+ /// `SPTSessionManagerDelegate` requires NSObject conformance, which an actor
106
+ /// can't satisfy directly. The bridge is a tiny NSObject that hops the call
107
+ /// onto the actor's executor.
108
+ final class SpotifySessionDelegateBridge: NSObject, SPTSessionManagerDelegate {
109
+ weak var coordinator: SpotifyAuthCoordinator?
110
+
111
+ func sessionManager(manager _: SPTSessionManager, didInitiate session: SPTSession) {
112
+ Task { await coordinator?.deliver(.success(session)) }
113
+ }
114
+
115
+ func sessionManager(manager _: SPTSessionManager, didFailWith error: Error) {
116
+ let mapped: Error = mapSDKError(error)
117
+ Task { await coordinator?.deliver(.failure(mapped)) }
118
+ }
119
+
120
+ func sessionManager(manager _: SPTSessionManager, didRenew session: SPTSession) {
121
+ Task { await coordinator?.deliver(.success(session)) }
122
+ }
123
+
124
+ /// Translate a few well-known SDK error shapes into our taxonomy.
125
+ private func mapSDKError(_ error: Error) -> Error {
126
+ let nsError = error as NSError
127
+ let description = nsError.localizedDescription.lowercased()
128
+ if description.contains("cancel") {
129
+ return SpotifyError.userCancelled
130
+ }
131
+ return SpotifyError.underlying(error)
132
+ }
133
+ }
@@ -5,35 +5,31 @@
5
5
  <key>AvailableLibraries</key>
6
6
  <array>
7
7
  <dict>
8
- <key>BinaryPath</key>
9
- <string>SpotifyiOS.framework/SpotifyiOS</string>
10
8
  <key>LibraryIdentifier</key>
11
- <string>ios-arm64_x86_64-simulator</string>
9
+ <string>ios-arm64</string>
12
10
  <key>LibraryPath</key>
13
11
  <string>SpotifyiOS.framework</string>
14
12
  <key>SupportedArchitectures</key>
15
13
  <array>
16
14
  <string>arm64</string>
17
- <string>x86_64</string>
18
15
  </array>
19
16
  <key>SupportedPlatform</key>
20
17
  <string>ios</string>
21
- <key>SupportedPlatformVariant</key>
22
- <string>simulator</string>
23
18
  </dict>
24
19
  <dict>
25
- <key>BinaryPath</key>
26
- <string>SpotifyiOS.framework/SpotifyiOS</string>
27
20
  <key>LibraryIdentifier</key>
28
- <string>ios-arm64</string>
21
+ <string>ios-arm64_x86_64-simulator</string>
29
22
  <key>LibraryPath</key>
30
23
  <string>SpotifyiOS.framework</string>
31
24
  <key>SupportedArchitectures</key>
32
25
  <array>
33
26
  <string>arm64</string>
27
+ <string>x86_64</string>
34
28
  </array>
35
29
  <key>SupportedPlatform</key>
36
30
  <string>ios</string>
31
+ <key>SupportedPlatformVariant</key>
32
+ <string>simulator</string>
37
33
  </dict>
38
34
  </array>
39
35
  <key>CFBundlePackageType</key>
@@ -12,18 +12,18 @@
12
12
 
13
13
  NS_ASSUME_NONNULL_BEGIN
14
14
 
15
- extern NSString * const SPTAppRemoteAccessTokenKey;
16
- extern NSString * const SPTAppRemoteErrorKey;
17
- extern NSString * const SPTAppRemoteErrorDescriptionKey;
15
+ extern NSString *const SPTAppRemoteAccessTokenKey;
16
+ extern NSString *const SPTAppRemoteErrorKey;
17
+ extern NSString *const SPTAppRemoteErrorDescriptionKey;
18
18
 
19
19
  /// The severity of log messages that the App Remote should log to console.
20
20
  typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
21
21
  /// Do not log at all.
22
- SPTAppRemoteLogLevelNone = 0,
22
+ SPTAppRemoteLogLevelNone = 0,
23
23
  /// Log debug, info and error messages.
24
24
  SPTAppRemoteLogLevelDebug = 1,
25
25
  /// Log info and error messages.
26
- SPTAppRemoteLogLevelInfo = 2,
26
+ SPTAppRemoteLogLevelInfo = 2,
27
27
  /// Log only error messages.
28
28
  SPTAppRemoteLogLevelError = 3,
29
29
  };
@@ -63,7 +63,8 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
63
63
  @end
64
64
 
65
65
  /**
66
- * The `SPTAppRemote` is the main entry point for interacting with the Spotify app using the Spotify App Remote for iOS.
66
+ * The `SPTAppRemote` is the main entry point for interacting with the Spotify app using the Spotify App Remote for
67
+ * iOS.
67
68
  */
68
69
  @interface SPTAppRemote : NSObject
69
70
 
@@ -83,7 +84,8 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
83
84
  * Designated Initializer for a new App Remote instance
84
85
  *
85
86
  * @param configuration The `SPTConfiguration` to use for client-id's and redirect URLs
86
- * @param connectionParameters `SPTAppRemoteConnectionParams` for custom image sizes and types, and to hold the accessToken
87
+ * @param connectionParameters `SPTAppRemoteConnectionParams` for custom image sizes and types, and to hold the
88
+ * accessToken
87
89
  * @param logLevel The lowest severity to log to console.
88
90
  *
89
91
  * @return A fresh new App Remote, ready to connect.
@@ -93,15 +95,6 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
93
95
  logLevel:(SPTAppRemoteLogLevel)logLevel NS_DESIGNATED_INITIALIZER;
94
96
  #pragma mark Class Methods
95
97
 
96
- /**
97
- * Checks if the Spotify app is active on the user's device. You can use this to determine if maybe you should prompt
98
- * the user to connect to Spotify (because you know they are already using Spotify if it is active). The Spotify app
99
- * will be considered active if music is playing or the app is active in the background.
100
- *
101
- * @param completion Completion block for determining the result of the check. YES if Spotify is active, othewise NO.
102
- */
103
- + (void)checkIfSpotifyAppIsActive:(void (^)(BOOL active))completion;
104
-
105
98
  /**
106
99
  * Determine the current version of the Spotify App Remote
107
100
  *
@@ -110,9 +103,11 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
110
103
  + (NSString *)appRemoteVersion;
111
104
 
112
105
  /**
113
- * The Spotify app iTunes item identifier for use with `SKStoreProductViewController` for installing Spotify from the App Store.
106
+ * The Spotify app iTunes item identifier for use with `SKStoreProductViewController` for installing Spotify from the
107
+ * App Store.
114
108
  *
115
- * @return An `NSNumber` representing the Spotify iTunes item identifier to be used for the `SKStoreProductParameterITunesItemIdentifier` key
109
+ * @return An `NSNumber` representing the Spotify iTunes item identifier to be used for the
110
+ * `SKStoreProductParameterITunesItemIdentifier` key
116
111
  */
117
112
  + (NSNumber *)spotifyItunesItemIdentifier;
118
113
 
@@ -149,7 +144,8 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
149
144
  *
150
145
  * @discussion If the Spotify app is not running you will need to use authorizeAndPlayURI: to wake it up.
151
146
  *
152
- * @discussion If `authorizeAndPlayURI` was used without a given session identifier, `connect` should be used instead of this method.
147
+ * @discussion If `authorizeAndPlayURI` was used without a given session identifier, `connect` should be used instead of
148
+ * this method.
153
149
  *
154
150
  * @param sessionIdentifier The unique session identifier which was used when calling
155
151
  * `authorizeAndPlayURI:asRadio:additionalScopes:sessionIdentifier:`
@@ -166,62 +162,68 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
166
162
  * The passed URI will start playing unless Spotify is already playing.
167
163
  *
168
164
  * @param URI The URI to play. Use a blank string to attempt to play the user's last song
169
- * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
165
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise
166
+ * `NO`.
170
167
  *
171
168
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
172
169
  * the Spotify app is installed and can attempt to handle the authorization request.
173
170
  */
174
- - (void)authorizeAndPlayURI:(NSString *)URI completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
171
+ - (void)authorizeAndPlayURI:(NSString *)URI completionHandler:(void (^__nullable)(BOOL success))completionHandler;
175
172
 
176
173
  /**
177
174
  * Open Spotify app to obtain access token and start playback.
178
175
  *
179
176
  * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
180
177
  * @param asRadio `YES` to start radio for the given URI.
181
- * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
178
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise
179
+ * `NO`.
182
180
  *
183
181
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
184
182
  * the Spotify app is installed and can attempt to handle the authorization request.
185
183
  */
186
184
  - (void)authorizeAndPlayURI:(NSString *)playURI
187
185
  asRadio:(BOOL)asRadio
188
- completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
186
+ completionHandler:(void (^__nullable)(BOOL success))completionHandler;
189
187
 
190
188
  /**
191
- * Open Spotify app to obtain access token and start playback.
192
- *
193
- * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
194
- * @param asRadio `YES` to start radio for the given URI.
195
- * @param additionalScopes An array of scopes in addition to `app-remote-control`. Can be nil if you only need `app-remote-control`
196
- * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
197
- *
198
- * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
199
- * the Spotify app is installed and can attempt to handle the authorization request.
200
- */
189
+ * Open Spotify app to obtain access token and start playback.
190
+ *
191
+ * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
192
+ * @param asRadio `YES` to start radio for the given URI.
193
+ * @param additionalScopes An array of scopes in addition to `app-remote-control`. Can be nil if you only need
194
+ * `app-remote-control`
195
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise
196
+ * `NO`.
197
+ *
198
+ * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
199
+ * the Spotify app is installed and can attempt to handle the authorization request.
200
+ */
201
201
  - (void)authorizeAndPlayURI:(NSString *)playURI
202
202
  asRadio:(BOOL)asRadio
203
203
  additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
204
- completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
204
+ completionHandler:(void (^__nullable)(BOOL success))completionHandler;
205
205
 
206
206
  /**
207
207
  * Open Spotify app to obtain access token and start playback.
208
208
  *
209
209
  * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
210
210
  * @param asRadio `YES` to start radio for the given URI.
211
- * @param additionalScopes An array of scopes in addition to `app-remote-control`. Can be nil if you only need `app-remote-control`
212
- * @param sessionIdentifier An optional unique identifier for this specific session, which is used for analytics purposes. Every new attempt to
213
- * connect to the Spotify app should have a new identifier, but the identifier used here should then be reused for the accompanied call to
214
- * `connectWithSessionIdentifier:`.
215
- * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
211
+ * @param additionalScopes An array of scopes in addition to `app-remote-control`. Can be nil if you only need
212
+ * `app-remote-control`
213
+ * @param sessionIdentifier An optional unique identifier for this specific session, which is used for analytics
214
+ * purposes. Every new attempt to connect to the Spotify app should have a new identifier, but the identifier used here
215
+ * should then be reused for the accompanied call to `connectWithSessionIdentifier:`.
216
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise
217
+ * `NO`.
216
218
  *
217
219
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
218
220
  * the Spotify app is installed and can attempt to handle the authorization request.
219
- */
221
+ */
220
222
  - (void)authorizeAndPlayURI:(NSString *)playURI
221
223
  asRadio:(BOOL)asRadio
222
224
  additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
223
225
  sessionIdentifier:(nullable NSUUID *)sessionIdentifier
224
- completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
226
+ completionHandler:(void (^__nullable)(BOOL success))completionHandler;
225
227
  /**
226
228
  * Parse out an access token or error description from a url passed to application:openURL:options:
227
229
  *
@@ -1,3 +1,5 @@
1
+ #import <Foundation/Foundation.h>
2
+
1
3
  /**
2
4
  * Common header definitions
3
5
  */
@@ -5,23 +7,23 @@
5
7
  NS_ASSUME_NONNULL_BEGIN
6
8
 
7
9
  /// The error domain for user facing errors that occur in the App Remote.
8
- extern NSString * const SPTAppRemoteErrorDomain;
10
+ extern NSString *const SPTAppRemoteErrorDomain;
9
11
 
10
12
  /// The error codes in the `SPTAppRemoteErrorDomain` domain.
11
13
  typedef NS_ENUM(NSInteger, SPTAppRemoteErrorCode) {
12
14
  /// An unknown error.
13
- SPTAppRemoteUnknownError = -1,
15
+ SPTAppRemoteUnknownError = -1,
14
16
 
15
17
  /// The background wakeup of the Spotify app failed.
16
- SPTAppRemoteBackgroundWakeupFailedError = -1000,
18
+ SPTAppRemoteBackgroundWakeupFailedError = -1000,
17
19
  /// The connection attempt to the Spotify app failed.
18
20
  SPTAppRemoteConnectionAttemptFailedError = -1001,
19
21
  /// The conncetion to the Spotify app was terminated.
20
- SPTAppRemoteConnectionTerminatedError = -1002,
22
+ SPTAppRemoteConnectionTerminatedError = -1002,
21
23
  /// The arguments supplied are invalid.
22
- SPTAppRemoteInvalidArgumentsError = -2000,
24
+ SPTAppRemoteInvalidArgumentsError = -2000,
23
25
  /// The request has failed for some reason.
24
- SPTAppRemoteRequestFailedError = -2001,
26
+ SPTAppRemoteRequestFailedError = -2001,
25
27
  };
26
28
 
27
29
  /**
@@ -30,7 +32,6 @@ typedef NS_ENUM(NSInteger, SPTAppRemoteErrorCode) {
30
32
  * @param result The result of the operation, or `nil` if the operation failed.
31
33
  * @param error An error object, or `nil` if the operation was a success.
32
34
  */
33
- typedef void (^SPTAppRemoteCallback)(id _Nullable result, NSError * _Nullable error);
35
+ typedef void (^SPTAppRemoteCallback)(id _Nullable result, NSError *_Nullable error);
34
36
 
35
37
  NS_ASSUME_NONNULL_END
36
-
@@ -1,5 +1,4 @@
1
1
  #import <Foundation/Foundation.h>
2
-
3
2
  #import "SPTAppRemoteCommon.h"
4
3
 
5
4
  @protocol SPTAppRemoteConnectivityAPI;
@@ -8,7 +7,8 @@
8
7
  NS_ASSUME_NONNULL_BEGIN
9
8
 
10
9
  /**
11
- * The `SPTAppRemoteConnectivityAPIDelegate` gets notified whenever the connectivity API receives new data from subscription events.
10
+ * The `SPTAppRemoteConnectivityAPIDelegate` gets notified whenever the connectivity API receives new data from
11
+ * subscription events.
12
12
  */
13
13
  @protocol SPTAppRemoteConnectivityAPIDelegate <NSObject>
14
14
 
@@ -18,7 +18,8 @@ NS_ASSUME_NONNULL_BEGIN
18
18
  * @param connectivityAPI The API that received updates.
19
19
  * @param connectivityState The new connectivity state received.
20
20
  */
21
- - (void)connectivityAPI:(id<SPTAppRemoteConnectivityAPI>)connectivityAPI didReceiveNewConnectivityState:(id<SPTAppRemoteConnectivityState>)connectivityState;
21
+ - (void)connectivityAPI:(id<SPTAppRemoteConnectivityAPI>)connectivityAPI
22
+ didReceiveNewConnectivityState:(id<SPTAppRemoteConnectivityState>)connectivityState;
22
23
 
23
24
  @end
24
25
 
@@ -4,12 +4,12 @@
4
4
  NS_ASSUME_NONNULL_BEGIN
5
5
 
6
6
  /// A type representing different lists of content.
7
- typedef NSString * const SPTAppRemoteContentType;
7
+ typedef NSString *const SPTAppRemoteContentType;
8
8
 
9
- extern NSString * const SPTAppRemoteContentTypeDefault;
10
- extern NSString * const SPTAppRemoteContentTypeNavigation;
11
- extern NSString * const SPTAppRemoteContentTypeFitness;
12
- extern NSString * const SPTAppRemoteContentTypeGaming;
9
+ extern NSString *const SPTAppRemoteContentTypeDefault;
10
+ extern NSString *const SPTAppRemoteContentTypeNavigation;
11
+ extern NSString *const SPTAppRemoteContentTypeFitness;
12
+ extern NSString *const SPTAppRemoteContentTypeGaming;
13
13
 
14
14
  @protocol SPTAppRemoteContentItem;
15
15
 
@@ -31,7 +31,9 @@ extern NSString * const SPTAppRemoteContentTypeGaming;
31
31
  * @param callback The callback to be called once the request is completed.
32
32
  */
33
33
  - (void)fetchRootContentItemsForType:(SPTAppRemoteContentType)contentType
34
- callback:(nullable SPTAppRemoteCallback)callback DEPRECATED_MSG_ATTRIBUTE("Deprecated. Use fetchRecommendedContentItemsForType:flattenContainers:callback: instead.");
34
+ callback:(nullable SPTAppRemoteCallback)callback
35
+ DEPRECATED_MSG_ATTRIBUTE(
36
+ "Deprecated. Use fetchRecommendedContentItemsForType:flattenContainers:callback: instead.");
35
37
 
36
38
  /**
37
39
  * Fetches the children items for the provided content item.
@@ -4,8 +4,8 @@
4
4
  NS_ASSUME_NONNULL_BEGIN
5
5
 
6
6
  /**
7
- * The `SPTAppRemoteContentItem` protocol represents a track or a collection of tracks. Use the `isContainer` instance method
8
- * to determine if the content item is a collection of tracks for which to grab children from.
7
+ * The `SPTAppRemoteContentItem` protocol represents a track or a collection of tracks. Use the `isContainer` instance
8
+ * method to determine if the content item is a collection of tracks for which to grab children from.
9
9
  */
10
10
  @protocol SPTAppRemoteContentItem <NSObject, SPTAppRemoteImageRepresentable>
11
11
 
@@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
33
33
  /// Returns `YES` if the item is expected to contain children, otherwise `NO`.
34
34
  @property (nonatomic, assign, readonly, getter=isContainer) BOOL container;
35
35
 
36
- /// Returns `YES` if the item is pinned in Your Library, otherwise `NO`.
36
+ /// Returns `YES` if the item is pinned in Your Library, otherwise `NO`.
37
37
  @property (nonatomic, assign, readonly, getter=isPinned) BOOL pinnned;
38
38
 
39
39
  /**
@@ -1,5 +1,3 @@
1
- #import <UIKit/UIKit.h>
2
-
3
1
  #import "SPTAppRemoteCommon.h"
4
2
  #import "SPTAppRemoteImageRepresentable.h"
5
3
 
@@ -18,7 +16,9 @@ NS_ASSUME_NONNULL_BEGIN
18
16
  * @param callback On success `result` will be an instance of `UIImage`
19
17
  * On error `result` will be nil and error set
20
18
  */
21
- - (void)fetchImageForItem:(id<SPTAppRemoteImageRepresentable>)imageRepresentable withSize:(CGSize)imageSize callback:(nullable SPTAppRemoteCallback)callback;
19
+ - (void)fetchImageForItem:(id<SPTAppRemoteImageRepresentable>)imageRepresentable
20
+ withSize:(CGSize)imageSize
21
+ callback:(nullable SPTAppRemoteCallback)callback;
22
22
 
23
23
  @end
24
24
 
@@ -1,14 +1,15 @@
1
1
  #import <Foundation/Foundation.h>
2
-
3
2
  #import "SPTAppRemoteCommon.h"
4
3
  #import "SPTAppRemotePlaybackOptions.h"
5
4
 
6
- @protocol SPTAppRemotePlayerState, SPTAppRemoteContentItem, SPTAppRemotePodcastPlaybackSpeed;
5
+ @protocol SPTAppRemotePlayerState
6
+ , SPTAppRemoteContentItem, SPTAppRemotePodcastPlaybackSpeed;
7
7
 
8
8
  NS_ASSUME_NONNULL_BEGIN
9
9
 
10
10
  /**
11
- * The `SPTAppRemotePlayerStateDelegate` is used to get notifications from the Spotify app when the player state is changed.
11
+ * The `SPTAppRemotePlayerStateDelegate` is used to get notifications from the Spotify app when the player state is
12
+ * changed.
12
13
  */
13
14
  @protocol SPTAppRemotePlayerStateDelegate <NSObject>
14
15
 
@@ -84,7 +85,9 @@ NS_ASSUME_NONNULL_BEGIN
84
85
  * @param callback On success `result` will be `YES`.
85
86
  * On error `result` will be `nil` and error set
86
87
  */
87
- - (void)playItem:(id<SPTAppRemoteContentItem>)contentItem skipToTrackIndex:(NSInteger) index callback:(nullable SPTAppRemoteCallback)callback;
88
+ - (void)playItem:(id<SPTAppRemoteContentItem>)contentItem
89
+ skipToTrackIndex:(NSInteger)index
90
+ callback:(nullable SPTAppRemoteCallback)callback;
88
91
 
89
92
  /**
90
93
  * Asks the Spotify player to resume playback.
@@ -175,7 +178,8 @@ NS_ASSUME_NONNULL_BEGIN
175
178
  * @param callback On success `result` will be `YES`.
176
179
  * On error `result` will be `nil` and `error` will be set.
177
180
  */
178
- - (void)setRepeatMode:(SPTAppRemotePlaybackOptionsRepeatMode)repeatMode callback:(nullable SPTAppRemoteCallback)callback;
181
+ - (void)setRepeatMode:(SPTAppRemotePlaybackOptionsRepeatMode)repeatMode
182
+ callback:(nullable SPTAppRemoteCallback)callback;
179
183
 
180
184
  #pragma mark Player State
181
185
 
@@ -213,7 +217,7 @@ NS_ASSUME_NONNULL_BEGIN
213
217
  * @param callback On success `result` will be `YES`
214
218
  * On error `result` will be `nil` and error set
215
219
  */
216
- - (void)enqueueTrackUri:(NSString*)trackUri callback:(nullable SPTAppRemoteCallback)callback;
220
+ - (void)enqueueTrackUri:(NSString *)trackUri callback:(nullable SPTAppRemoteCallback)callback;
217
221
 
218
222
  /**
219
223
  * Asks the Spotify player for available podcast playback speeds
@@ -247,7 +251,8 @@ NS_ASSUME_NONNULL_BEGIN
247
251
  * @param callback On success `result` will be `YES`.
248
252
  * On error `result` will be `nil` and `error` set
249
253
  */
250
- - (void)setPodcastPlaybackSpeed:(nonnull id<SPTAppRemotePodcastPlaybackSpeed>)speed callback:(nullable SPTAppRemoteCallback)callback;
254
+ - (void)setPodcastPlaybackSpeed:(nonnull id<SPTAppRemotePodcastPlaybackSpeed>)speed
255
+ callback:(nullable SPTAppRemoteCallback)callback;
251
256
 
252
257
  /**
253
258
  * Asks the Spotify player for the current crossfade state.