spotify / ios-sdk

Spotify SDK for iOS
https://developer.spotify.com/documentation/ios/
659 stars 187 forks source link

Login issue with iOS SDK #350

Open lguzman-caden opened 2 years ago

lguzman-caden commented 2 years ago

Hey folks, I'm having an issue implementing the iOS Spotify SDK, my objective is to get the user’s spotifyAccessToken and spotifyRefreshToken, as it is now is partially working, if the user log in using the web browser everything works well, but when the user use the Spotify app the process is not completed, the methods of the SPTSessionManagerDelegate are not called in spite the fact the spotify app callback my app.

My current implementation is simple, I have a single class in charge to dealing with the configuration and initialization of the SDK for login and authorization purposes also this class implements the SPTSessionManagerDelegate methods.

Another point to mention is that I tried with the ruby server example discribed in the Github page but this approach didn’t work the SDK never call the server.

Info: I took the SpotifyiOS.xcframework from the Spotify sample project hosted in: Spotify GitHub Xcode version: 13.2.1 iOS target version: 14.0 Swift version: 5.0

I tested this behavior in physical device, any assistance will be helpful!

sgoodwin commented 2 years ago

Are you handling the part where your app is launched via a URL? In your Scene Delegate, you should see the incoming URL, this URL needs to be fed to the session manager.

jayeshtejwani8055 commented 2 years ago
lazy var configuration: SPTConfiguration = {
        let configuration = SPTConfiguration(clientID: clientId, redirectURL: redirectUri)
        return configuration
    }()

    lazy var appRemote: SPTAppRemote = {
        let appRemote = SPTAppRemote(configuration: configuration, logLevel: .debug)
        appRemote.delegate = self
        return appRemote
    }()

    var accessToken = UserDefaults.standard.string(forKey: kAccessTokenKey) {
        didSet {
            let defaults = UserDefaults.standard
            defaults.set(accessToken, forKey: kAccessTokenKey)
        }
    }

    lazy var sessionManager: SPTSessionManager = {
        let configuration = SPTConfiguration(clientID: clientId, redirectURL: redirectUri)
        let manager = SPTSessionManager(configuration: configuration, delegate: self)
        return manager
    }()

func application(_ app: UIApplication,
                     open url: URL,
                     options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
        if let parameters = appRemote.authorizationParameters(from: url) {
            let access_token = parameters[SPTAppRemoteAccessTokenKey]
            appRemote.connectionParameters.accessToken = access_token
            sessionManager.application(app, open: url, options: options)
        } 
        return true
    }

To login into Spotify account

let scope: SPTScope = [.appRemoteControl, .playlistReadPrivate, .userModifyPlaybackState] _appDelegator.sessionManager.initiateSession(with: scope, options: .clientOnly)

You will be redirected back to your app and get access token in func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any])

breiko83 commented 2 years ago

Hey @jayeshtejwani8055 - I'm having similar issue and I can't figure out why I can't authenticate anymore.

This is my configuration:

func connect(){
    let scope: SPTScope = [.appRemoteControl]

    sessionManager.initiateSession(with: scope, options: .default)
}

lazy var configuration: SPTConfiguration = {
        var configuration = SPTConfiguration(clientID: clientIdentifier, redirectURL: redirectUri)
        // Set the playURI to a non-nil value so that Spotify plays music after authenticating and App Remote can connect
        // otherwise another app switch will be required
        //configuration.playURI = ""

        // Set these url's to your backend which contains the secret to exchange for an access token
        // You can use the provided ruby script spotify_token_swap.rb for testing purposes
        configuration.tokenSwapURL = URL(string: "http://52.17.226.85:1234/swap")
        configuration.tokenRefreshURL = URL(string: "http://52.17.226.85:1234/refresh")
        return configuration
    }()

   func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        guard let url = URLContexts.first?.url else {
            return
        }

        print(url)
        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
            print(error_description)
        }
    }

And this is my what I receive once I'm redirected from the app.

2022-09-30 12:05:13.789345+0100 SpinBeats[71628:4778724] [Common] Snapshot request 0x281155050 complete with error: <NSError: 0x2811a7f60; domain: BSActionErrorDomain; code: 6>

spinbeats://spotify-login-callback/?code=AQCJgg4JLDWQnLAZ0DPL2ALur2xocvJYPApSR9ZyjPgh6Q54D-lygxIHIx2Y_8dEp66H8vEd-H7vXe5Ij_dVdG2HAupeyO1zyA80F4J--JrrMJPP-nRENXHgzp3PXb4tR44YGdC25qcOB6K2lM-nKb-6f4IrSOk7RuloIXNJAGcb073BikRs9TKUaGVfMdj9TcwrCACW3lQhKS53uLBJ4aDsI5S9eLjZM1oxFXqR8zsV&spotify_version=8.7.68.568

It seems the url I'm receiving back does not have an access token therefore this is never saved. Also the token swap url is never called as I don't see any requests from the logs.

breiko83 commented 2 years ago

So I ended up swapping the url myself as the SDK seems to fail in doing so. Here is the code if it can help.

 func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        guard let url = URLContexts.first?.url else {
            return
        }

        print(url)

        // Not working
        // self.sessionManager.application(UIApplication.shared, open: url, options: [:])

        // Working
        let parameters = appRemote.authorizationParameters(from: url);

        if let code = parameters?["code"] {
            print(code)
            AF.request("http://52.17.226.85:1234/swap", method: .post, parameters:["code": [code]]).responseDecodable(of: SpotifyToken.self) { (response) in
                guard let token = response.value else { return }
                print(token.access_token)
                self.appRemote.connectionParameters.accessToken = token.access_token
                self.appRemote.connect()
            }
        }
    }