### Configure Initial Music Playback URI Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Set the playURI to either resume the last track or start a specific Spotify URI. ```swift self.configuration.playURI = "" ``` ```swift self.configuration.playURI = "spotify:track:20I6sIOMTCkB6w7ryavxtO" ``` -------------------------------- ### Trigger Spotify App Store Install via Branch Source: https://developer.spotify.com/documentation/ios/tutorials/content-linking Direct users to the Spotify App Store page for installation. This uses a Branch tracker URL, optionally including a canonical URL for deferred deep linking. ```objective-c NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; NSString *canonicalURL = @"https://open.spotify.com/album/0sNOF9WDwhWunNAHPD3Baj"; NSString *branchLink = [NSString stringWithFormat:@"https://spotify.link/content_linking?~campaign=%@&$canonical_url=%@", bundleId, canonicalURL]; NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:branchLink]]; [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { }] resume]; ``` -------------------------------- ### Setup Token Swap and Refresh Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Configure the session manager with token swap and refresh URLs to securely obtain access tokens. ```swift lazy var sessionManager: SPTSessionManager = { if let tokenSwapURL = URL(string: "https://[my token swap app domain]/api/token"), let tokenRefreshURL = URL(string: "https://[my token swap app domain]/api/refresh_token") { self.configuration.tokenSwapURL = tokenSwapURL self.configuration.tokenRefreshURL = tokenRefreshURL self.configuration.playURI = "" } let manager = SPTSessionManager(configuration: self.configuration, delegate: self) return manager }() ``` -------------------------------- ### Configure Info.plist: Add spotify to LSApplicationQueriesSchemes Source: https://developer.spotify.com/documentation/ios/getting-started Add the 'spotify' scheme to `LSApplicationQueriesSchemes` in your `Info.plist` to enable checking if the Spotify main application is installed. ```xml LSApplicationQueriesSchemes spotify ``` -------------------------------- ### Detect Spotify Installation Source: https://developer.spotify.com/documentation/ios/tutorials/content-linking Check if the Spotify app is installed on the device by attempting to open the 'spotify:' URL scheme. ```objective-c [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"spotify:"]] ``` -------------------------------- ### Instantiate SPTConfiguration Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Define client credentials and initialize the SDK configuration at the class level. ```swift let SpotifyClientID = "[your spotify client id here]" let SpotifyRedirectURL = URL(string: "spotify-ios-quick-start://spotify-login-callback")! lazy var configuration = SPTConfiguration( clientID: SpotifyClientID, redirectURL: SpotifyRedirectURL ) ``` -------------------------------- ### Instantiate SPTConfiguration Source: https://developer.spotify.com/documentation/ios/getting-started Define your Client ID and Redirect URI to initialize the SDK configuration. ```swift let SpotifyClientID = "[your spotify client id here]" let SpotifyRedirectURL = URL(string: "spotify-ios-quick-start://spotify-login-callback")! lazy var configuration = SPTConfiguration( clientID: SpotifyClientID, redirectURL: SpotifyRedirectURL ) ``` -------------------------------- ### Configure Initial Music Playback URI Source: https://developer.spotify.com/documentation/ios/getting-started Set the playURI property to either an empty string to resume playback or a specific Spotify track URI. ```swift self.playURI = "" ``` ```swift self.playURI = "spotify:track:20I6sIOMTCkB6w7ryavxtO" ``` -------------------------------- ### Configure Info.plist: Add URI Scheme in CFBundleURLTypes Source: https://developer.spotify.com/documentation/ios/getting-started Set up a URI scheme in `Info.plist` by adding your Bundle ID to `CFBundleURLName` and your Redirect URI protocol to `CFBundleURLSchemes` to allow Spotify to send users back to your application. ```xml CFBundleURLTypes CFBundleURLName com.spotify.iOS-SDK-Quick-Start CFBundleURLSchemes spotify-ios-quick-start ``` -------------------------------- ### Initialize App Remote Source: https://developer.spotify.com/documentation/ios/getting-started Initialize the App Remote instance using the previously defined configuration. ```swift lazy var appRemote: SPTAppRemote = { let appRemote = SPTAppRemote(configuration: self.configuration, logLevel: .debug) appRemote.connectionParameters.accessToken = self.accessToken appRemote.delegate = self return appRemote }() ``` -------------------------------- ### Handle Session Delegate Methods Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Implement the required delegate methods to handle session initiation, failure, and renewal. ```swift func sessionManager(manager: SPTSessionManager, didInitiate session: SPTSession) { print("success", session) } func sessionManager(manager: SPTSessionManager, didFailWith error: Error) { print("fail", error) } func sessionManager(manager: SPTSessionManager, didRenew session: SPTSession) { print("renewed", session) } ``` -------------------------------- ### Authorize and Connect to Spotify Source: https://developer.spotify.com/documentation/ios/getting-started Initiate the authorization flow and connect to the Spotify App Remote using the configured URI. ```swift func connect()) { self.appRemote.authorizeAndPlayURI(self.playURI) } ``` -------------------------------- ### Configure Auth Callback Source: https://developer.spotify.com/documentation/ios/getting-started Handle the authorization callback to assign the access token to the app remote connection parameters. ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let parameters = appRemote.authorizationParameters(from: url); if let access_token = parameters?[SPTAppRemoteAccessTokenKey] { appRemote.connectionParameters.accessToken = access_token self.accessToken = access_token } else if let error_description = parameters?[SPTAppRemoteErrorDescriptionKey] { // Show the error } return true } ``` ```swift func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let url = URLContexts.first?.url else { return } let parameters = appRemote.authorizationParameters(from: url); if let access_token = parameters?[SPTAppRemoteAccessTokenKey] { appRemote.connectionParameters.accessToken = access_token self.accessToken = access_token } else if let error_description = parameters?[SPTAppRemoteErrorDescriptionKey] { // Show the error } } ``` -------------------------------- ### Open Spotify App Store URL Source: https://developer.spotify.com/documentation/ios/tutorials/content-linking Open the Spotify app in the App Store. This is a direct link to the application's page. ```objective-c NSString *url = @"https://itunes.apple.com/app/spotify-music/id324684580?mt=8"; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; ``` -------------------------------- ### Handle Player State Changes Source: https://developer.spotify.com/documentation/ios/getting-started Implement the delegate method to react to player state changes, such as logging the current track name. ```swift func playerStateDidChange(_ playerState: SPTAppRemotePlayerState) { debugPrint("Track name: %@", playerState.track.name) } ``` -------------------------------- ### Subscribe to Player State Updates Source: https://developer.spotify.com/documentation/ios/getting-started Register the player delegate and subscribe to state updates upon successful connection. ```swift func appRemoteDidEstablishConnection(_ appRemote: SPTAppRemote) { // Connection was successful, you can begin issuing commands self.appRemote.playerAPI?.delegate = self self.appRemote.playerAPI?.subscribe(toPlayerState: { (result, error) in if let error = error { debugPrint(error.localizedDescription) } }) } ``` -------------------------------- ### Add Spotify Scheme to Info.plist Source: https://developer.spotify.com/documentation/ios/tutorials/content-linking Declare your app's intent to query the Spotify URL scheme by adding 'spotify' to the LSApplicationQueriesSchemes key in your Info.plist file. ```xml ... LSApplicationQueriesSchemes spotify ... ... ``` -------------------------------- ### Configure Auth Callback in AppDelegate Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Notify the session manager when the user returns to the application after authorization. ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { self.sessionManager.application(app, open: url, options: options) return true } ``` -------------------------------- ### Open Spotify Content in App Source: https://developer.spotify.com/documentation/ios/tutorials/content-linking Open specific Spotify content (e.g., an album) within the Spotify app using a web link. This method is preferred over a direct 'spotify:' URI to avoid confirmation prompts and leverage Universal Links. ```objective-c NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; NSString *canonicalURL = @"https://open.spotify.com/album/0sNOF9WDwhWunNAHPD3Baj"; NSString *branchLink = [NSString stringWithFormat:@"https://spotify.link/content_linking?~campaign=%@&$canonical_url=%@", bundleId, canonicalURL]; NSURL *url = [NSURL URLWithString:branchLink]; [[UIApplication sharedApplication] openURL:url]; ``` -------------------------------- ### Skip to next track using SPTRemotePlayerAPI Source: https://developer.spotify.com/documentation/ios/tutorials/making-remote-calls Uses the skipToNext method to advance the player, providing a callback block to handle success or failure. ```objective-c [appRemote.playerAPI skipToNext:^(id _Nullable result, NSError * _Nullable error) { 2 if (error) { 3 // Operation failed 4 } else { 5 // Operation succeeded 6 } 7 }]; ``` -------------------------------- ### Implement Remote Delegates Source: https://developer.spotify.com/documentation/ios/getting-started Implement the required delegate protocols in your AppDelegate or SceneDelegate. ```swift class AppDelegate: UIResponder, UIApplicationDelegate, SPTAppRemoteDelegate, SPTAppRemotePlayerStateDelegate { ... ``` ```swift class SceneDelegate: UIResponder, UIWindowSceneDelegate, SPTAppRemoteDelegate, SPTAppRemotePlayerStateDelegate ... ``` ```swift func appRemoteDidEstablishConnection(_ appRemote: SPTAppRemote) { print("connected") } func appRemote(_ appRemote: SPTAppRemote, didDisconnectWithError error: Error?) { print("disconnected") } func appRemote(_ appRemote: SPTAppRemote, didFailConnectionAttemptWithError error: Error?) { print("failed") } func playerStateDidChange(_ playerState: SPTAppRemotePlayerState) { print("player state changed") } ``` -------------------------------- ### Invoke Authorization Modal Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Trigger the authentication screen with requested scopes and optional campaign tracking. ```swift let requestedScopes: SPTScope = [.appRemoteControl] self.sessionManager.initiateSession(with: requestedScopes, options: .default, campaign: "utm-campaign") ``` -------------------------------- ### Token Swap Response - JSON Source: https://developer.spotify.com/documentation/ios/concepts/token-swap-and-refresh This is the expected JSON response when successfully swapping a code for tokens. It includes the access token, its expiration time in seconds, and a refresh token. ```json { "access_token" : "NgAagA...Um_SHo", "expires_in" : "3600", "refresh_token" : "NgCXRK...MzYjw" } ``` -------------------------------- ### Manage Connection Lifecycle in UIScene Source: https://developer.spotify.com/documentation/ios/getting-started Handle App Remote connection and disconnection within the UIScene lifecycle methods. ```swift func sceneDidBecomeActive(_ scene: UIScene) { if let _ = self.appRemote.connectionParameters.accessToken { self.appRemote.connect() } } func sceneWillResignActive(_ scene: UIScene) { if self.appRemote.isConnected { self.appRemote.disconnect() } } ``` -------------------------------- ### Swap Code for Tokens Request - cURL Source: https://developer.spotify.com/documentation/ios/concepts/token-swap-and-refresh Use this cURL command to swap an authorization code for an access token and a refresh token. Ensure the Content-Type header is set to application/x-www-form-urlencoded. ```bash curl -X POST "https://example.com/v1/swap” -H "Content-Type: application/x-www-form-urlencoded" --data “code=AQDy8...xMhKNA” ``` -------------------------------- ### Add Bridging Header Source: https://developer.spotify.com/documentation/ios/getting-started Include the Spotify iOS SDK header in your project's bridging header file. ```objective-c #import ``` -------------------------------- ### Manage Connection Lifecycle in AppDelegate Source: https://developer.spotify.com/documentation/ios/getting-started Disconnect from App Remote when the app resigns active and reconnect when it becomes active. ```swift func applicationWillResignActive(_ application: UIApplication) { if self.appRemote.isConnected { self.appRemote.disconnect() } } func applicationDidBecomeActive(_ application: UIApplication) { if let _ = self.appRemote.connectionParameters.accessToken { self.appRemote.connect() } } ``` -------------------------------- ### POST /v1/swap - Token Swap Source: https://developer.spotify.com/documentation/ios/concepts/token-swap-and-refresh Swaps a code obtained from the Spotify account service for an access token and a refresh token. ```APIDOC ## POST /v1/swap ### Description Swaps a code for an access token and a refresh token. ### Method POST ### Endpoint https://example.com/v1/swap ### Parameters #### Request Headers - **Content-Type** (string) - Required - application/x-www-form-urlencoded #### Request Body - **code** (string) - Required - The code returned from Spotify account service to be used in the token request. ### Request Example ``` curl -X POST "https://example.com/v1/swap" -H "Content-Type: application/x-www-form-urlencoded" --data "code=AQDy8...xMhKNA" ``` ### Response #### Success Response (200) - **access_token** (string) - Access token received from Spotify account service. - **expires_in** (string) - The time period (in seconds) for which the access token is valid. Returned from the Spotify account service. - **refresh_token** (string) - The refresh token returned from the Spotify account service. It should not return the actual refresh token but a reference to the token or an encrypted version of the token. Encryption solution is shown in the ruby example. #### Response Example ```json { "access_token" : "NgAagA...Um_SHo", "expires_in" : "3600", "refresh_token" : "NgCXRK...MzYjw" } ``` ``` -------------------------------- ### Refresh Access Token Request - cURL Source: https://developer.spotify.com/documentation/ios/concepts/token-swap-and-refresh Use this cURL command to obtain a new access token using a previously obtained refresh token. The Content-Type header must be application/x-www-form-urlencoded. ```bash curl -X POST "https://example.com/v1/refresh" -H "Content-Type: application/x-www-form-urlencoded" --data "refresh_token=NgCXRK...MzYjw" ``` -------------------------------- ### Implement SPTSessionManagerDelegate in AppDelegate Source: https://developer.spotify.com/documentation/ios/tutorials/advanced-auth Add the delegate protocol to your AppDelegate class definition. ```swift class AppDelegate: UIResponder, UIApplicationDelegate, SPTSessionManagerDelegate { ... ``` -------------------------------- ### Set -ObjC Linker Flag Source: https://developer.spotify.com/documentation/ios/getting-started Add the `-ObjC` linker flag in Xcode's Build Settings under 'Other Linker Flags' to enable compilation of Objective-C code within the iOS SDK. ```bash -ObjC ``` -------------------------------- ### Manage App Remote Lifecycle in AppDelegate Source: https://developer.spotify.com/documentation/ios/concepts/application-lifecycle Disconnect the App Remote when the application resigns active status and reconnect when it becomes active, provided an access token exists. ```Objective-C - (void)applicationWillResignActive:(UIApplication *)application { if (self.appRemote.isConnected) { [self.appRemote disconnect]; } } - (void)applicationDidBecomeActive:(UIApplication *)application { if (self.appRemote.connectionParameters.accessToken) { [self.appRemote connect]; } } ``` -------------------------------- ### POST /v1/refresh - Token Refresh Source: https://developer.spotify.com/documentation/ios/concepts/token-swap-and-refresh Uses a refresh token to obtain a new access token when the current one expires. ```APIDOC ## POST /v1/refresh ### Description Uses the refresh token to get a new access token. ### Method POST ### Endpoint https://example.com/v1/refresh ### Parameters #### Request Headers - **Content-Type** (string) - Required - application/x-www-form-urlencoded #### Request Body - **refresh_token** (string) - Required - The refresh_token value previously returned from the token swap endpoint. ### Request Example ``` curl -X POST "https://example.com/v1/refresh" -H "Content-Type: application/x-www-form-urlencoded" --data "refresh_token=NgCXRK...MzYjw" ``` ### Response #### Success Response (200) - **access_token** (string) - Access token received from Spotify account service. - **expires_in** (string) - The time period (in seconds) for which the access token is valid. Returned from the Spotify account service. #### Response Example ```json { "access_token" : "NgAagA...Um_SHo", "expires_in" : "3600" } ``` ``` -------------------------------- ### Token Refresh Response - JSON Source: https://developer.spotify.com/documentation/ios/concepts/token-swap-and-refresh This is the expected JSON response when a refresh token is used to obtain a new access token. It contains the new access token and its expiration time in seconds. ```json { "access_token" : "NgAagA...Um_SHo", "expires_in" : "3600" } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.