cjam / react-native-spotify-remote

React Native wrapper around the Spotify Remote SDK
MIT License
252 stars 97 forks source link

Auth is calling Swap with no code on ios #153

Open NehoCandy opened 3 years ago

NehoCandy commented 3 years ago

Hi @cjam !

First of all, just want to say thank you for this amazing library! It is going to help us a lot!

Now for the problem: after some adjustments, I was able to get the app to redirect to the Spotify app, there you can see the 'authenticating' loading animation and after a second a tick with 'success'. The problem occurs when we redirect back to our app- after debugging, we discovered that the swap function in the server, does not get any code from your Auth function, and because of that we are not getting an access token+refresh token so we cannot proceed into the actual player component in our app. To be more specific, the way to replicate the error is by opening the app-> press the 'Authenticate silently' button (-> redirect to Spotify app that authenticates the connection)->redirecting back to the 'home page' of our app but with error 'SPTAuthorizationDailedErrorCode: invalid_request'.

We would really appreciate the help @cjam!! Thank you!

cjam commented 3 years ago

Hey @NehoCandy, Glad you enjoying the library.

Are you talking about the example app in the Repo or are you creating your own app?

Can you confirm that you have made the following change in your AppDelegate.m:

https://github.com/cjam/react-native-spotify-remote/blob/1d75f227a3869c8f91e7509efd0315321b76c80a/example/ios/example/AppDelegate.m#L61-L64

What you could try and do, is actually debug your iOS app and put a breakpoint here:

https://github.com/cjam/react-native-spotify-remote/blob/1d75f227a3869c8f91e7509efd0315321b76c80a/ios/RNSpotifyRemoteAuth.m#L84

Which would allow you to step through and inspect what is coming back from spotify. But if your SWAP endpoint isn't being hit, I think it's likely something to do with the auth config being passed. Make sure that your bundle id is registered in spotify's dev console and that the id's and everything match.

NehoCandy commented 3 years ago

Hi @cjam ! did not expect such a quick reply, so thanks :)

I got my app to work on Android (not exactly, because of the refresh mechanism not being exist there, but that is another question..) so I moved to mac trying to get it to work on IOS. I can confirm I've made that change in the AppDelegate.m file and it still doesn't work. I've also tried just pasting the code from AppDelegate.m in the example app you provided, but when I do that, xcode says 'FlipperKit/FlipperClient.h' file not found and I have no idea how to fix it...

After so many tries I decided to start from scratch and currently I'm trying to get your example app to work on iOS, but with no success; The problem I get with your app is that the Spotify app does authenticate the connection, but there is no redirection back to our app at all (server is up and I added some console logs to the 'swap' function but it seems like it does not get there at all).

I'm pretty lost to be honest... If you have any suggestions, I would love to hear them!

Thank you again for your response!!

NehoCandy commented 3 years ago

Hi @cjam !

We decided to continue testing the library to check if it fits our needs, so we moved to your example, and got it to work.

The thing is- we found another problem on iOS (didnt get the time to check on android); Authentication works just fine and we are able to move into the player. but, about 30 seconds or less after we pause a song, the player just disconnects! we tried adding remote.connect(...) in the ConnectButton.tsx component once the disconnection is occurred in order to reconnect in the background, but with no success... We have to go back to the homepage and re-authenticate everything..

The error I see in the xcode console is AppRemote: Failed connection attempt with error: Error Domain=com.spotify.app-remote.transport Code=-2000 "Stream error." UserInfo={NSLocalizedDescription=Stream error., NSUnderlyingError=0x282b1ebb0 {Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused" UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}}, NSLocalizedRecoverySuggestion=Reconnect the transport to the Spotify app., NSLocalizedFailureReason=A stream error has occured in the transport.}

Have you heard about this problem? do you have any idea how to solve it? thank you!

cjam commented 3 years ago

Hey @NehoCandy , you have unfortunately found a known issue in the Spotify iOS SDK. Unfortunately, at the current moment, iOS aggressively backgrounds applications that are not being used. So once Spotify stops playing music, within that 30 second window, iOS will background it. I've spoken with the Spotify Developer Advocate about some of these issues that people using this library are experiencing.

Some ways that I've worked around them in the past are pretty hacky, but playing a track of silence works, because spotify is still technically playing music. Running through the auth flow (non-silent) will start spotify playing music again (and bring it to the foreground) and kick back to your app. This usually works, however, the user experience from your apps perspective is less than ideal.

Sorry you ran into that issue. 👎

NehoCandy commented 3 years ago

Hey @NehoCandy , you have unfortunately found a known issue in the Spotify iOS SDK. Unfortunately, at the current moment, iOS aggressively backgrounds applications that are not being used. So once Spotify stops playing music, within that 30 second window, iOS will background it. I've spoken with the Spotify Developer Advocate about some of these issues that people using this library are experiencing.

Some ways that I've worked around them in the past are pretty hacky, but playing a track of silence works, because spotify is still technically playing music. Running through the auth flow (non-silent) will start spotify playing music again (and bring it to the foreground) and kick back to your app. This usually works, however, the user experience from your apps perspective is less than ideal.

Sorry you ran into that issue. 👎

all good @cjam, I actually thought about this solution but I have a hard time implementing it correctly... We are actually a team of volunteers working on an app that encourages disabled people to move with music (the music will continue to play as long as the device detects movement). We wanted to add Spotify so we decided to go with your library since it's pretty much the only one for RN users.

Anyways, back to my problem: my idea was to save the URI of a silent track, and every time we are suppose to pause the song instead of sending a 'pause' request, I'll add the URI of the silent track to the queue, save the timestamp of the song that was being played, and skip to the next song (which now is the silent track). When we need to resume the music, we'll go back to the previous song (now the song that's suppose to be paused) and play it from the timestamp we saved. The idea behind this is that as a Spotify user, I know that when you shuffle play a playlist for example, and then add a song to the queue, it is gonna be there only once; meaning lets say you play a song named X and the next song is called Z, if you add song Y to the playlist, play it and go back to the prev song (X), the next song after X will be Z and not Y! My original idea was to use this in order to keep the playlist going in it's original order. BUT, apparently the queueUri function you have in the remote, will actually add a song permanently, meaning lets say you play a song named X and the next song is called Z, if you add song Y to the playlist, play it and go back to the prev song (X), the next song after X will remain Y and not Z like in the built in 'add to queue' function in the Spotify app!

Do you have any idea of how to get around this? We thought about just keep deleting the silent track from the queue, but fir some reason there is no such function in the library (probably in the sdk as well) :/

Thank you again for your replies we really appreciate it here!! :)

cjam commented 3 years ago

Hey @NehoCandy , I suspect your experiencing this with iOS? I think in Android it works how you would imagine. I've already spoken to the Developer advocate about this issue so hopefully it gets resolved on their end and there is a way to have better control over what is playing and the queue of songs.

NehoCandy commented 3 years ago

hey @cjam , thanks again for your replies :) We moved to iOS quickly after realizing the android sdk does not support refresh tokens, so we didn't do the proper testings to tell you if it happens there as well... Worst case- we'll implement it the same way we will do on iOS.. anyways, we have 2 more questions regarding the implementation on the platforms:

  1. Right out of the box, the progress of the song playing does not update 'live' in player in the example provided, meaning unless I press a button on the player (play/pause, toggle shuffle etc...) the slider will stay the same and will not move at all. pressing one of the buttons will only update the slider once and it will stay at its updated point until I press something again.. it seems like you did include listeners to these events, like remote.on('playerStateChanged', this.onPlayerStateChanged), but it seems like the Spotify SDK does not send us any event named 'playerStateChanged' unless I press a button... Do you know about that problem?

  2. regarding the refresh mechanism not existing on Android; is there a different way to get a new token on Android? or are we doomed to reconnect manually in order to request a new access token? Thanks again!

cjam commented 3 years ago

Hey @NehoCandy ,

with regards to 1 this is a limitation in the Spotify SDK and not this library. Unfortunately, They only offer a mechanism to ask for the player state. Within this library, I also push updates via this event whenever there is an action that results in an update to the state. You could however, just periodically getPlayerState which would also push the updated playerState through this event / event listeners.

  1. I haven't had an opportunity to explore more options around the refresh / swap. Would love if someone could PR an approach that could be added to the example